blob: 7af0123bba7da9a676865ced761eba50bcdba934 [file] [log] [blame]
// Copyright (c) 2000-2019 Ericsson Telecom AB Telecom AB //
// All rights reserved. This program and the accompanying materials are made available under the //
// terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at //
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html //
///////////////////////////////////////////////////////////////////////////////////////////////////////
function LineDrawer(p_parentId, p_id, p_from, p_to, p_options) {
"use strict";
var v_this = this;
// params
var v_parentId = p_parentId;
var v_id = p_id;
var v_from = p_from;
var v_to = p_to;
var v_options = {
"stroke" : "#456",
"strokeWidth" : 3,
"arrowForward" : true,
"markerStroke" : "#456",
"arrowHead" : "target",
"z-index" : 0
};
var zIndex = 0;
setOptions(p_options);
var v_svg;
function setOptions(p_options) {
// copy given options to the default
for (var key in p_options) {
if (p_options.hasOwnProperty(key) && v_options.hasOwnProperty(key)) {
v_options[key] = p_options[key];
}
}
// settings whose value depends on others
v_options.markerStroke = '-' + v_options.stroke.replace('#', '');
}
this.init = function() {
createSVG();
createMarkers();
createPath();
v_this.update();
};
function createSVG() {
v_svg = $("#" + v_parentId).createSVGNode({
"id": v_id,
"position": "absolute",
"style": "position: absolute; z-index: " + v_options["z-index"] + ";",
"pointer-events": "none",
"version": "1.1",
"z-index": v_options["z-index"]
});
}
function setZIndex(svgElement) {
var amount;
if (v_from.getZIndex != undefined) {
amount = v_from.getZIndex();
}
if (v_to.getZIndex != undefined) {
var newAmount = v_to.getZIndex();
if (amount == undefined || newAmount > amount) {
amount = newAmount;
}
}
if (amount != undefined && amount != zIndex) {
svgElement.setAttribute("z-index", amount);
svgElement.style["z-index"] = amount;
zIndex = amount;
}
};
function createMarkers() {
// the marker head descriptor
var markerHead = {
"id": v_id + "_head",
"orient": "auto",
"markerWidth": 4,
"markerHeight": 4,
"refX": 2,
"refY": 2
};
var markerFoot = shallowcopy(markerHead);
markerFoot.id = v_id + "_foot";
// we also need the marker path descriptor
var pathHead = {
"fill": v_options.stroke,
"stroke": v_options.stroke,
"stroke-linejoin": "miter",
"stroke-linecap": "round",
"d": "M0,0 V4 L2,2 Z"
};
var pathFoot = shallowcopy(pathHead);
pathFoot.d = "M4,0 V4 L2,2 Z";
// finally we crete the defs element and fill it up
var defs = v_svg.createSVGNode("defs");
defs.createSVGNode("marker", markerHead)
.createSVGNode("path", pathHead);
defs.createSVGNode("marker", markerFoot)
.createSVGNode("path", pathFoot);
}
function createPath() {
var svgattrs = {
"id": v_id + "_path",
"fill": "none",
"stroke": v_options.stroke,
"stroke-width": v_options.strokeWidth,
"stroke-linejoin": "round",
"stroke-linecap": "round",
"pointer-events": "none",
"shape-rendering": "geometricPrecision",
"stroke-antialiasing": "true"
};
if(!isIE11 && !isIE10) {
// In IE10 and up, the url() virtual function crashes the SVG engine, hence nothing gets drawn in that <svg> element.
if (v_options.arrowHead === "target") {
svgattrs["marker-end"] = "url(#" + v_id + "_head)";
} else if (v_options.arrowHead === "source") {
svgattrs["marker-start"] = "url(#" + v_id + "_foot)";
} else if (v_options.arrowHead === "both") {
svgattrs["marker-end"] = "url(#" + v_id + "_head)";
svgattrs["marker-start"] = "url(#" + v_id + "_foot)";
}
}
v_svg.createSVGNode("path", svgattrs);
}
this.remove = function() {
$("#" + v_id).remove();
};
function findMinOffsetFromList(list, element) {
var minAmount = Math.abs(list[0].top - element.top) + Math.abs(list[0].left - element.left);
var min = 0;
for (var i = 1; i < list.length; ++i) {
var amount = Math.abs(list[1].top - element.top) + Math.abs(list[1].left - element.left);
if (amount < minAmount) {
minAmount = amount;
min = i;
}
}
return [min, minAmount];
}
function getFinalCoordinates(sourceOffset, targetOffset) {
var x1 = Math.round(sourceOffset.top);
var y1 = Math.round(sourceOffset.left);
var x2 = Math.round(targetOffset.top);
if (x2 === x1) {
x2++;
}
var y2 = Math.round(targetOffset.left);
if (y2 === y1) {
y2++;
}
return [x1, y1, x2, y2];
}
function getOffsetCoordinates() {
if (!v_from.multiple && !v_to.multiple) {
// only one source and one target
return getFinalCoordinates(v_from.getOffset(), v_to.getOffset());
} else if (v_from.multiple && !v_to.multiple) {
// multiple sources and one target
var list = v_from.getOffsets();
var element = v_to.getOffset();
var min = findMinOffsetFromList(list, element);
return getFinalCoordinates(list[min[0]], element);
} else if (!v_from.multiple && v_to.multiple) {
// one surce and multiple targets
var list = v_to.getOffsets();
var element = v_from.getOffset();
var min = findMinOffsetFromList(list, element);
return getFinalCoordinates(element, list[min[0]]);
} else {
// multiple source and multiple targets
var sourceList = v_from.getOffsets();
var targetList = v_to.getOffsets();
// assume the first is the minimum
var minsource = 0;
var min = findMinOffsetFromList(targetList, sourceList[0]);
// we need the index of the target whose distance from the current source element is minimal
var mintarget = min[0];
// and the distance itself
var minAmount = min[1];
// find the real minimum from the rest
for (var i = 1; i < sourceList.length; ++i) {
var element = sourceList[i];
min = findMinOffsetFromList(targetList, element);
if (min[1] < minAmount) {
minsource = i;
mintarget = min[0];
minAmount = min[1];
}
}
return getFinalCoordinates(sourceList[minsource], targetList[mintarget]);
}
}
function getStyle(fromX, fromY, toX, toY) {
var d = 'M' + fromX + ',' + fromY + ' C';
if (v_from.style == "vertical") {
d += fromX + ',' + ( (fromY + toY) / 2 ) + ' ';
} else {
d += ( (fromX + toX) / 2 ) + ',' + fromY + ' ';
}
if (v_to.style == "vertical") {
d += toX + ',' + ( (fromY + toY) / 2 );
} else {
d += ( (fromX + toX) / 2 ) + ',' + toY;
}
d += ' ' + toX + ',' + toY;
return d;
}
this.update = function() {
if ((v_from.isEnabled != undefined && !v_from.isEnabled()) || (v_to.isEnabled != undefined && !v_to.isEnabled())) {
// check whether one of the endpoints is disabled
$("#" + v_id).css("display", "none");
return;
} else {
$("#" + v_id).css("display", "block");
}
var offsets = getOffsetCoordinates();
var x1 = offsets[0];
var y1 = offsets[1];
var x2 = offsets[2];
var y2 = offsets[3];
// these are the only values we need, and we need them all
// the bounding box position
var boundingBoxOffset = {"top" : 0, "left" : 0};
var boundingBoxWidth = 0;
var boundingBoxHeight = 0;
// the corners of the bounding box we should connect
var fromX = 0;
var fromY = 0;
var toX = 0;
var toY = 0;
if (x2 > x1 && y2 > y1) {
boundingBoxOffset.top = x1 - 5;
boundingBoxOffset.left = y1 - 5;
boundingBoxWidth = y2 - y1 + 10;
boundingBoxHeight = x2 - x1 + 10;
fromX = 0 + 5;
fromY = 0 + 5;
toX = boundingBoxWidth - 5;
toY = boundingBoxHeight - 5;
} else if (x2 > x1 && y2 < y1) {
boundingBoxOffset.top = x1 - 5;
boundingBoxOffset.left = y2 - 5;
boundingBoxWidth = y1 - y2 + 10;
boundingBoxHeight = x2 - x1 + 10;
fromX = boundingBoxWidth - 5;
fromY = 0 + 5;
toX = 0 + 5;
toY = boundingBoxHeight - 5;
} else if (x2 < x1 && y2 > y1) {
boundingBoxOffset.top = x2 - 5;
boundingBoxOffset.left = y1 - 5;
boundingBoxWidth = y2 - y1 + 10;
boundingBoxHeight = x1 - x2 + 10;
fromX = 0 + 5;
fromY = boundingBoxHeight - 5;
toX = boundingBoxWidth - 5;
toY = 0 + 5;
} else if (x2 < x1 && y2 < y1) {
boundingBoxOffset.top = x2 - 5;
boundingBoxOffset.left = y2 - 5;
boundingBoxWidth = y1 - y2 + 10;
boundingBoxHeight = x1 - x2 + 10;
fromX = boundingBoxWidth - 5;
fromY = boundingBoxHeight - 5;
toX = 0 + 5;
toY = 0 + 5;
}
v_svg.offset(boundingBoxOffset);
// in IE and chrome we need to set the offset twice so it gets calculated correctly
v_svg.offset(boundingBoxOffset);
var svgElement = document.getElementById(v_id);
svgElement.setAttribute("height", boundingBoxHeight);
svgElement.setAttribute("width", boundingBoxWidth);
svgElement.style.height = boundingBoxHeight;
svgElement.style.width = boundingBoxWidth;
//var d = 'M' + fromX + ',' + fromY + ' C' + ( (fromX + toX) / 2 ) + ',' + fromY + ' ' + ( (fromX + toX) / 2 ) + ',' + toY + ' ' + toX + ',' + toY;
var d = getStyle(fromX, fromY, toX, toY);
document.getElementById(v_id + "_path").setAttribute("d", d);
setZIndex(svgElement);
};
}
//# sourceURL=Utils\LineDrawer.js