mirror of
https://github.com/OCA/web.git
synced 2025-02-22 13:21:25 +02:00
161 lines
5.9 KiB
JavaScript
161 lines
5.9 KiB
JavaScript
/* Copyright 2018 Onestein
|
|
* License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). */
|
|
|
|
odoo.define("web_timeline.TimelineCanvas", function (require) {
|
|
"use strict";
|
|
const Widget = require("web.Widget");
|
|
|
|
/**
|
|
* Used to draw stuff on upon the timeline view.
|
|
*/
|
|
const TimelineCanvas = Widget.extend({
|
|
template: "TimelineView.Canvas",
|
|
|
|
/**
|
|
* Clears all drawings (svg elements) from the canvas.
|
|
*/
|
|
clear: function () {
|
|
this.$(" > :not(defs)").remove();
|
|
},
|
|
|
|
/**
|
|
* Gets the path from one point to another.
|
|
*
|
|
* @param {Object} rectFrom
|
|
* @param {Object} rectTo
|
|
* @param {Number} widthMarker The marker's width of the polyline
|
|
* @param {Number} breakAt The space between the line turns
|
|
* @returns {Array} Each item represents a coordinate
|
|
*/
|
|
get_polyline_points: function (rectFrom, rectTo, widthMarker, breakAt) {
|
|
let fromX = 0,
|
|
toX = 0;
|
|
if (rectFrom.x < rectTo.x + rectTo.w) {
|
|
fromX = rectFrom.x + rectFrom.w + widthMarker;
|
|
toX = rectTo.x;
|
|
} else {
|
|
fromX = rectFrom.x - widthMarker;
|
|
toX = rectTo.x + rectTo.w;
|
|
}
|
|
let deltaBreak = 0;
|
|
if (fromX < toX) {
|
|
deltaBreak = fromX + breakAt - (toX - breakAt);
|
|
} else {
|
|
deltaBreak = fromX - breakAt - (toX + breakAt);
|
|
}
|
|
const fromHalfHeight = rectFrom.h / 2;
|
|
const fromY = rectFrom.y + fromHalfHeight;
|
|
const toHalfHeight = rectTo.h / 2;
|
|
const toY = rectTo.y + toHalfHeight;
|
|
const xDiff = fromX - toX;
|
|
const yDiff = fromY - toY;
|
|
const threshold = breakAt + widthMarker;
|
|
const spaceY = toHalfHeight + 2;
|
|
|
|
const points = [[fromX, fromY]];
|
|
const _addPoints = (space, ePoint, mode) => {
|
|
if (mode) {
|
|
points.push([fromX + breakAt, fromY]);
|
|
points.push([fromX + breakAt, ePoint + space]);
|
|
points.push([toX - breakAt, toY + space]);
|
|
points.push([toX - breakAt, toY]);
|
|
} else {
|
|
points.push([fromX - breakAt, fromY]);
|
|
points.push([fromX - breakAt, ePoint + space]);
|
|
points.push([toX + breakAt, toY + space]);
|
|
points.push([toX + breakAt, toY]);
|
|
}
|
|
};
|
|
if (fromY !== toY) {
|
|
if (Math.abs(xDiff) < threshold) {
|
|
points.push([fromX + breakAt, toY + yDiff]);
|
|
points.push([fromX + breakAt, toY]);
|
|
} else {
|
|
const yDiffSpace = yDiff > 0 ? spaceY : -spaceY;
|
|
_addPoints(yDiffSpace, toY, rectFrom.x < rectTo.x + rectTo.w);
|
|
}
|
|
} else if (Math.abs(deltaBreak) >= threshold) {
|
|
_addPoints(spaceY, fromY, fromX < toX);
|
|
}
|
|
points.push([toX, toY]);
|
|
|
|
return points;
|
|
},
|
|
|
|
/**
|
|
* Draws an arrow.
|
|
*
|
|
* @param {HTMLElement} from Element to draw the arrow from
|
|
* @param {HTMLElement} to Element to draw the arrow to
|
|
* @param {String} color Color of the line
|
|
* @param {Number} width Width of the line
|
|
* @returns {HTMLElement} The created SVG polyline
|
|
*/
|
|
draw_arrow: function (from, to, color, width) {
|
|
return this.draw_line(from, to, color, width, "#arrowhead", 10, 12);
|
|
},
|
|
|
|
/**
|
|
* Draws a line.
|
|
*
|
|
* @param {HTMLElement} from Element to draw the line from
|
|
* @param {HTMLElement} to Element to draw the line to
|
|
* @param {String} color Color of the line
|
|
* @param {Number} width Width of the line
|
|
* @param {String} markerStart Start marker of the line
|
|
* @param {Number} widthMarker The marker's width of the polyline
|
|
* @param {Number} breakLineAt The space between the line turns
|
|
* @returns {HTMLElement} The created SVG polyline
|
|
*/
|
|
draw_line: function (
|
|
from,
|
|
to,
|
|
color,
|
|
width,
|
|
markerStart,
|
|
widthMarker,
|
|
breakLineAt
|
|
) {
|
|
const $from = $(from);
|
|
const childPosFrom = $from.offset();
|
|
const parentPosFrom = $from.closest(".vis-center").offset();
|
|
const rectFrom = {
|
|
x: childPosFrom.left - parentPosFrom.left,
|
|
y: childPosFrom.top - parentPosFrom.top,
|
|
w: $from.width(),
|
|
h: $from.height(),
|
|
};
|
|
const $to = $(to);
|
|
const childPosTo = $to.offset();
|
|
const parentPosTo = $to.closest(".vis-center").offset();
|
|
const rectTo = {
|
|
x: childPosTo.left - parentPosTo.left,
|
|
y: childPosTo.top - parentPosTo.top,
|
|
w: $to.width(),
|
|
h: $to.height(),
|
|
};
|
|
const points = this.get_polyline_points(
|
|
rectFrom,
|
|
rectTo,
|
|
widthMarker,
|
|
breakLineAt
|
|
);
|
|
const line = document.createElementNS(
|
|
"http://www.w3.org/2000/svg",
|
|
"polyline"
|
|
);
|
|
line.setAttribute("points", _.flatten(points).join(","));
|
|
line.setAttribute("stroke", color || "#000");
|
|
line.setAttribute("stroke-width", width || 1);
|
|
line.setAttribute("fill", "none");
|
|
if (markerStart) {
|
|
line.setAttribute("marker-start", "url(" + markerStart + ")");
|
|
}
|
|
this.$el.append(line);
|
|
return line;
|
|
},
|
|
});
|
|
|
|
return TimelineCanvas;
|
|
});
|