未验证 提交 dd4dd938 编写于 作者: R RotPublic 提交者: GitHub

Optimize visual effects

Co-authored-by: Nwuzewu <wuzewu@baidu.com>
上级 6fdfcdea
html { html {
text-size-adjust: 100%; text-size-adjust: 100%;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
} }
body { body {
overflow: hidden; overflow: hidden;
margin: 0; margin: 0;
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', 'Ubuntu', 'Droid Sans', sans-serif, font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', 'Ubuntu', 'Droid Sans', sans-serif,
'PingFang SC'; 'PingFang SC';
font-size: 12px; font-size: 12px;
text-rendering: geometricPrecision; text-rendering: geometricPrecision;
background-color: #fff; background-color: #fff;
&.dark { &.dark {
background-color: #1d1d1f; background-color: #1d1d1f;
} }
} }
.graph { .graph {
overflow: auto; overflow: auto;
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.canvas { .canvas {
display: block; display: block;
// position: absolute; // position: absolute;
text-rendering: geometricPrecision; text-rendering: geometricPrecision;
user-select: none; user-select: none;
cursor: grab; cursor: grab;
} }
path { path {
stroke: #666; stroke: #666;
stroke-width: 1px; stroke-width: 1px;
fill: none; fill: none;
} }
line { line {
stroke: #666; stroke: #666;
stroke-width: 1px; stroke-width: 1px;
fill: #666; fill: #666;
} }
text { text {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', 'Ubuntu', 'Droid Sans', sans-serif, font-family: -apple-system, BlinkMacSystemFont, 'Segoe WPC', 'Segoe UI', 'Ubuntu', 'Droid Sans', sans-serif,
'PingFang SC'; 'PingFang SC';
font-size: 11px; font-size: 11px;
text-rendering: geometricPrecision; text-rendering: geometricPrecision;
fill: #000; fill: #000;
.dark & { .dark & {
fill: #cfcfd1; fill: #cfcfd1;
} }
} }
.node-item { .node-item {
path { path {
fill: #fff; fill: #fff;
fill-opacity: 1; fill-opacity: 1;
stroke: none; stroke: none;
transition: fill 0.075s ease-in, fill-opacity 0.075s ease-in; transition: fill 0.075s ease-in, fill-opacity 0.075s ease-in;
} }
text { text {
transition: fill 0.075s ease-in; transition: fill 0.075s ease-in;
} }
&:hover { &:hover {
path { path {
fill: #2932e1; fill: #2932e1;
fill-opacity: 1; fill-opacity: 1;
} }
text { text {
fill: #fff; fill: #fff;
} }
} }
} }
.node-item-function path { .node-item-function path {
fill: #9bb9e8; fill: #9bb9e8;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-type { .node-item-type {
cursor: pointer; cursor: pointer;
path { path {
fill: #8bb8ff; fill: #8bb8ff;
fill-opacity: 0.9; fill-opacity: 0.9;
} }
} }
.node-item-type-constant path { .node-item-type-constant path {
fill: #b4ccb7; fill: #b4ccb7;
} }
.node-item-type-control path { .node-item-type-control path {
fill: #a8e9b8; fill: #a8e9b8;
} }
.node-item-type-layer path { .node-item-type-layer path {
fill: #db989a; fill: #db989a;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-type-container path { .node-item-type-container path {
fill: #db989a; fill: #db989a;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-type-wrapper path { .node-item-type-wrapper path {
fill: #6dcde4; fill: #6dcde4;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-type-conv path { .node-item-type-conv path {
fill: #6dcde4; fill: #6dcde4;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-type-activation path { .node-item-type-activation path {
fill: #93c2ca; fill: #93c2ca;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-type-pool path { .node-item-type-pool path {
fill: #de7cce; fill: #de7cce;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-type-normalization path { .node-item-type-normalization path {
fill: #da96bc; fill: #da96bc;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-type-dropout path { .node-item-type-dropout path {
fill: #309e51; fill: #309e51;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-type-pad path { .node-item-type-pad path {
fill: #309e51; fill: #309e51;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-type-shape path { .node-item-type-shape path {
fill: #d6c482; fill: #d6c482;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-type-tensor path { .node-item-type-tensor path {
fill: #6d7ce4; fill: #6d7ce4;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-type-transform path { .node-item-type-transform path {
fill: #cdcb74; fill: #cdcb74;
} }
.node-item-type-sequence path { .node-item-type-sequence path {
fill: #cdcb74; fill: #cdcb74;
} }
.node-item-type-data path { .node-item-type-data path {
fill: #2576ad; fill: #2576ad;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-type-custom path { .node-item-type-custom path {
fill: #e46d6d; fill: #e46d6d;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.node-item-input { .node-item-input {
cursor: pointer; cursor: pointer;
path { path {
fill: #fff; fill: #fff;
} }
} }
.node-item-constant { .node-item-constant {
cursor: pointer; cursor: pointer;
path { path {
fill: #eee; fill: #eee;
} }
} }
.node-item-undefined { .node-item-undefined {
cursor: pointer; cursor: pointer;
path { path {
fill: #ca5353; fill: #ca5353;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
} }
.node-attribute { .node-attribute {
cursor: pointer; cursor: pointer;
text { text {
font-size: 9px; font-size: 9px;
font-weight: normal; font-weight: normal;
} }
} }
.node-attribute path { .node-attribute path {
fill: #fff; fill: #fff;
stroke-width: 0; stroke-width: 0;
.dark & { .dark & {
fill: #262629; fill: #262629;
} }
} }
.graph-item-input { .graph-item-input {
cursor: pointer; cursor: pointer;
path { path {
fill: #e49d6d; fill: #e49d6d;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
} }
.graph-item-output { .graph-item-output {
cursor: pointer; cursor: pointer;
path { path {
fill: #e4e06d; fill: #e4e06d;
fill-opacity: 0.9; fill-opacity: 0.9;
} }
} }
.edge-label text { .edge-label text {
font-size: 10px; font-size: 10px;
} }
.edge-path { .edge-path {
stroke: #666; stroke: #666;
stroke-width: 1px; stroke-width: 1px;
fill: none; fill: none;
} }
#arrowhead-vee path { #arrowhead-vee path {
fill: #666; fill: #666;
} }
.edge-path-control-dependency { .edge-path-control-dependency {
stroke-dasharray: 3, 2; stroke-dasharray: 3, 2;
} }
.cluster .clusterGroup { .cluster .clusterGroup {
fill: #dce9ff; fill: #dce9ff;
stroke: #666; stroke: #666;
stroke-width: 1px; stroke-width: 1px;
} }
.node-item-function path { .node-item-function path {
fill: #9bb9e8; fill: #9bb9e8;
fill-opacity: 0.7; fill-opacity: 0.7;
} }
.cluster .clusterGroup-constant { .cluster .clusterGroup-constant {
fill: #e8efe9; fill: #e8efe9;
} }
.cluster .clusterGroup-control { .cluster .clusterGroup-control {
fill: #e4f8e9; fill: #e4f8e9;
} }
.cluster .clusterGroup-layer { .cluster .clusterGroup-layer {
fill: #f4e0e0; fill: #f4e0e0;
} }
.cluster .clusterGroup-conv { .cluster .clusterGroup-conv {
fill: #d3f0f6; fill: #d3f0f6;
} }
.cluster .clusterGroup-container { .cluster .clusterGroup-container {
fill: #f4e0e0; fill: #f4e0e0;
} }
.cluster .clusterGroup-wrapper { .cluster .clusterGroup-wrapper {
fill: #d3f0f6; fill: #d3f0f6;
} }
.cluster .clusterGroup-activation { .cluster .clusterGroup-activation {
fill: #deecef; fill: #deecef;
} }
.cluster .clusterGroup-pool { .cluster .clusterGroup-pool {
fill: #f5d7f0; fill: #f5d7f0;
} }
.cluster .clusterGroup-normalization { .cluster .clusterGroup-normalization {
fill: #f3dfea; fill: #f3dfea;
} }
.cluster .clusterGroup-dropout { .cluster .clusterGroup-dropout {
fill: #c0e1ca; fill: #c0e1ca;
} }
.cluster .clusterGroup-pad { .cluster .clusterGroup-pad {
fill: #c0e1ca; fill: #c0e1ca;
} }
.cluster .clusterGroup-shape { .cluster .clusterGroup-shape {
fill: #f2edd9; fill: #f2edd9;
} }
.cluster .clusterGroup-tensor { .cluster .clusterGroup-tensor {
fill: #d3d7f6; fill: #d3d7f6;
} }
.cluster .clusterGroup-transform { .cluster .clusterGroup-transform {
fill: #f0efd5; fill: #f0efd5;
} }
.cluster .clusterGroup-sequence { .cluster .clusterGroup-sequence {
fill: #f0efd5; fill: #f0efd5;
} }
.cluster .clusterGroup-data { .cluster .clusterGroup-data {
fill: #bdd5e6; fill: #bdd5e6;
} }
.cluster .clusterGroup-custom { .cluster .clusterGroup-custom {
fill: #f6d3d3; fill: #f6d3d3;
} }
.cluster .clusterButton { .cluster .clusterButton {
fill-opacity: 0.3;
fill-opacity: 0;
fill: #db989a; fill: #db989a;
stroke: #999; stroke: #999;
cursor: pointer; cursor: pointer;
} }
.cluster .button-text { .cluster .button-text {
fill: #999; fill: #999;
} }
.cluster.border { .cluster.border {
display: none; display: none;
} }
.select { .select {
&.edge-path { &.edge-path {
stroke: #1527c2; stroke: #1527c2;
stroke-width: 2px; stroke-width: 2px;
stroke-dasharray: 6px 3px; stroke-dasharray: 6px 3px;
stroke-dashoffset: 0; stroke-dashoffset: 0;
animation: pulse 4s infinite linear; animation: pulse 4s infinite linear;
} }
.node.border { .node.border {
stroke: #1527c2; stroke: #1527c2;
stroke-width: 2px; stroke-width: 2px;
stroke-dasharray: 6px 3px; stroke-dasharray: 6px 3px;
stroke-dashoffset: 0; stroke-dashoffset: 0;
animation: pulse 4s infinite linear; animation: pulse 4s infinite linear;
} }
.cluster.border { .cluster.border {
display: block; display: block;
stroke: #1527c2; stroke: #1527c2;
stroke-width: 2px; stroke-width: 2px;
stroke-dasharray: 6px 3px; stroke-dasharray: 6px 3px;
stroke-dashoffset: 0; stroke-dashoffset: 0;
animation: pulse 4s infinite linear; animation: pulse 4s infinite linear;
} }
} }
@keyframes pulse { @keyframes pulse {
from { from {
stroke-dashoffset: 100px; stroke-dashoffset: 100px;
} }
to { to {
stroke-dashoffset: 0; stroke-dashoffset: 0;
} }
} }
\ No newline at end of file
...@@ -15,39 +15,59 @@ ...@@ -15,39 +15,59 @@
*/ */
var grapher = grapher || {}; var grapher = grapher || {};
var dagre = dagre || require('dagre'); var dagre = dagre || require('dagre');
grapher.Renderer = class { grapher.Renderer = class {
constructor(host, svgElement, view) { constructor(host, svgElement, view) {
this._document = host.document; this._document = host.document;
this._svgElement = svgElement; this._svgElement = svgElement;
this._host = host; this._host = host;
this._view = view; this._view = view;
} }
render(graph) { render(graph) {
let svgClusterGroup = null; let svgClusterGroup = null;
let svgEdgePathGroup = null; let svgEdgePathGroup = null;
let svgEdgeLabelGroup = null; let svgEdgeLabelGroup = null;
let svgNodeGroup = null; let svgNodeGroup = null;
svgClusterGroup = this.createElement('g'); svgClusterGroup = this.createElement('g');
svgClusterGroup.setAttribute('id', 'clusters'); svgClusterGroup.setAttribute('id', 'clusters');
svgClusterGroup.setAttribute('class', 'clusters'); svgClusterGroup.setAttribute('class', 'clusters');
this._svgElement.appendChild(svgClusterGroup); this._svgElement.appendChild(svgClusterGroup);
svgEdgePathGroup = this.createElement('g'); svgEdgePathGroup = this.createElement('g');
svgEdgePathGroup.setAttribute('id', 'edge-paths'); svgEdgePathGroup.setAttribute('id', 'edge-paths');
svgEdgePathGroup.setAttribute('class', 'edge-paths'); svgEdgePathGroup.setAttribute('class', 'edge-paths');
this._svgElement.appendChild(svgEdgePathGroup); this._svgElement.appendChild(svgEdgePathGroup);
svgEdgeLabelGroup = this.createElement('g'); svgEdgeLabelGroup = this.createElement('g');
svgEdgeLabelGroup.setAttribute('id', 'edge-labels'); svgEdgeLabelGroup.setAttribute('id', 'edge-labels');
svgEdgeLabelGroup.setAttribute('class', 'edge-labels'); svgEdgeLabelGroup.setAttribute('class', 'edge-labels');
this._svgElement.appendChild(svgEdgeLabelGroup); this._svgElement.appendChild(svgEdgeLabelGroup);
svgNodeGroup = this.createElement('g'); svgNodeGroup = this.createElement('g');
svgNodeGroup.setAttribute('id', 'nodes'); svgNodeGroup.setAttribute('id', 'nodes');
svgNodeGroup.setAttribute('class', 'nodes'); svgNodeGroup.setAttribute('class', 'nodes');
this._svgElement.appendChild(svgNodeGroup); this._svgElement.appendChild(svgNodeGroup);
// } else { // } else {
// svgClusterGroup = this._document.getElementById('clusters') // svgClusterGroup = this._document.getElementById('clusters')
...@@ -59,6 +79,7 @@ grapher.Renderer = class { ...@@ -59,6 +79,7 @@ grapher.Renderer = class {
for (const nodeId of graph.nodes()) { for (const nodeId of graph.nodes()) {
if (graph.children(nodeId).length == 0) { if (graph.children(nodeId).length == 0) {
const node = graph.node(nodeId); const node = graph.node(nodeId);
// 在这里进行缓存的判断 // 在这里进行缓存的判断
// console.log('this._document', this._document); // console.log('this._document', this._document);
// const nodeDom = this._document.getElementById(node.id); // const nodeDom = this._document.getElementById(node.id);
...@@ -67,11 +88,15 @@ grapher.Renderer = class { ...@@ -67,11 +88,15 @@ grapher.Renderer = class {
// 这个节点存在过 // 这个节点存在过
svgNodeGroup.appendChild(this._view._nodes[node.id]); svgNodeGroup.appendChild(this._view._nodes[node.id]);
const nodeBox = this._view._nodes[node.id].getBBox(); const nodeBox = this._view._nodes[node.id].getBBox();
node.width = nodeBox.width; node.width = nodeBox.width;
node.height = nodeBox.height; node.height = nodeBox.height;
node.element = this._view._nodes[node.id]; node.element = this._view._nodes[node.id];
} else { } else {
const element = this.createElement('g'); const element = this.createElement('g');
if (node.id) { if (node.id) {
element.setAttribute('id', node.id); element.setAttribute('id', node.id);
} }
...@@ -80,17 +105,25 @@ grapher.Renderer = class { ...@@ -80,17 +105,25 @@ grapher.Renderer = class {
Object.prototype.hasOwnProperty.call(node, 'class') ? 'node ' + node.class : 'node' Object.prototype.hasOwnProperty.call(node, 'class') ? 'node ' + node.class : 'node'
); );
element.style.opacity = 0; element.style.opacity = 0;
const container = this.createElement('g'); const container = this.createElement('g');
container.appendChild(node.label); container.appendChild(node.label);
// node.label 就是fromat 之后的节点 // node.label 就是fromat 之后的节点
element.appendChild(container); element.appendChild(container);
svgNodeGroup.appendChild(element); svgNodeGroup.appendChild(element);
const nodeBox = node.label.getBBox(); const nodeBox = node.label.getBBox();
const nodeX = -nodeBox.width / 2; const nodeX = -nodeBox.width / 2;
const nodeY = -nodeBox.height / 2; const nodeY = -nodeBox.height / 2;
container.setAttribute('transform', 'translate(' + nodeX + ',' + nodeY + ')'); container.setAttribute('transform', 'translate(' + nodeX + ',' + nodeY + ')');
node.width = nodeBox.width; node.width = nodeBox.width;
node.height = nodeBox.height; node.height = nodeBox.height;
node.element = element; node.element = element;
} }
} }
...@@ -98,27 +131,43 @@ grapher.Renderer = class { ...@@ -98,27 +131,43 @@ grapher.Renderer = class {
for (const edgeId of graph.edges()) { for (const edgeId of graph.edges()) {
const edge = graph.edge(edgeId); const edge = graph.edge(edgeId);
if (edge.label) { if (edge.label) {
const tspan = this.createElement('tspan'); const tspan = this.createElement('tspan');
tspan.setAttribute('xml:space', 'preserve'); tspan.setAttribute('xml:space', 'preserve');
tspan.setAttribute('dy', '1em'); tspan.setAttribute('dy', '1em');
tspan.setAttribute('x', '1'); tspan.setAttribute('x', '1');
tspan.appendChild(this._document.createTextNode(edge.label)); tspan.appendChild(this._document.createTextNode(edge.label));
const text = this.createElement('text'); const text = this.createElement('text');
text.appendChild(tspan); text.appendChild(tspan);
const textContainer = this.createElement('g'); const textContainer = this.createElement('g');
textContainer.appendChild(text); textContainer.appendChild(text);
const labelElement = this.createElement('g'); const labelElement = this.createElement('g');
labelElement.style.opacity = 0; labelElement.style.opacity = 0;
labelElement.setAttribute('class', 'edge-label'); labelElement.setAttribute('class', 'edge-label');
labelElement.appendChild(textContainer); labelElement.appendChild(textContainer);
svgEdgeLabelGroup.appendChild(labelElement); svgEdgeLabelGroup.appendChild(labelElement);
const edgeBox = textContainer.getBBox(); const edgeBox = textContainer.getBBox();
const edgeX = -edgeBox.width / 2; const edgeX = -edgeBox.width / 2;
const edgeY = -edgeBox.height / 2; const edgeY = -edgeBox.height / 2;
textContainer.setAttribute('transform', 'translate(' + edgeX + ',' + edgeY + ')'); textContainer.setAttribute('transform', 'translate(' + edgeX + ',' + edgeY + ')');
edge.width = edgeBox.width; edge.width = edgeBox.width;
edge.height = edgeBox.height; edge.height = edgeBox.height;
edge.labelElement = labelElement; edge.labelElement = labelElement;
} }
} }
...@@ -128,49 +177,74 @@ grapher.Renderer = class { ...@@ -128,49 +177,74 @@ grapher.Renderer = class {
for (const nodeId of graph.nodes()) { for (const nodeId of graph.nodes()) {
if (graph.children(nodeId).length == 0) { if (graph.children(nodeId).length == 0) {
const node = graph.node(nodeId); const node = graph.node(nodeId);
node.element.setAttribute('transform', 'translate(' + node.x + ',' + node.y + ')'); node.element.setAttribute('transform', 'translate(' + node.x + ',' + node.y + ')');
node.element.style.opacity = 1; node.element.style.opacity = 1;
delete node.element; delete node.element;
} }
} }
for (const edgeId of graph.edges()) { for (const edgeId of graph.edges()) {
const edge = graph.edge(edgeId); const edge = graph.edge(edgeId);
if (edge.labelElement) { if (edge.labelElement) {
edge.labelElement.setAttribute('transform', 'translate(' + edge.x + ',' + edge.y + ')'); edge.labelElement.setAttribute('transform', 'translate(' + edge.x + ',' + edge.y + ')');
edge.labelElement.style.opacity = 1; edge.labelElement.style.opacity = 1;
delete edge.labelElement; delete edge.labelElement;
} }
} }
const edgePathGroupDefs = this.createElement('defs'); const edgePathGroupDefs = this.createElement('defs');
svgEdgePathGroup.appendChild(edgePathGroupDefs); svgEdgePathGroup.appendChild(edgePathGroupDefs);
const marker = this.createElement('marker'); const marker = this.createElement('marker');
marker.setAttribute('id', 'arrowhead-vee'); marker.setAttribute('id', 'arrowhead-vee');
marker.setAttribute('viewBox', '0 0 10 10'); marker.setAttribute('viewBox', '0 0 10 10');
marker.setAttribute('refX', 9); marker.setAttribute('refX', 9);
marker.setAttribute('refY', 5); marker.setAttribute('refY', 5);
marker.setAttribute('markerUnits', 'strokeWidth'); marker.setAttribute('markerUnits', 'strokeWidth');
marker.setAttribute('markerWidth', 8); marker.setAttribute('markerWidth', 8);
marker.setAttribute('markerHeight', 6); marker.setAttribute('markerHeight', 6);
marker.setAttribute('orient', 'auto'); marker.setAttribute('orient', 'auto');
edgePathGroupDefs.appendChild(marker); edgePathGroupDefs.appendChild(marker);
const markerPath = this.createElement('path'); const markerPath = this.createElement('path');
markerPath.setAttribute('d', 'M 0 0 L 10 5 L 0 10 L 4 5 z'); markerPath.setAttribute('d', 'M 0 0 L 10 5 L 0 10 L 4 5 z');
markerPath.style.setProperty('stroke-width', 1); markerPath.style.setProperty('stroke-width', 1);
markerPath.style.setProperty('stroke-dasharray', '1,0'); markerPath.style.setProperty('stroke-dasharray', '1,0');
marker.appendChild(markerPath); marker.appendChild(markerPath);
for (const edgeId of graph.edges()) { for (const edgeId of graph.edges()) {
const edge = graph.edge(edgeId); const edge = graph.edge(edgeId);
const edgePath = grapher.Renderer._computeCurvePath(edge, graph.node(edgeId.v), graph.node(edgeId.w)); const edgePath = grapher.Renderer._computeCurvePath(edge, graph.node(edgeId.v), graph.node(edgeId.w));
const edgeElement = this.createElement('path'); const edgeElement = this.createElement('path');
edgeElement.setAttribute( edgeElement.setAttribute(
'class', 'class',
Object.prototype.hasOwnProperty.call(edge, 'class') ? 'edge-path ' + edge.class : 'edge-path' Object.prototype.hasOwnProperty.call(edge, 'class') ? 'edge-path ' + edge.class : 'edge-path'
); );
edgeElement.setAttribute('d', edgePath); edgeElement.setAttribute('d', edgePath);
edgeElement.setAttribute('marker-end', 'url(#arrowhead-vee)'); edgeElement.setAttribute('marker-end', 'url(#arrowhead-vee)');
if (edge.id) { if (edge.id) {
edgeElement.setAttribute('id', edge.id); edgeElement.setAttribute('id', edge.id);
} }
...@@ -183,6 +257,7 @@ grapher.Renderer = class { ...@@ -183,6 +257,7 @@ grapher.Renderer = class {
svgEdgePathGroup.appendChild(edgeElement); svgEdgePathGroup.appendChild(edgeElement);
} }
const groupArray = []; const groupArray = [];
for (const nodeId of graph.nodes()) { for (const nodeId of graph.nodes()) {
if (!Number(nodeId) && Number(nodeId) !== 0) { if (!Number(nodeId) && Number(nodeId) !== 0) {
groupArray.push(nodeId); groupArray.push(nodeId);
...@@ -190,52 +265,76 @@ grapher.Renderer = class { ...@@ -190,52 +265,76 @@ grapher.Renderer = class {
} }
const newGroupArray = groupArray.sort((a, b) => { const newGroupArray = groupArray.sort((a, b) => {
let level1 = a.split('/').length; let level1 = a.split('/').length;
let level2 = b.split('/').length; let level2 = b.split('/').length;
return level1 - level2; return level1 - level2;
}); });
for (const nodeId of newGroupArray) { for (const nodeId of newGroupArray) {
if (graph.children(nodeId).length > 0) { if (graph.children(nodeId).length > 0) {
const node = graph.node(nodeId); const node = graph.node(nodeId);
// const nodeDom = this._document.getElementById(`node-${nodeId}`)
// if (this._view._nodes.hasOwnProperty(node.id)) {
// // 这个节点存在过
// svgNodeGroup.appendChild(this._view._nodes[node.id]);
// const nodeBox = this._view._nodes[node.id].getBBox();
// node.width = nodeBox.width;
// node.height = nodeBox.height;
// node.element = this._view._nodes[node.id]
if (this._view._clusters.hasOwnProperty(node.id)) { if (this._view._clusters.hasOwnProperty(node.id)) {
const nodeDom = this._view._clusters.hasOwnProperty(node.id); const nodeDom = this._view._clusters.hasOwnProperty(node.id);
nodeDom.setAttribute('transform', 'translate(' + node.x + ',' + node.y + ')'); nodeDom.setAttribute('transform', 'translate(' + node.x + ',' + node.y + ')');
nodeDom.firstChild.setAttribute('x', -node.width / 2); nodeDom.firstChild.setAttribute('x', -node.width / 2);
nodeDom.firstChild.setAttribute('y', -node.height / 2); nodeDom.firstChild.setAttribute('y', -node.height / 2);
nodeDom.firstChild.setAttribute('width', node.width + 10); nodeDom.firstChild.setAttribute('width', node.width + 10);
nodeDom.firstChild.setAttribute('height', node.height + 10); nodeDom.firstChild.setAttribute('height', node.height + 10);
} else { } else {
const nodeElement = this.createElement('g'); const nodeElement = this.createElement('g');
nodeElement.setAttribute('class', 'cluster'); nodeElement.setAttribute('class', 'cluster');
nodeElement.setAttribute('id', `node-${nodeId}`); nodeElement.setAttribute('id', `node-${nodeId}`);
nodeElement.setAttribute('transform', 'translate(' + node.x + ',' + node.y + ')'); nodeElement.setAttribute('transform', 'translate(' + node.x + ',' + node.y + ')');
const rect = this.createElement('rect'); const rect = this.createElement('rect');
const tspan = this.createElement('tspan'); const tspan = this.createElement('tspan');
const button = this.createElement('circle'); const button = this.createElement('circle');
const buttonSign = this.createElement('tspan'); const buttonSign = this.createElement('tspan');
button.setAttribute('r', '6.5'); button.setAttribute('r', '6.5');
button.setAttribute('cx', node.width / 2 - 20 + 7.5 + 10); button.setAttribute('cx', node.width / 2 - 20 + 7.5 + 10);
button.setAttribute('cy', -(node.height / 2) + 5 + 7.5); button.setAttribute('cy', -(node.height / 2) + 5 + 7.5);
buttonSign.setAttribute('x', node.width / 2 - 15 + 9); buttonSign.setAttribute('x', node.width / 2 - 15 + 9);
buttonSign.setAttribute('y', -(node.height / 2) + 1.3); buttonSign.setAttribute('y', -(node.height / 2) + 1.3);
buttonSign.setAttribute('xml:space', 'preserve'); buttonSign.setAttribute('xml:space', 'preserve');
buttonSign.setAttribute('dy', '1em'); buttonSign.setAttribute('dy', '1em');
buttonSign.setAttribute('font-size', '16px'); buttonSign.setAttribute('font-size', '16px');
buttonSign.setAttribute('class', 'button-text'); buttonSign.setAttribute('class', 'button-text');
button.setAttribute('class', 'clusterButton'); button.setAttribute('class', 'clusterButton');
tspan.setAttribute('xml:space', 'preserve'); tspan.setAttribute('xml:space', 'preserve');
tspan.setAttribute('dy', '1em'); tspan.setAttribute('dy', '1em');
tspan.setAttribute('x', 0); tspan.setAttribute('x', 0);
tspan.setAttribute('y', -(node.height / 2) + 5); tspan.setAttribute('y', -(node.height / 2) + 5);
tspan.setAttribute('text-anchor', 'middle'); tspan.setAttribute('text-anchor', 'middle');
let name = ''; let name = '';
for (const nodes of this._host._view._allGraph.nodes) { for (const nodes of this._host._view._allGraph.nodes) {
if (nodes.name === node.nodeId) { if (nodes.name === node.nodeId) {
name = nodes.show_name.split('/')[nodes.show_name.split('/').length - 1]; name = nodes.show_name.split('/')[nodes.show_name.split('/').length - 1];
...@@ -244,23 +343,36 @@ grapher.Renderer = class { ...@@ -244,23 +343,36 @@ grapher.Renderer = class {
tspan.appendChild(this._document.createTextNode(name)); tspan.appendChild(this._document.createTextNode(name));
buttonSign.appendChild(this._document.createTextNode('-')); buttonSign.appendChild(this._document.createTextNode('-'));
const text = this.createElement('text'); const text = this.createElement('text');
text.appendChild(tspan); text.appendChild(tspan);
const text2 = this.createElement('text'); const text2 = this.createElement('text');
text2.appendChild(buttonSign); text2.appendChild(buttonSign);
rect.setAttribute('class', node.classList.join(' ')); rect.setAttribute('class', node.classList.join(' '));
rect.setAttribute('x', -node.width / 2); rect.setAttribute('x', -node.width / 2);
rect.setAttribute('y', -node.height / 2); rect.setAttribute('y', -node.height / 2);
rect.setAttribute('width', node.width + 10); rect.setAttribute('width', node.width + 10);
rect.setAttribute('height', node.height + 10); rect.setAttribute('height', node.height + 10);
const borderElement = this.createElement('path'); const borderElement = this.createElement('path');
borderElement.setAttribute('class', ['cluster', 'border'].join(' ')); borderElement.setAttribute('class', ['cluster', 'border'].join(' '));
borderElement.setAttribute( borderElement.setAttribute(
'd', 'd',
grapher.NodeElement.roundedRect( grapher.NodeElement.roundedRect2(
-node.width / 2, -node.width / 2,
-node.height / 2, -node.height / 2,
node.width + 10, node.width + 10,
node.height + 10, node.height + 10,
true, true,
true, true,
true, true,
...@@ -270,19 +382,25 @@ grapher.Renderer = class { ...@@ -270,19 +382,25 @@ grapher.Renderer = class {
nodeElement.addEventListener('click', () => { nodeElement.addEventListener('click', () => {
this._view.select({ this._view.select({
id: `node-${nodeId}`, id: `node-${nodeId}`,
name: nodeId, name: nodeId,
type: 'node' type: 'node'
}); });
}); });
text2.addEventListener('click', () => { text2.addEventListener('click', () => {
this._host.selectNodeId({ this._host.selectNodeId({
nodeId: node.nodeId, nodeId: node.nodeId,
expand: node.expand, expand: node.expand,
isKeepData: node.isKeepData isKeepData: node.isKeepData
}); });
this._host.selectItems({ this._host.selectItems({
id: `node-${node.nodeId}`, id: `node-${node.nodeId}`,
name: node.nodeId, name: node.nodeId,
type: 'node' type: 'node'
}); });
}); });
...@@ -340,17 +458,23 @@ grapher.Renderer = class { ...@@ -340,17 +458,23 @@ grapher.Renderer = class {
static _computeCurvePath(edge, tail, head) { static _computeCurvePath(edge, tail, head) {
const points = edge.points.slice(1, edge.points.length - 1); const points = edge.points.slice(1, edge.points.length - 1);
points.unshift(grapher.Renderer.intersectRect(tail, points[0])); points.unshift(grapher.Renderer.intersectRect(tail, points[0]));
points.push(grapher.Renderer.intersectRect(head, points[points.length - 1])); points.push(grapher.Renderer.intersectRect(head, points[points.length - 1]));
const path = new Path(); const path = new Path();
const curve = new Curve(path); const curve = new Curve(path);
for (let i = 0; i < points.length; i++) { for (let i = 0; i < points.length; i++) {
const point = points[i]; const point = points[i];
if (i == 0) { if (i == 0) {
curve.lineStart(); curve.lineStart();
} }
curve.point(point.x, point.y); curve.point(point.x, point.y);
if (i == points.length - 1) { if (i == points.length - 1) {
curve.lineEnd(); curve.lineEnd();
} }
...@@ -361,24 +485,34 @@ grapher.Renderer = class { ...@@ -361,24 +485,34 @@ grapher.Renderer = class {
static intersectRect(node, point) { static intersectRect(node, point) {
const x = node.x; const x = node.x;
const y = node.y; const y = node.y;
const dx = point.x - x; const dx = point.x - x;
const dy = point.y - y; const dy = point.y - y;
let w = node.width / 2; let w = node.width / 2;
let h = node.height / 2; let h = node.height / 2;
let sx; let sx;
let sy; let sy;
if (Math.abs(dy) * w > Math.abs(dx) * h) { if (Math.abs(dy) * w > Math.abs(dx) * h) {
if (dy < 0) { if (dy < 0) {
h = -h; h = -h;
} }
sx = dy === 0 ? 0 : (h * dx) / dy; sx = dy === 0 ? 0 : (h * dx) / dy;
sy = h; sy = h;
} else { } else {
if (dx < 0) { if (dx < 0) {
w = -w; w = -w;
} }
sx = w; sx = w;
sy = dx === 0 ? 0 : (w * dy) / dx; sy = dx === 0 ? 0 : (w * dy) / dx;
} }
return {x: x + sx, y: y + sy}; return {x: x + sx, y: y + sy};
...@@ -388,17 +522,21 @@ grapher.Renderer = class { ...@@ -388,17 +522,21 @@ grapher.Renderer = class {
grapher.NodeElement = class { grapher.NodeElement = class {
constructor(document) { constructor(document) {
this._document = document; this._document = document;
this._blocks = []; this._blocks = [];
} }
block(type) { block(type) {
this._block = null; this._block = null;
switch (type) { switch (type) {
case 'header': case 'header':
this._block = new grapher.NodeElement.Header(this._document); this._block = new grapher.NodeElement.Header(this._document);
break; break;
case 'list': case 'list':
this._block = new grapher.NodeElement.List(this._document); this._block = new grapher.NodeElement.List(this._document);
break; break;
} }
this._blocks.push(this._block); this._blocks.push(this._block);
...@@ -407,9 +545,12 @@ grapher.NodeElement = class { ...@@ -407,9 +545,12 @@ grapher.NodeElement = class {
format(contextElement) { format(contextElement) {
const rootElement = this.createElement('g'); const rootElement = this.createElement('g');
contextElement.appendChild(rootElement); contextElement.appendChild(rootElement);
let width = 0; let width = 0;
let height = 0; let height = 0;
const tops = []; const tops = [];
for (const block of this._blocks) { for (const block of this._blocks) {
...@@ -424,22 +565,91 @@ grapher.NodeElement = class { ...@@ -424,22 +565,91 @@ grapher.NodeElement = class {
for (let i = 0; i < this._blocks.length; i++) { for (let i = 0; i < this._blocks.length; i++) {
// push 进来的header 或者 list // push 进来的header 或者 list
const top = tops.shift(); const top = tops.shift();
this._blocks[i].update(rootElement, top, width, i == 0, i == this._blocks.length - 1); this._blocks[i].update(rootElement, top, width, i == 0, i == this._blocks.length - 1);
} }
const borderElement = this.createElement('path'); const borderElement = this.createElement('path');
borderElement.setAttribute('class', ['node', 'border'].join(' ')); borderElement.setAttribute('class', ['node', 'border'].join(' '));
borderElement.setAttribute('d', grapher.NodeElement.roundedRect(0, 0, width, height, true, true, true, true)); borderElement.setAttribute('d', grapher.NodeElement.roundedRect(0, 0, width, height, true, true, true, true));
rootElement.appendChild(borderElement); rootElement.appendChild(borderElement);
contextElement.innerHTML = ''; contextElement.innerHTML = '';
return rootElement; return rootElement;
} }
static roundedRect(x, y, width, height, r1, r2, r3, r4) { static roundedRect(x, y, width, height, r1, r2, r3, r4) {
const radius = 5; const radius = 5;
r1 = r1 ? radius : 0;
r2 = r2 ? radius : 0;
r3 = r3 ? radius : 0;
r4 = r4 ? radius : 0;
return (
'M' +
(x + r1) +
',' +
y +
'h' +
(width - r1 - r2) +
'a' +
r2 +
',' +
r2 +
' 0 0 1 ' +
r2 +
',' +
r2 +
'v' +
(height - r2 - r3) +
'a' +
r3 +
',' +
r3 +
' 0 0 1 ' +
-r3 +
',' +
r3 +
'h' +
(r3 + r4 - width) +
'a' +
r4 +
',' +
r4 +
' 0 0 1 ' +
-r4 +
',' +
-r4 +
'v' +
(-height + r4 + r1) +
'a' +
r1 +
',' +
r1 +
' 0 0 1 ' +
r1 +
',' +
-r1 +
'z'
);
}
static roundedRect2(x, y, width, height, r1, r2, r3, r4) {
const radius = 10;
r1 = r1 ? radius : 0; r1 = r1 ? radius : 0;
r2 = r2 ? radius : 0; r2 = r2 ? radius : 0;
r3 = r3 ? radius : 0; r3 = r3 ? radius : 0;
r4 = r4 ? radius : 0; r4 = r4 ? radius : 0;
return ( return (
'M' + 'M' +
(x + r1) + (x + r1) +
...@@ -497,39 +707,56 @@ grapher.NodeElement = class { ...@@ -497,39 +707,56 @@ grapher.NodeElement = class {
grapher.NodeElement.Header = class { grapher.NodeElement.Header = class {
constructor(document) { constructor(document) {
this._document = document; this._document = document;
this._items = []; this._items = [];
} }
add(id, classList, content, tooltip, handler) { add(id, classList, content, tooltip, handler) {
this._items.push({ this._items.push({
id: id, id: id,
classList: classList, classList: classList,
content: content, content: content,
tooltip: tooltip, tooltip: tooltip,
handler: handler handler: handler
}); });
} }
layout(parentElement) { layout(parentElement) {
this._width = 0; this._width = 0;
this._height = 0; this._height = 0;
this._elements = []; this._elements = [];
let x = 0; let x = 0;
const y = 0; const y = 0;
for (const item of this._items) { for (const item of this._items) {
const yPadding = 4; const yPadding = 4;
const xPadding = 7; const xPadding = 7;
const element = this.createElement('g'); const element = this.createElement('g');
let classList = ['node-item']; let classList = ['node-item'];
parentElement.appendChild(element); parentElement.appendChild(element);
const pathElement = this.createElement('path'); const pathElement = this.createElement('path');
const textElement = this.createElement('text'); const textElement = this.createElement('text');
element.appendChild(pathElement); element.appendChild(pathElement);
element.appendChild(textElement); element.appendChild(textElement);
if (item.classList) { if (item.classList) {
classList = classList.concat(item.classList); classList = classList.concat(item.classList);
} }
element.setAttribute('class', classList.join(' ')); element.setAttribute('class', classList.join(' '));
if (item.id) { if (item.id) {
element.setAttribute('id', item.id); element.setAttribute('id', item.id);
} }
...@@ -538,27 +765,41 @@ grapher.NodeElement.Header = class { ...@@ -538,27 +765,41 @@ grapher.NodeElement.Header = class {
} }
if (item.tooltip) { if (item.tooltip) {
const titleElement = this.createElement('title'); const titleElement = this.createElement('title');
titleElement.textContent = item.tooltip; titleElement.textContent = item.tooltip;
element.appendChild(titleElement); element.appendChild(titleElement);
} }
if (item.content) { if (item.content) {
textElement.textContent = item.content; textElement.textContent = item.content;
} }
const boundingBox = textElement.getBBox(); const boundingBox = textElement.getBBox();
const width = boundingBox.width + xPadding + xPadding; const width = boundingBox.width + xPadding + xPadding;
const height = boundingBox.height + yPadding + yPadding; const height = boundingBox.height + yPadding + yPadding;
this._elements.push({ this._elements.push({
group: element, group: element,
text: textElement, text: textElement,
path: pathElement, path: pathElement,
x: x, x: x,
y: y, y: y,
width: width, width: width,
height: height, height: height,
tx: xPadding, tx: xPadding,
ty: yPadding - boundingBox.y ty: yPadding - boundingBox.y
}); });
x += width; x += width;
if (this._height < height) { if (this._height < height) {
this._height = height; this._height = height;
} }
...@@ -578,15 +819,19 @@ grapher.NodeElement.Header = class { ...@@ -578,15 +819,19 @@ grapher.NodeElement.Header = class {
update(parentElement, top, width, first, last) { update(parentElement, top, width, first, last) {
const dx = width - this._width; const dx = width - this._width;
let i; let i;
let element; let element;
for (i = 0; i < this._elements.length; i++) { for (i = 0; i < this._elements.length; i++) {
element = this._elements[i]; element = this._elements[i];
if (i == 0) { if (i == 0) {
element.width = element.width + dx; element.width = element.width + dx;
} else { } else {
element.x = element.x + dx; element.x = element.x + dx;
element.tx = element.tx + dx; element.tx = element.tx + dx;
} }
element.y = element.y + top; element.y = element.y + top;
...@@ -594,40 +839,61 @@ grapher.NodeElement.Header = class { ...@@ -594,40 +839,61 @@ grapher.NodeElement.Header = class {
for (i = 0; i < this._elements.length; i++) { for (i = 0; i < this._elements.length; i++) {
element = this._elements[i]; element = this._elements[i];
element.group.setAttribute('transform', 'translate(' + element.x + ',' + element.y + ')'); element.group.setAttribute('transform', 'translate(' + element.x + ',' + element.y + ')');
const r1 = i == 0 && first; const r1 = i == 0 && first;
const r2 = i == this._elements.length - 1 && first; const r2 = i == this._elements.length - 1 && first;
const r3 = i == this._elements.length - 1 && last; const r3 = i == this._elements.length - 1 && last;
const r4 = i == 0 && last; const r4 = i == 0 && last;
element.path.setAttribute( element.path.setAttribute(
'd', 'd',
grapher.NodeElement.roundedRect(0, 0, element.width, element.height, r1, r2, r3, r4) grapher.NodeElement.roundedRect(0, 0, element.width, element.height, r1, r2, r3, r4)
); );
element.text.setAttribute('x', 6); element.text.setAttribute('x', 7);
element.text.setAttribute('y', element.ty);
element.text.setAttribute('y', element.ty - 1);
} }
let lineElement; let lineElement;
for (i = 0; i < this._elements.length; i++) { for (i = 0; i < this._elements.length; i++) {
element = this._elements[i]; element = this._elements[i];
if (i != 0) { if (i != 0) {
lineElement = this.createElement('line'); lineElement = this.createElement('line');
lineElement.setAttribute('class', 'node'); lineElement.setAttribute('class', 'node');
lineElement.setAttribute('x1', element.x); lineElement.setAttribute('x1', element.x);
lineElement.setAttribute('x2', element.x); lineElement.setAttribute('x2', element.x);
lineElement.setAttribute('y1', top); lineElement.setAttribute('y1', top);
lineElement.setAttribute('y2', top + this._height); lineElement.setAttribute('y2', top + this._height);
parentElement.appendChild(lineElement); parentElement.appendChild(lineElement);
} }
} }
if (!first) { if (!first) {
lineElement = this.createElement('line'); lineElement = this.createElement('line');
lineElement.setAttribute('class', 'node'); lineElement.setAttribute('class', 'node');
lineElement.setAttribute('x1', 0); lineElement.setAttribute('x1', 0);
lineElement.setAttribute('x2', width); lineElement.setAttribute('x2', width);
lineElement.setAttribute('y1', top); lineElement.setAttribute('y1', top);
lineElement.setAttribute('y2', top); lineElement.setAttribute('y2', top);
parentElement.appendChild(lineElement); parentElement.appendChild(lineElement);
} }
} }
...@@ -640,6 +906,7 @@ grapher.NodeElement.Header = class { ...@@ -640,6 +906,7 @@ grapher.NodeElement.Header = class {
grapher.NodeElement.List = class { grapher.NodeElement.List = class {
constructor(document) { constructor(document) {
this._document = document; this._document = document;
this._items = []; this._items = [];
} }
...@@ -657,49 +924,72 @@ grapher.NodeElement.List = class { ...@@ -657,49 +924,72 @@ grapher.NodeElement.List = class {
layout(parentElement) { layout(parentElement) {
this._width = 0; this._width = 0;
this._height = 0; this._height = 0;
const x = 0; const x = 0;
const y = 0; const y = 0;
this._element = this.createElement('g'); this._element = this.createElement('g');
this._element.setAttribute('class', 'node-attribute'); this._element.setAttribute('class', 'node-attribute');
parentElement.appendChild(this._element); parentElement.appendChild(this._element);
if (this._handler) { if (this._handler) {
this._element.addEventListener('click', this._handler); this._element.addEventListener('click', this._handler);
} }
this._backgroundElement = this.createElement('path'); this._backgroundElement = this.createElement('path');
this._element.appendChild(this._backgroundElement); this._element.appendChild(this._backgroundElement);
this._element.setAttribute('transform', 'translate(' + x + ',' + y + ')'); this._element.setAttribute('transform', 'translate(' + x + ',' + y + ')');
this._height += 3; this._height += 3;
for (const item of this._items) { for (const item of this._items) {
const yPadding = 1; const yPadding = 1;
const xPadding = 6; const xPadding = 6;
const textElement = this.createElement('text'); const textElement = this.createElement('text');
if (item.id) { if (item.id) {
textElement.setAttribute('id', item.id); textElement.setAttribute('id', item.id);
} }
textElement.setAttribute('xml:space', 'preserve'); textElement.setAttribute('xml:space', 'preserve');
this._element.appendChild(textElement); this._element.appendChild(textElement);
if (item.tooltip) { if (item.tooltip) {
const titleElement = this.createElement('title'); const titleElement = this.createElement('title');
titleElement.textContent = item.tooltip; titleElement.textContent = item.tooltip;
textElement.appendChild(titleElement); textElement.appendChild(titleElement);
} }
const textNameElement = this.createElement('tspan'); const textNameElement = this.createElement('tspan');
textNameElement.textContent = item.name; textNameElement.textContent = item.name;
if (item.separator.trim() != '=') { if (item.separator.trim() != '=') {
textNameElement.style.fontWeight = 'bold'; textNameElement.style.fontWeight = 'bold';
} }
textElement.appendChild(textNameElement); textElement.appendChild(textNameElement);
const textValueElement = this.createElement('tspan'); const textValueElement = this.createElement('tspan');
textValueElement.textContent = item.separator + item.value; textValueElement.textContent = item.separator + item.value;
textElement.appendChild(textValueElement); textElement.appendChild(textValueElement);
const size = textElement.getBBox(); const size = textElement.getBBox();
const width = xPadding + size.width + xPadding; const width = xPadding + size.width + xPadding;
if (this._width < width) { if (this._width < width) {
this._width = width; this._width = width;
} }
textElement.setAttribute('x', x + xPadding); textElement.setAttribute('x', x + xPadding);
textElement.setAttribute('y', this._height + yPadding - size.y); textElement.setAttribute('y', this._height + yPadding - size.y);
this._height += yPadding + size.height + yPadding; this._height += yPadding + size.height + yPadding;
} }
this._height += 3; this._height += 3;
...@@ -721,9 +1011,13 @@ grapher.NodeElement.List = class { ...@@ -721,9 +1011,13 @@ grapher.NodeElement.List = class {
this._element.setAttribute('transform', 'translate(0,' + top + ')'); this._element.setAttribute('transform', 'translate(0,' + top + ')');
const r1 = first; const r1 = first;
const r2 = first; const r2 = first;
const r3 = last; const r3 = last;
const r4 = last; const r4 = last;
this._backgroundElement.setAttribute( this._backgroundElement.setAttribute(
'd', 'd',
grapher.NodeElement.roundedRect(0, 0, width, this._height, r1, r2, r3, r4) grapher.NodeElement.roundedRect(0, 0, width, this._height, r1, r2, r3, r4)
...@@ -731,11 +1025,17 @@ grapher.NodeElement.List = class { ...@@ -731,11 +1025,17 @@ grapher.NodeElement.List = class {
if (!first) { if (!first) {
const lineElement = this.createElement('line'); const lineElement = this.createElement('line');
lineElement.setAttribute('class', 'node'); lineElement.setAttribute('class', 'node');
lineElement.setAttribute('x1', 0); lineElement.setAttribute('x1', 0);
lineElement.setAttribute('x2', width); lineElement.setAttribute('x2', width);
lineElement.setAttribute('y1', 0); lineElement.setAttribute('y1', 0);
lineElement.setAttribute('y2', 0); lineElement.setAttribute('y2', 0);
this._element.appendChild(lineElement); this._element.appendChild(lineElement);
} }
} }
...@@ -748,9 +1048,13 @@ grapher.NodeElement.List = class { ...@@ -748,9 +1048,13 @@ grapher.NodeElement.List = class {
class Path { class Path {
constructor() { constructor() {
this._x0 = null; this._x0 = null;
this._y0 = null; this._y0 = null;
this._x1 = null; this._x1 = null;
this._y1 = null; this._y1 = null;
this._data = ''; this._data = '';
} }
...@@ -769,7 +1073,9 @@ class Path { ...@@ -769,7 +1073,9 @@ class Path {
closePath() { closePath() {
if (this._x1 !== null) { if (this._x1 !== null) {
this._x1 = this._x0; this._x1 = this._x0;
this._y1 = this._y0; this._y1 = this._y0;
this._data += 'Z'; this._data += 'Z';
} }
} }
...@@ -786,9 +1092,13 @@ class Curve { ...@@ -786,9 +1092,13 @@ class Curve {
lineStart() { lineStart() {
this._x0 = NaN; this._x0 = NaN;
this._x1 = NaN; this._x1 = NaN;
this._y0 = NaN; this._y0 = NaN;
this._y1 = NaN; this._y1 = NaN;
this._point = 0; this._point = 0;
} }
...@@ -796,10 +1106,13 @@ class Curve { ...@@ -796,10 +1106,13 @@ class Curve {
switch (this._point) { switch (this._point) {
case 3: case 3:
this.curve(this._x1, this._y1); this.curve(this._x1, this._y1);
this._context.lineTo(this._x1, this._y1); this._context.lineTo(this._x1, this._y1);
break; break;
case 2: case 2:
this._context.lineTo(this._x1, this._y1); this._context.lineTo(this._x1, this._y1);
break; break;
} }
if (this._line || (this._line !== 0 && this._point === 1)) { if (this._line || (this._line !== 0 && this._point === 1)) {
...@@ -810,10 +1123,13 @@ class Curve { ...@@ -810,10 +1123,13 @@ class Curve {
point(x, y) { point(x, y) {
x = +x; x = +x;
y = +y; y = +y;
switch (this._point) { switch (this._point) {
case 0: case 0:
this._point = 1; this._point = 1;
if (this._line) { if (this._line) {
this._context.lineTo(x, y); this._context.lineTo(x, y);
} else { } else {
...@@ -822,29 +1138,42 @@ class Curve { ...@@ -822,29 +1138,42 @@ class Curve {
break; break;
case 1: case 1:
this._point = 2; this._point = 2;
break; break;
case 2: case 2:
this._point = 3; this._point = 3;
this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6);
this.curve(x, y); this.curve(x, y);
break; break;
default: default:
this.curve(x, y); this.curve(x, y);
break; break;
} }
this._x0 = this._x1; this._x0 = this._x1;
this._x1 = x; this._x1 = x;
this._y0 = this._y1; this._y0 = this._y1;
this._y1 = y; this._y1 = y;
} }
curve(x, y) { curve(x, y) {
this._context.bezierCurveTo( this._context.bezierCurveTo(
(2 * this._x0 + this._x1) / 3, (2 * this._x0 + this._x1) / 3,
(2 * this._y0 + this._y1) / 3, (2 * this._y0 + this._y1) / 3,
(this._x0 + 2 * this._x1) / 3, (this._x0 + 2 * this._x1) / 3,
(this._y0 + 2 * this._y1) / 3, (this._y0 + 2 * this._y1) / 3,
(this._x0 + 4 * this._x1 + x) / 6, (this._x0 + 4 * this._x1 + x) / 6,
(this._y0 + 4 * this._y1 + y) / 6 (this._y0 + 4 * this._y1 + y) / 6
); );
} }
...@@ -852,5 +1181,6 @@ class Curve { ...@@ -852,5 +1181,6 @@ class Curve {
if (typeof module !== 'undefined' && typeof module.exports === 'object') { if (typeof module !== 'undefined' && typeof module.exports === 'object') {
module.exports.Renderer = grapher.Renderer; module.exports.Renderer = grapher.Renderer;
module.exports.NodeElement = grapher.NodeElement; module.exports.NodeElement = grapher.NodeElement;
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册