2019-09-12 12:58:04 -07:00
|
|
|
import * as d3 from 'd3';
|
|
|
|
import { sanitizeUrl } from '@braintree/sanitize-url';
|
|
|
|
import { logger } from '../../logger';
|
|
|
|
import utils from '../../utils';
|
|
|
|
import { getConfig } from '../../config';
|
|
|
|
|
|
|
|
const config = getConfig();
|
|
|
|
let vertices = {};
|
|
|
|
let edges = [];
|
|
|
|
let classes = [];
|
|
|
|
let subGraphs = [];
|
|
|
|
let subGraphLookup = {};
|
|
|
|
let tooltips = {};
|
|
|
|
let subCount = 0;
|
2019-09-18 12:56:24 -07:00
|
|
|
let firstGraphFlag = true;
|
2019-09-12 12:58:04 -07:00
|
|
|
let direction;
|
2014-11-24 22:03:32 +01:00
|
|
|
// Functions to be run after graph rendering
|
2019-09-12 12:58:04 -07:00
|
|
|
let funs = [];
|
2019-07-13 22:50:53 -07:00
|
|
|
|
|
|
|
const sanitize = text => {
|
2019-09-12 12:58:04 -07:00
|
|
|
let txt = text;
|
2019-08-11 03:26:44 -07:00
|
|
|
if (config.securityLevel !== 'loose') {
|
2019-09-12 12:58:04 -07:00
|
|
|
txt = txt.replace(/<br>/g, '#br#');
|
|
|
|
txt = txt.replace(/<br\S*?\/>/g, '#br#');
|
|
|
|
txt = txt.replace(/</g, '<').replace(/>/g, '>');
|
|
|
|
txt = txt.replace(/=/g, '=');
|
|
|
|
txt = txt.replace(/#br#/g, '<br/>');
|
2019-07-14 06:07:27 -07:00
|
|
|
}
|
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
return txt;
|
|
|
|
};
|
2019-07-13 22:50:53 -07:00
|
|
|
|
2014-11-20 20:46:51 +01:00
|
|
|
/**
|
|
|
|
* Function called by parser when a node definition has been found
|
|
|
|
* @param id
|
|
|
|
* @param text
|
|
|
|
* @param type
|
|
|
|
* @param style
|
2019-05-24 17:08:45 +02:00
|
|
|
* @param classes
|
2014-11-20 20:46:51 +01:00
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const addVertex = function(_id, text, type, style, classes) {
|
|
|
|
let txt;
|
|
|
|
let id = _id;
|
2017-04-11 22:14:25 +08:00
|
|
|
if (typeof id === 'undefined') {
|
2019-09-12 12:58:04 -07:00
|
|
|
return;
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
if (id.trim().length === 0) {
|
2019-09-12 12:58:04 -07:00
|
|
|
return;
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2015-05-29 08:23:13 +02:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
if (id[0].match(/\d/)) id = 's' + id;
|
2019-08-15 08:57:49 +02:00
|
|
|
|
2017-04-11 22:14:25 +08:00
|
|
|
if (typeof vertices[id] === 'undefined') {
|
2019-09-12 12:58:04 -07:00
|
|
|
vertices[id] = { id: id, styles: [], classes: [] };
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
if (typeof text !== 'undefined') {
|
2019-09-12 12:58:04 -07:00
|
|
|
txt = sanitize(text.trim());
|
2017-04-11 22:14:25 +08:00
|
|
|
|
2017-04-16 23:48:36 +08:00
|
|
|
// strip quotes if string starts and exnds with a quote
|
2017-04-11 22:14:25 +08:00
|
|
|
if (txt[0] === '"' && txt[txt.length - 1] === '"') {
|
2019-09-12 12:58:04 -07:00
|
|
|
txt = txt.substring(1, txt.length - 1);
|
2014-11-22 15:34:21 +01:00
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
vertices[id].text = txt;
|
2019-08-27 12:16:11 -07:00
|
|
|
} else {
|
|
|
|
if (!vertices[id].text) {
|
2019-09-12 12:58:04 -07:00
|
|
|
vertices[id].text = _id;
|
2019-08-27 12:16:11 -07:00
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
if (typeof type !== 'undefined') {
|
2019-09-12 12:58:04 -07:00
|
|
|
vertices[id].type = type;
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
if (typeof style !== 'undefined') {
|
|
|
|
if (style !== null) {
|
2019-09-12 12:58:04 -07:00
|
|
|
style.forEach(function(s) {
|
|
|
|
vertices[id].styles.push(s);
|
|
|
|
});
|
2014-11-20 20:46:51 +01:00
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2019-05-24 17:08:45 +02:00
|
|
|
if (typeof classes !== 'undefined') {
|
|
|
|
if (classes !== null) {
|
2019-09-12 12:58:04 -07:00
|
|
|
classes.forEach(function(s) {
|
|
|
|
vertices[id].classes.push(s);
|
|
|
|
});
|
2019-05-24 17:08:45 +02:00
|
|
|
}
|
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
};
|
2014-12-04 17:58:05 +01:00
|
|
|
|
2014-11-20 20:46:51 +01:00
|
|
|
/**
|
|
|
|
* Function called by parser when a link/edge definition has been found
|
|
|
|
* @param start
|
|
|
|
* @param end
|
|
|
|
* @param type
|
|
|
|
* @param linktext
|
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const addLink = function(_start, _end, type, linktext) {
|
|
|
|
let start = _start;
|
|
|
|
let end = _end;
|
|
|
|
if (start[0].match(/\d/)) start = 's' + start;
|
|
|
|
if (end[0].match(/\d/)) end = 's' + end;
|
|
|
|
logger.info('Got edge...', start, end);
|
2019-08-16 12:38:34 +02:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
const edge = { start: start, end: end, type: undefined, text: '' };
|
|
|
|
linktext = type.text;
|
2017-04-11 22:14:25 +08:00
|
|
|
|
|
|
|
if (typeof linktext !== 'undefined') {
|
2019-09-12 12:58:04 -07:00
|
|
|
edge.text = sanitize(linktext.trim());
|
2014-12-09 22:26:42 -08:00
|
|
|
|
2017-04-16 23:48:36 +08:00
|
|
|
// strip quotes if string starts and exnds with a quote
|
2017-04-11 22:14:25 +08:00
|
|
|
if (edge.text[0] === '"' && edge.text[edge.text.length - 1] === '"') {
|
2019-09-12 12:58:04 -07:00
|
|
|
edge.text = edge.text.substring(1, edge.text.length - 1);
|
2014-11-20 20:46:51 +01:00
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2014-11-20 20:46:51 +01:00
|
|
|
|
2017-04-11 22:14:25 +08:00
|
|
|
if (typeof type !== 'undefined') {
|
2019-09-12 12:58:04 -07:00
|
|
|
edge.type = type.type;
|
|
|
|
edge.stroke = type.stroke;
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
edges.push(edge);
|
|
|
|
};
|
2016-04-28 20:59:09 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates a link's line interpolation algorithm
|
|
|
|
* @param pos
|
|
|
|
* @param interpolate
|
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const updateLinkInterpolate = function(positions, interp) {
|
|
|
|
positions.forEach(function(pos) {
|
2019-02-21 22:06:11 +02:00
|
|
|
if (pos === 'default') {
|
2019-09-12 12:58:04 -07:00
|
|
|
edges.defaultInterpolate = interp;
|
2019-02-21 22:06:11 +02:00
|
|
|
} else {
|
2019-09-12 12:58:04 -07:00
|
|
|
edges[pos].interpolate = interp;
|
2019-02-21 22:06:11 +02:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
});
|
|
|
|
};
|
2016-04-28 20:59:09 -04:00
|
|
|
|
2014-11-20 20:46:51 +01:00
|
|
|
/**
|
|
|
|
* Updates a link with a style
|
|
|
|
* @param pos
|
|
|
|
* @param style
|
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const updateLink = function(positions, style) {
|
|
|
|
positions.forEach(function(pos) {
|
2019-02-21 22:06:11 +02:00
|
|
|
if (pos === 'default') {
|
2019-09-12 12:58:04 -07:00
|
|
|
edges.defaultStyle = style;
|
2019-02-21 22:06:11 +02:00
|
|
|
} else {
|
|
|
|
if (utils.isSubstringInArray('fill', style) === -1) {
|
2019-09-12 12:58:04 -07:00
|
|
|
style.push('fill:none');
|
2019-02-21 22:06:11 +02:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
edges[pos].style = style;
|
2015-02-28 23:50:23 +01:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
});
|
|
|
|
};
|
2014-11-22 15:34:21 +01:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
export const addClass = function(id, style) {
|
2017-04-11 22:14:25 +08:00
|
|
|
if (typeof classes[id] === 'undefined') {
|
2019-09-12 12:58:04 -07:00
|
|
|
classes[id] = { id: id, styles: [] };
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof style !== 'undefined') {
|
|
|
|
if (style !== null) {
|
2019-09-12 12:58:04 -07:00
|
|
|
style.forEach(function(s) {
|
|
|
|
classes[id].styles.push(s);
|
|
|
|
});
|
2014-11-22 15:34:21 +01:00
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
};
|
2014-11-22 15:34:21 +01:00
|
|
|
|
2014-11-20 20:46:51 +01:00
|
|
|
/**
|
|
|
|
* Called by parser when a graph definition is found, stores the direction of the chart.
|
|
|
|
* @param dir
|
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const setDirection = function(dir) {
|
|
|
|
direction = dir;
|
2019-09-18 12:56:24 -07:00
|
|
|
if (direction.match(/.*</)) {
|
|
|
|
direction = 'RL';
|
|
|
|
}
|
|
|
|
if (direction.match(/.*\^/)) {
|
|
|
|
direction = 'BT';
|
|
|
|
}
|
|
|
|
if (direction.match(/.*>/)) {
|
|
|
|
direction = 'LR';
|
|
|
|
}
|
|
|
|
if (direction.match(/.*v/)) {
|
|
|
|
direction = 'TB';
|
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
};
|
2014-11-22 15:34:21 +01:00
|
|
|
|
|
|
|
/**
|
2018-12-01 15:31:57 +01:00
|
|
|
* Called by parser when a special node is found, e.g. a clickable element.
|
|
|
|
* @param ids Comma separated list of ids
|
|
|
|
* @param className Class to add
|
2014-11-22 15:34:21 +01:00
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const setClass = function(ids, className) {
|
|
|
|
ids.split(',').forEach(function(_id) {
|
|
|
|
let id = _id;
|
|
|
|
if (_id[0].match(/\d/)) id = 's' + id;
|
2015-10-02 00:18:47 +02:00
|
|
|
if (typeof vertices[id] !== 'undefined') {
|
2019-09-12 12:58:04 -07:00
|
|
|
vertices[id].classes.push(className);
|
2015-10-02 00:18:47 +02:00
|
|
|
}
|
2019-05-24 17:08:45 +02:00
|
|
|
|
|
|
|
if (typeof subGraphLookup[id] !== 'undefined') {
|
2019-09-12 12:58:04 -07:00
|
|
|
subGraphLookup[id].classes.push(className);
|
2019-05-24 17:08:45 +02:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
});
|
|
|
|
};
|
2017-04-11 22:14:25 +08:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
const setTooltip = function(ids, tooltip) {
|
|
|
|
ids.split(',').forEach(function(id) {
|
2018-12-01 15:31:57 +01:00
|
|
|
if (typeof tooltip !== 'undefined') {
|
2019-09-12 12:58:04 -07:00
|
|
|
tooltips[id] = sanitize(tooltip);
|
2018-12-01 15:31:57 +01:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
});
|
|
|
|
};
|
2017-04-11 22:14:25 +08:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
const setClickFun = function(_id, functionName) {
|
|
|
|
let id = _id;
|
|
|
|
if (_id[0].match(/\d/)) id = 's' + id;
|
2019-08-11 03:26:44 -07:00
|
|
|
if (config.securityLevel !== 'loose') {
|
2019-09-12 12:58:04 -07:00
|
|
|
return;
|
2019-07-13 22:50:53 -07:00
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
if (typeof functionName === 'undefined') {
|
2019-09-12 12:58:04 -07:00
|
|
|
return;
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
if (typeof vertices[id] !== 'undefined') {
|
2019-09-12 12:58:04 -07:00
|
|
|
funs.push(function(element) {
|
|
|
|
const elem = document.querySelector(`[id="${id}"]`);
|
2017-04-11 22:14:25 +08:00
|
|
|
if (elem !== null) {
|
2019-09-12 12:58:04 -07:00
|
|
|
elem.addEventListener(
|
|
|
|
'click',
|
|
|
|
function() {
|
|
|
|
window[functionName](id);
|
|
|
|
},
|
|
|
|
false
|
|
|
|
);
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
});
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
};
|
2017-04-11 22:14:25 +08:00
|
|
|
|
2018-12-01 15:31:57 +01:00
|
|
|
/**
|
|
|
|
* Called by parser when a link is found. Adds the URL to the vertex data.
|
|
|
|
* @param ids Comma separated list of ids
|
|
|
|
* @param linkStr URL to create a link for
|
|
|
|
* @param tooltip Tooltip for the clickable element
|
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const setLink = function(ids, linkStr, tooltip) {
|
|
|
|
ids.split(',').forEach(function(_id) {
|
|
|
|
let id = _id;
|
|
|
|
if (_id[0].match(/\d/)) id = 's' + id;
|
2018-12-01 15:31:57 +01:00
|
|
|
if (typeof vertices[id] !== 'undefined') {
|
2019-08-11 03:26:44 -07:00
|
|
|
if (config.securityLevel !== 'loose') {
|
2019-09-12 12:58:04 -07:00
|
|
|
vertices[id].link = sanitizeUrl(linkStr); // .replace(/javascript:.*/g, '')
|
2019-07-21 07:39:36 -07:00
|
|
|
} else {
|
2019-09-12 12:58:04 -07:00
|
|
|
vertices[id].link = linkStr;
|
2019-07-21 07:39:36 -07:00
|
|
|
}
|
2018-12-01 15:31:57 +01:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
});
|
|
|
|
setTooltip(ids, tooltip);
|
|
|
|
setClass(ids, 'clickable');
|
|
|
|
};
|
|
|
|
export const getTooltip = function(id) {
|
|
|
|
return tooltips[id];
|
|
|
|
};
|
2015-10-17 12:46:36 +02:00
|
|
|
|
2014-11-24 22:03:32 +01:00
|
|
|
/**
|
2018-12-01 15:31:57 +01:00
|
|
|
* Called by parser when a click definition is found. Registers an event handler.
|
|
|
|
* @param ids Comma separated list of ids
|
|
|
|
* @param functionName Function to be called on click
|
|
|
|
* @param tooltip Tooltip for the clickable element
|
2014-11-24 22:03:32 +01:00
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const setClickEvent = function(ids, functionName, tooltip) {
|
|
|
|
ids.split(',').forEach(function(id) {
|
|
|
|
setClickFun(id, functionName);
|
|
|
|
});
|
|
|
|
setTooltip(ids, tooltip);
|
|
|
|
setClass(ids, 'clickable');
|
|
|
|
};
|
|
|
|
|
|
|
|
export const bindFunctions = function(element) {
|
|
|
|
funs.forEach(function(fun) {
|
|
|
|
fun(element);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
export const getDirection = function() {
|
|
|
|
return direction;
|
|
|
|
};
|
2014-11-20 20:46:51 +01:00
|
|
|
/**
|
|
|
|
* Retrieval function for fetching the found nodes after parsing has completed.
|
|
|
|
* @returns {{}|*|vertices}
|
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const getVertices = function() {
|
|
|
|
return vertices;
|
|
|
|
};
|
2014-11-20 20:46:51 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieval function for fetching the found links after parsing has completed.
|
|
|
|
* @returns {{}|*|edges}
|
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const getEdges = function() {
|
|
|
|
return edges;
|
|
|
|
};
|
2014-11-20 20:46:51 +01:00
|
|
|
|
2014-11-22 15:34:21 +01:00
|
|
|
/**
|
|
|
|
* Retrieval function for fetching the found class definitions after parsing has completed.
|
|
|
|
* @returns {{}|*|classes}
|
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const getClasses = function() {
|
|
|
|
return classes;
|
|
|
|
};
|
2014-11-22 15:34:21 +01:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
const setupToolTips = function(element) {
|
|
|
|
let tooltipElem = d3.select('.mermaidTooltip');
|
2018-03-08 21:07:18 +08:00
|
|
|
if ((tooltipElem._groups || tooltipElem)[0][0] === null) {
|
2019-09-12 12:58:04 -07:00
|
|
|
tooltipElem = d3
|
|
|
|
.select('body')
|
2017-04-16 23:48:36 +08:00
|
|
|
.append('div')
|
|
|
|
.attr('class', 'mermaidTooltip')
|
2019-09-12 12:58:04 -07:00
|
|
|
.style('opacity', 0);
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2015-10-02 00:18:47 +02:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
const svg = d3.select(element).select('svg');
|
2015-10-02 00:18:47 +02:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
const nodes = svg.selectAll('g.node');
|
2017-04-11 22:14:25 +08:00
|
|
|
nodes
|
2019-09-12 12:58:04 -07:00
|
|
|
.on('mouseover', function() {
|
|
|
|
const el = d3.select(this);
|
|
|
|
const title = el.attr('title');
|
2017-04-16 23:48:36 +08:00
|
|
|
// Dont try to draw a tooltip if no data is provided
|
|
|
|
if (title === null) {
|
2019-09-12 12:58:04 -07:00
|
|
|
return;
|
2017-04-16 23:48:36 +08:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
const rect = this.getBoundingClientRect();
|
2017-04-16 23:48:36 +08:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
tooltipElem
|
|
|
|
.transition()
|
2017-04-16 23:48:36 +08:00
|
|
|
.duration(200)
|
2019-09-12 12:58:04 -07:00
|
|
|
.style('opacity', '.9');
|
|
|
|
tooltipElem
|
|
|
|
.html(el.attr('title'))
|
|
|
|
.style('left', rect.left + (rect.right - rect.left) / 2 + 'px')
|
|
|
|
.style('top', rect.top - 14 + document.body.scrollTop + 'px');
|
|
|
|
el.classed('hover', true);
|
2017-04-16 23:48:36 +08:00
|
|
|
})
|
2019-09-12 12:58:04 -07:00
|
|
|
.on('mouseout', function() {
|
|
|
|
tooltipElem
|
|
|
|
.transition()
|
2017-04-16 23:48:36 +08:00
|
|
|
.duration(500)
|
2019-09-12 12:58:04 -07:00
|
|
|
.style('opacity', 0);
|
|
|
|
const el = d3.select(this);
|
|
|
|
el.classed('hover', false);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
funs.push(setupToolTips);
|
2015-10-02 00:18:47 +02:00
|
|
|
|
2014-11-20 20:46:51 +01:00
|
|
|
/**
|
|
|
|
* Clears the internal graph db so that a new graph can be parsed.
|
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const clear = function() {
|
|
|
|
vertices = {};
|
|
|
|
classes = {};
|
|
|
|
edges = [];
|
|
|
|
funs = [];
|
|
|
|
funs.push(setupToolTips);
|
|
|
|
subGraphs = [];
|
|
|
|
subGraphLookup = {};
|
|
|
|
subCount = 0;
|
|
|
|
tooltips = [];
|
2019-09-18 12:56:24 -07:00
|
|
|
firstGraphFlag = true;
|
2019-09-12 12:58:04 -07:00
|
|
|
};
|
2014-11-20 20:46:51 +01:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const defaultStyle = function() {
|
|
|
|
return 'fill:#ffa;stroke: #f66; stroke-width: 3px; stroke-dasharray: 5, 5;fill:#ffa;stroke: #666;';
|
|
|
|
};
|
2015-01-07 21:02:58 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Clears the internal graph db so that a new graph can be parsed.
|
|
|
|
*/
|
2019-09-12 12:58:04 -07:00
|
|
|
export const addSubGraph = function(_id, list, _title) {
|
|
|
|
let id = _id;
|
|
|
|
let title = _title;
|
2019-08-15 08:57:49 +02:00
|
|
|
if (_id === _title && _title.match(/\s/)) {
|
2019-09-12 12:58:04 -07:00
|
|
|
id = undefined;
|
2019-08-15 08:57:49 +02:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
function uniq(a) {
|
|
|
|
const prims = { boolean: {}, number: {}, string: {} };
|
|
|
|
const objs = [];
|
2017-04-11 22:14:25 +08:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
return a.filter(function(item) {
|
|
|
|
const type = typeof item;
|
2018-03-17 18:12:24 +08:00
|
|
|
if (item.trim() === '') {
|
2019-09-12 12:58:04 -07:00
|
|
|
return false;
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
if (type in prims) {
|
|
|
|
return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true);
|
|
|
|
} else {
|
|
|
|
return objs.indexOf(item) >= 0 ? false : objs.push(item);
|
|
|
|
}
|
|
|
|
});
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
let nodeList = [];
|
2017-04-11 22:14:25 +08:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
nodeList = uniq(nodeList.concat.apply(nodeList, list));
|
2019-09-01 02:18:00 -07:00
|
|
|
for (let i = 0; i < nodeList.length; i++) {
|
2019-09-12 12:58:04 -07:00
|
|
|
if (nodeList[i][0].match(/\d/)) nodeList[i] = 's' + nodeList[i];
|
2019-09-01 00:44:48 -07:00
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
id = id || 'subGraph' + subCount;
|
|
|
|
if (id[0].match(/\d/)) id = 's' + id;
|
|
|
|
title = title || '';
|
|
|
|
title = sanitize(title);
|
|
|
|
subCount = subCount + 1;
|
|
|
|
const subGraph = { id: id, nodes: nodeList, title: title.trim(), classes: [] };
|
|
|
|
subGraphs.push(subGraph);
|
|
|
|
subGraphLookup[id] = subGraph;
|
|
|
|
return id;
|
|
|
|
};
|
|
|
|
|
|
|
|
const getPosForId = function(id) {
|
2017-09-14 20:27:52 +08:00
|
|
|
for (let i = 0; i < subGraphs.length; i++) {
|
2017-04-11 22:14:25 +08:00
|
|
|
if (subGraphs[i].id === id) {
|
2019-09-12 12:58:04 -07:00
|
|
|
return i;
|
2015-05-26 20:41:53 +02:00
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
let secCount = -1;
|
|
|
|
const posCrossRef = [];
|
|
|
|
const indexNodes2 = function(id, pos) {
|
|
|
|
const nodes = subGraphs[pos].nodes;
|
|
|
|
secCount = secCount + 1;
|
2017-04-11 22:14:25 +08:00
|
|
|
if (secCount > 2000) {
|
2019-09-12 12:58:04 -07:00
|
|
|
return;
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
posCrossRef[secCount] = pos;
|
2017-04-16 23:48:36 +08:00
|
|
|
// Check if match
|
2017-04-11 22:14:25 +08:00
|
|
|
if (subGraphs[pos].id === id) {
|
|
|
|
return {
|
|
|
|
result: true,
|
|
|
|
count: 0
|
2019-09-12 12:58:04 -07:00
|
|
|
};
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2015-05-26 20:41:53 +02:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
let count = 0;
|
|
|
|
let posCount = 1;
|
2017-04-11 22:14:25 +08:00
|
|
|
while (count < nodes.length) {
|
2019-09-12 12:58:04 -07:00
|
|
|
const childPos = getPosForId(nodes[count]);
|
2017-04-16 23:48:36 +08:00
|
|
|
// Ignore regular nodes (pos will be -1)
|
2017-04-11 22:14:25 +08:00
|
|
|
if (childPos >= 0) {
|
2019-09-12 12:58:04 -07:00
|
|
|
const res = indexNodes2(id, childPos);
|
2017-04-11 22:14:25 +08:00
|
|
|
if (res.result) {
|
|
|
|
return {
|
|
|
|
result: true,
|
|
|
|
count: posCount + res.count
|
2019-09-12 12:58:04 -07:00
|
|
|
};
|
2017-04-11 22:14:25 +08:00
|
|
|
} else {
|
2019-09-12 12:58:04 -07:00
|
|
|
posCount = posCount + res.count;
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2015-05-26 20:41:53 +02:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
count = count + 1;
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2015-05-26 20:41:53 +02:00
|
|
|
|
2017-04-11 22:14:25 +08:00
|
|
|
return {
|
|
|
|
result: false,
|
|
|
|
count: posCount
|
2019-09-12 12:58:04 -07:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
export const getDepthFirstPos = function(pos) {
|
|
|
|
return posCrossRef[pos];
|
|
|
|
};
|
|
|
|
export const indexNodes = function() {
|
|
|
|
secCount = -1;
|
2017-04-11 22:14:25 +08:00
|
|
|
if (subGraphs.length > 0) {
|
2019-09-12 12:58:04 -07:00
|
|
|
indexNodes2('none', subGraphs.length - 1, 0);
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
};
|
2015-05-26 20:41:53 +02:00
|
|
|
|
2019-09-12 12:58:04 -07:00
|
|
|
export const getSubGraphs = function() {
|
|
|
|
return subGraphs;
|
|
|
|
};
|
2017-09-10 21:51:48 +08:00
|
|
|
|
2019-09-18 12:56:24 -07:00
|
|
|
export const firstGraph = () => {
|
|
|
|
if (firstGraphFlag) {
|
|
|
|
firstGraphFlag = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2017-09-10 21:51:48 +08:00
|
|
|
export default {
|
|
|
|
addVertex,
|
|
|
|
addLink,
|
|
|
|
updateLinkInterpolate,
|
|
|
|
updateLink,
|
|
|
|
addClass,
|
|
|
|
setDirection,
|
|
|
|
setClass,
|
|
|
|
getTooltip,
|
|
|
|
setClickEvent,
|
2018-12-01 15:31:57 +01:00
|
|
|
setLink,
|
2017-09-10 21:51:48 +08:00
|
|
|
bindFunctions,
|
|
|
|
getDirection,
|
|
|
|
getVertices,
|
|
|
|
getEdges,
|
|
|
|
getClasses,
|
|
|
|
clear,
|
|
|
|
defaultStyle,
|
|
|
|
addSubGraph,
|
|
|
|
getDepthFirstPos,
|
|
|
|
indexNodes,
|
2019-09-18 12:56:24 -07:00
|
|
|
getSubGraphs,
|
|
|
|
lex: {
|
|
|
|
firstGraph
|
|
|
|
}
|
2019-09-12 12:58:04 -07:00
|
|
|
};
|