diff --git a/src/diagrams/er/erMarkers.js b/src/diagrams/er/erMarkers.js new file mode 100644 index 000000000..af9edbc9c --- /dev/null +++ b/src/diagrams/er/erMarkers.js @@ -0,0 +1,174 @@ +import * as d3 from 'd3'; + +const ERMarkers = { + ONLY_ONE_START: 'ONLY_ONE_START', + ONLY_ONE_END: 'ONLY_ONE_END', + + ZERO_OR_ONE_START: 'ZERO_OR_ONE_START', + ZERO_OR_ONE_END: 'ZERO_OR_ONE_END', + + ONE_OR_MORE_START: 'ONE_OR_MORE_START', + ONE_OR_MORE_END: 'ONE_OR_MORE_END', + + ZERO_OR_MORE_START: 'ZERO_OR_MORE_START', + ZERO_OR_MORE_END: 'ZERO_OR_MORE_END' +}; + +/** + * Put the markers into the svg DOM for use in paths + */ +const insertMarkers = function(elem, conf) { + let marker; + + const markerWidth = + elem + .append('defs') + .append('marker') + .attr('id', ERMarkers.ONLY_ONE_START) + .attr('refX', 0) + .attr('refY', 9) + .attr('markerWidth', 18) + .attr('markerHeight', 18) + .attr('orient', 'auto') + .append('path') + .attr('stroke', conf.stroke) + .attr('fill', 'none') + .attr('d', 'M9,0 L9,18 M15,0 L15,18'); + + elem + .append('defs') + .append('marker') + .attr('id', ERMarkers.ONLY_ONE_END) + .attr('refX', 18) + .attr('refY', 9) + .attr('markerWidth', 18) + .attr('markerHeight', 18) + .attr('orient', 'auto') + .append('path') + .attr('stroke', conf.stroke) + .attr('fill', 'none') + .attr('d', 'M3,0 L3,18 M9,0 L9,18'); + + marker = elem + .append('defs') + .append('marker') + .attr('id', ERMarkers.ZERO_OR_ONE_START) + .attr('refX', 0) + .attr('refY', 9) + .attr('markerWidth', 30) + .attr('markerHeight', 18) + .attr('orient', 'auto'); + marker + .append('circle') + .attr('stroke', conf.stroke) + .attr('fill', 'white') + .attr('cx', 21) + .attr('cy', 9) + .attr('r', 6); + marker + .append('path') + .attr('stroke', conf.stroke) + .attr('fill', 'none') + .attr('d', 'M9,0 L9,18'); + + marker = elem + .append('defs') + .append('marker') + .attr('id', ERMarkers.ZERO_OR_ONE_END) + .attr('refX', 30) + .attr('refY', 9) + .attr('markerWidth', 30) + .attr('markerHeight', 18) + .attr('orient', 'auto'); + marker + .append('circle') + .attr('stroke', conf.stroke) + .attr('fill', 'white') + .attr('cx', 9) + .attr('cy', 9) + .attr('r', 6); + marker + .append('path') + .attr('stroke', conf.stroke) + .attr('fill', 'none') + .attr('d', 'M21,0 L21,18'); + + elem + .append('defs') + .append('marker') + .attr('id', ERMarkers.ONE_OR_MORE_START) + .attr('refX', 0) + .attr('refY', 9) + .attr('markerWidth', 18) + .attr('markerHeight', 18) + .attr('orient', 'auto') + .append('path') + .attr('stroke', conf.stroke) + .attr('fill', 'none') + .attr('d', 'M0,0 L9,9 L0,18 M15,0 L15,18'); + + elem + .append('defs') + .append('marker') + .attr('id', ERMarkers.ONE_OR_MORE_END) + .attr('refX', 18) + .attr('refY', 9) + .attr('markerWidth', 21) + .attr('markerHeight', 18) + .attr('orient', 'auto') + .append('path') + .attr('stroke', conf.stroke) + .attr('fill', 'none') + .attr('d', 'M3,0 L3,18 M18,0 L9,9 L18,18'); + + marker = elem + .append('defs') + .append('marker') + .attr('id', ERMarkers.ZERO_OR_MORE_START) + .attr('refX', 0) + .attr('refY', 9) + .attr('markerWidth', 30) + .attr('markerHeight', 18) + .attr('orient', 'auto'); + marker + .append('circle') + .attr('stroke', conf.stroke) + .attr('fill', 'white') + .attr('cx', 21) + .attr('cy', 9) + .attr('r', 6); + marker + .append('path') + .attr('stroke', conf.stroke) + .attr('fill', 'none') + .attr('d', 'M0,0 L9,9 L0,18'); + + marker = elem + .append('defs') + .append('marker') + .attr('id', ERMarkers.ZERO_OR_MORE_END) + .attr('refX', 30) + .attr('refY', 9) + .attr('markerWidth', 30) + .attr('markerHeight', 18) + .attr('orient', 'auto'); + marker + .append('circle') + .attr('stroke', conf.stroke) + .attr('fill', 'white') + .attr('cx', 9) + .attr('cy', 9) + .attr('r', 6); + marker + .append('path') + .attr('stroke', conf.stroke) + .attr('fill', 'none') + .attr('d', 'M30,0 L21,9 L30,18'); + + return; +}; + +export default { + ERMarkers, + insertMarkers +}; diff --git a/src/diagrams/er/erRenderer.js b/src/diagrams/er/erRenderer.js index 15eeb6499..ba010dab7 100644 --- a/src/diagrams/er/erRenderer.js +++ b/src/diagrams/er/erRenderer.js @@ -5,6 +5,7 @@ import erParser from './parser/erDiagram'; import dagre from 'dagre'; import { getConfig } from '../../config'; import { logger } from '../../logger'; +import erMarkers from './erMarkers'; const conf = {}; export const setConf = function(cnf) { @@ -99,10 +100,119 @@ const addRelationships = function(relationships, g) { const drawRelationships = function(diagram, relationships, g) { relationships.forEach(function(rel) { - drawRelationship(diagram, rel, g); + //drawRelationship(diagram, rel, g); + drawRelationshipFromLayout(diagram, rel, g); }); }; // drawRelationships +const drawRelationshipFromLayout = function(diagram, rel, g) { + // Find the edge relating to this relationship + const edge = g.edge({ v: rel.entityA, w: rel.entityB }); + + // Using it's points, generate a line function + edge.points = edge.points.filter(p => !Number.isNaN(p.y)); // TODO: why is necessary? + + // Get a function that will generate the line path + const lineFunction = d3 + .line() + .x(function(d) { + return d.x; + }) + .y(function(d) { + return d.y; + }) + .curve(d3.curveBasis); + + // Append the line to the diagram node + const svgPath = diagram + .append('path') + .attr('d', lineFunction(edge.points)) + .attr('stroke', conf.stroke) + .attr('fill', 'none'); + + // TODO: Understand this + let url = ''; + if (conf.arrowMarkerAbsolute) { + url = + window.location.protocol + + '//' + + window.location.host + + window.location.pathname + + window.location.search; + url = url.replace(/\(/g, '\\('); + url = url.replace(/\)/g, '\\)'); + } + + // TODO: change the way enums are imported + // Decide which start and end markers it needs + switch (rel.cardinality) { + case erDb.Cardinality.ONLY_ONE_TO_ONE_OR_MORE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_END + ')'); + break; + case erDb.Cardinality.ONLY_ONE_TO_ZERO_OR_MORE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_END + ')'); + break; + case erDb.Cardinality.ZERO_OR_ONE_TO_ZERO_OR_MORE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_END + ')'); + break; + case erDb.Cardinality.ZERO_OR_ONE_TO_ONE_OR_MORE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_END + ')'); + break; + case erDb.Cardinality.ONE_OR_MORE_TO_ONLY_ONE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_END + ')'); + break; + case erDb.Cardinality.ZERO_OR_MORE_TO_ONLY_ONE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_END + ')'); + break; + case erDb.Cardinality.ZERO_OR_MORE_TO_ZERO_OR_ONE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_END + ')'); + break; + case erDb.Cardinality.ONE_OR_MORE_TO_ZERO_OR_ONE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_END + ')'); + break; + case erDb.Cardinality.ZERO_OR_ONE_TO_ONLY_ONE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_END + ')'); + break; + case erDb.Cardinality.ONLY_ONE_TO_ONLY_ONE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_END + ')'); + break; + case erDb.Cardinality.ONLY_ONE_TO_ZERO_OR_ONE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_END + ')'); + break; + case erDb.Cardinality.ZERO_OR_ONE_TO_ZERO_OR_ONE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_END + ')'); + break; + case erDb.Cardinality.ZERO_OR_MORE_TO_ZERO_OR_MORE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_END + ')'); + break; + case erDb.Cardinality.ZERO_OR_MORE_TO_ONE_OR_MORE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_END + ')'); + break; + case erDb.Cardinality.ONE_OR_MORE_TO_ZERO_OR_MORE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_END + ')'); + break; + case erDb.Cardinality.ONE_OR_MORE_TO_ONE_OR_MORE: + svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_START + ')'); + svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_END + ')'); + break; + } +}; + const drawRelationship = function(diagram, relationship, g) { // Set the from and to co-ordinates using the graph vertices @@ -406,7 +516,7 @@ export const draw = function(text, id) { const diagram = d3.select(`[id='${id}']`); // Add cardinality 'marker' definitions to the svg - //insertMarkers(diagram); + erMarkers.insertMarkers(diagram, conf); // Create the graph let g; @@ -451,8 +561,8 @@ export const draw = function(text, id) { //const element = d3.select('#' + id + ' g'); //render(element, g); + //drawFeet(diagram, relationships, g); drawRelationships(diagram, relationships, g); - drawFeet(diagram, relationships, g); drawEntities(diagram, entities, g, id); const padding = 8;