Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix:node self pointed -add cubicBezierCurve #15405

Open
wants to merge 33 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
8b32aa8
fix:node self pointed -add forth point in curveShape
HCLacids Jul 22, 2021
72af0df
Delete echarts.common.js
HCLacids Jul 23, 2021
92d8826
Delete echarts.common.js.map
HCLacids Jul 23, 2021
3a1948c
Delete package-lock.json
HCLacids Jul 23, 2021
095bbc8
Delete echarts.simple.min.js
HCLacids Jul 23, 2021
b4a6cf5
del:dist
HCLacids Jul 23, 2021
78cc2a2
Merge branch 'NodeSelf' of https://github.com/HCLacids/echarts into N…
HCLacids Jul 23, 2021
6465ea7
fix: the style of rendering
HCLacids Jul 29, 2021
8cc74f2
fix: change the cp2 type of null
HCLacids Jul 29, 2021
701bf75
reupload dist
HCLacids Jul 29, 2021
57a845b
fix:adjustEdge for self-pointed
HCLacids Jul 31, 2021
9fc51d1
feat:adjustEdge for node-self-pointed edge & fix:style of that node
HCLacids Aug 1, 2021
5123faf
fix:adjustEdge array Index
HCLacids Aug 1, 2021
8a10379
fix:the cp2 type
HCLacids Aug 1, 2021
e71cd6c
feat:the circularLayout & forceLayout
HCLacids Aug 2, 2021
468d479
go back
HCLacids Aug 2, 2021
fe2f81a
Update package.json
HCLacids Aug 2, 2021
60e8a01
Update package.json
HCLacids Aug 2, 2021
35db67f
reupload
HCLacids Aug 2, 2021
b169301
Merge branch 'NodeSelf' of https://github.com/HCLacids/echarts into N…
HCLacids Aug 2, 2021
2f67aa5
feat:the direction of the ring
HCLacids Aug 4, 2021
7ce32a3
fix:the adjustEdge when the edge is not monotone & fix the angle of t…
HCLacids Aug 8, 2021
72c785c
fix: the symbolRotation
HCLacids Aug 9, 2021
2e6a45c
feat: the circular & force Layout
HCLacids Aug 9, 2021
72d8e5e
feat:mutiple loop egdes
HCLacids Aug 16, 2021
9d44975
reupload dist
HCLacids Aug 16, 2021
eee6878
fix:some prettier problems
HCLacids Sep 7, 2021
0ee4cfa
fix: (1) Fix the self-loop edge layout strategy in 'simple' layout. (…
100pah Sep 23, 2021
483162d
Merge pull request #1 from 100pah/feat/HCLacids-NodeSelf-fix
HCLacids Sep 24, 2021
c830abc
fix: add pre-fix & error rotation
Sep 25, 2021
5f7391a
fix:circleLayout
Sep 25, 2021
950dd4b
test
Oct 8, 2021
644a3c9
prettier
Oct 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 143 additions & 40 deletions src/chart/graph/adjustEdge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,67 +26,120 @@ const v1: number[] = [];
const v2: number[] = [];
const v3: number[] = [];
const quadraticAt = curveTool.quadraticAt;
const cubicAt = curveTool.cubicAt;
const v2DistSquare = vec2.distSquare;
const mathAbs = Math.abs;
function intersectCurveCircle(
export function intersectCurveCircle(
curvePoints: number[][],
center: number[],
radius: number
) {
const p0 = curvePoints[0];
const p1 = curvePoints[1];
const p2 = curvePoints[2];
const p3 = curvePoints[3];

let d = Infinity;
let t;
const radiusSquare = radius * radius;
let interval = 0.1;

for (let _t = 0.1; _t <= 0.9; _t += 0.1) {
v1[0] = quadraticAt(p0[0], p1[0], p2[0], _t);
v1[1] = quadraticAt(p0[1], p1[1], p2[1], _t);
const diff = mathAbs(v2DistSquare(v1, center) - radiusSquare);
if (diff < d) {
d = diff;
t = _t;
if (p3) {
HCLacids marked this conversation as resolved.
Show resolved Hide resolved
for (let _t = 0.1; _t <= 0.9; _t += 0.1) {
v1[0] = cubicAt(p0[0], p1[0], p2[0], p3[0], _t);
v1[1] = cubicAt(p0[1], p1[1], p2[1], p3[1], _t);
const diff = mathAbs(v2DistSquare(v1, center) - radiusSquare);
if (diff < d) {
d = diff;
t = _t;
}
}
}
// Assume the segment is monotone,Find root through Bisection method
// At most 32 iteration
for (let i = 0; i < 32; i++) {
// const prev = t - interval;
const next = t + interval;
// v1[0] = cubicAt(p0[0], p1[0], p2[0], p3[0], prev);
// v1[1] = cubicAt(p0[1], p1[1], p2[1], p3[1], prev);
v2[0] = cubicAt(p0[0], p1[0], p2[0], p3[0], t);
v2[1] = cubicAt(p0[1], p1[1], p2[1], p3[1], t);
v3[0] = cubicAt(p0[0], p1[0], p2[0], p3[0], next);
v3[1] = cubicAt(p0[1], p1[1], p2[1], p3[1], next);

// Assume the segment is monotone,Find root through Bisection method
// At most 32 iteration
for (let i = 0; i < 32; i++) {
// let prev = t - interval;
const next = t + interval;
// v1[0] = quadraticAt(p0[0], p1[0], p2[0], prev);
// v1[1] = quadraticAt(p0[1], p1[1], p2[1], prev);
v2[0] = quadraticAt(p0[0], p1[0], p2[0], t);
v2[1] = quadraticAt(p0[1], p1[1], p2[1], t);
v3[0] = quadraticAt(p0[0], p1[0], p2[0], next);
v3[1] = quadraticAt(p0[1], p1[1], p2[1], next);

const diff = v2DistSquare(v2, center) - radiusSquare;
if (mathAbs(diff) < 1e-2) {
break;
}
const diff = v2DistSquare(v2, center) - radiusSquare;
if (mathAbs(diff) < 1e-2) {
break;
}

// let prevDiff = v2DistSquare(v1, center) - radiusSquare;
const nextDiff = v2DistSquare(v3, center) - radiusSquare;
// const prevDiff = v2DistSquare(v1, center) - radiusSquare;
const nextDiff = v2DistSquare(v3, center) - radiusSquare;

interval /= 2;
if (diff < 0) {
if (nextDiff >= 0) {
t = t + interval;
}
else {
t = t - interval;
interval /= 2;
if (diff < 0) {
HCLacids marked this conversation as resolved.
Show resolved Hide resolved
if (nextDiff >= 0) {
t = t + interval;
}
else {
t = t - interval;
}
}
else {
if (nextDiff >= 0) {
t = t - interval;
}
else {
t = t + interval;
}
}
}
}
else {
for (let _t = 0.1; _t <= 0.9; _t += 0.1) {
v1[0] = quadraticAt(p0[0], p1[0], p2[0], _t);
v1[1] = quadraticAt(p0[1], p1[1], p2[1], _t);
const diff = mathAbs(v2DistSquare(v1, center) - radiusSquare);
if (diff < d) {
d = diff;
t = _t;
}
}
else {
if (nextDiff >= 0) {
t = t - interval;

// Assume the segment is monotone,Find root through Bisection method
// At most 32 iteration
for (let i = 0; i < 32; i++) {
// let prev = t - interval;
const next = t + interval;
// v1[0] = quadraticAt(p0[0], p1[0], p2[0], prev);
// v1[1] = quadraticAt(p0[1], p1[1], p2[1], prev);
v2[0] = quadraticAt(p0[0], p1[0], p2[0], t);
v2[1] = quadraticAt(p0[1], p1[1], p2[1], t);
v3[0] = quadraticAt(p0[0], p1[0], p2[0], next);
v3[1] = quadraticAt(p0[1], p1[1], p2[1], next);

const diff = v2DistSquare(v2, center) - radiusSquare;
if (mathAbs(diff) < 1e-2) {
break;
}

// let prevDiff = v2DistSquare(v1, center) - radiusSquare;
const nextDiff = v2DistSquare(v3, center) - radiusSquare;

interval /= 2;
if (diff < 0) {
if (nextDiff >= 0) {
t = t + interval;
}
else {
t = t - interval;
}
}
else {
t = t + interval;
if (nextDiff >= 0) {
t = t - interval;
}
else {
t = t + interval;
}
}
}
}
Expand All @@ -98,16 +151,17 @@ function intersectCurveCircle(
export default function adjustEdge(graph: Graph, scale: number) {
const tmp0: number[] = [];
const quadraticSubdivide = curveTool.quadraticSubdivide;
const cubicSubdivide = curveTool.cubicSubdivide;
const pts: number[][] = [[], [], []];
const pts2: number[][] = [[], []];
const pts3 : number[][] = [[], [], [], []];
HCLacids marked this conversation as resolved.
Show resolved Hide resolved
const v: number[] = [];
scale /= 2;

graph.eachEdge(function (edge, idx) {
const linePoints = edge.getLayout();
const fromSymbol = edge.getVisual('fromSymbol');
const toSymbol = edge.getVisual('toSymbol');

if (!linePoints.__original) {
linePoints.__original = [
vec2.clone(linePoints[0]),
Expand All @@ -116,10 +170,59 @@ export default function adjustEdge(graph: Graph, scale: number) {
if (linePoints[2]) {
linePoints.__original.push(vec2.clone(linePoints[2]));
}
if (linePoints[3]) {
linePoints.__original.push(vec2.clone(linePoints[3]));
}
}
const originalPoints = linePoints.__original;
// Cubic curve
if (linePoints[3] != null) {
vec2.copy(pts3[0], originalPoints[0]);
vec2.copy(pts3[1], originalPoints[2]);
vec2.copy(pts3[2], originalPoints[3]);
vec2.copy(pts3[3], originalPoints[1]);

if (fromSymbol && fromSymbol !== 'none') {
const symbolSize = getSymbolSize(edge.node1);

let t = intersectCurveCircle(pts3, originalPoints[0], symbolSize * scale);
if (t > 0.5) {
t = 1 - t;
}
// Subdivide and get the second
cubicSubdivide(pts3[0][0], pts3[1][0], pts3[2][0], pts3[3][0], t, tmp0);
pts3[0][0] = tmp0[4];
pts3[1][0] = tmp0[5];
pts3[2][0] = tmp0[6];
cubicSubdivide(pts3[0][1], pts3[1][1], pts3[2][1], pts3[3][1], t, tmp0);
pts3[0][1] = tmp0[4];
pts3[1][1] = tmp0[5];
pts3[2][1] = tmp0[6];
}
if (toSymbol && toSymbol !== 'none') {
const symbolSize = getSymbolSize(edge.node2);

let t = intersectCurveCircle(pts3, originalPoints[1], symbolSize * scale);
if (t < 0.5) {
t = 1 - t;
}
// Subdivide and get the first
cubicSubdivide(pts3[0][0], pts3[1][0], pts3[2][0], pts3[3][0], t, tmp0);
pts3[1][0] = tmp0[1];
pts3[2][0] = tmp0[2];
pts3[3][0] = tmp0[3];
cubicSubdivide(pts3[0][1], pts3[1][1], pts3[2][1], pts3[3][1], t, tmp0);
pts3[1][1] = tmp0[1];
pts3[2][1] = tmp0[2];
pts3[3][1] = tmp0[3];
}
vec2.copy(linePoints[0], pts3[0]);
vec2.copy(linePoints[1], pts3[3]);
vec2.copy(linePoints[2], pts3[1]);
vec2.copy(linePoints[3], pts3[2]);
}
// Quadratic curve
if (linePoints[2] != null) {
else if (linePoints[2] != null) {
vec2.copy(pts[0], originalPoints[0]);
vec2.copy(pts[1], originalPoints[2]);
vec2.copy(pts[2], originalPoints[1]);
Expand Down
73 changes: 70 additions & 3 deletions src/chart/graph/circularLayoutHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
import * as vec2 from 'zrender/src/core/vector';
import {getSymbolSize, getNodeGlobalScale} from './graphHelper';
import GraphSeriesModel, { GraphEdgeItemOption } from './GraphSeries';
import Graph from '../../data/Graph';
import Graph, { GraphNode } from '../../data/Graph';
import List from '../../data/List';
import * as zrUtil from 'zrender/src/core/util';
import {getCurvenessForEdge} from '../helper/multipleGraphEdgeHelper';
import {cubicPosition} from './simpleLayoutHelper';

const PI = Math.PI;

Expand Down Expand Up @@ -88,16 +89,82 @@ export function circularLayout(
const p1 = vec2.clone(edge.node1.getLayout());
const p2 = vec2.clone(edge.node2.getLayout());
let cp1;
let cp2;
const x12 = (p1[0] + p2[0]) / 2;
const y12 = (p1[1] + p2[1]) / 2;
if (+curveness) {
if (edge.node1 === edge.node2) {
HCLacids marked this conversation as resolved.
Show resolved Hide resolved
const size = getSymbolSize(edge.node1);
const radius = getNodeGlobalScale(seriesModel) * size / 2;
const inEdges = edge.node1.inEdges.filter((edge) => {
HCLacids marked this conversation as resolved.
Show resolved Hide resolved
return edge.node1 !== edge.node2;
});
const outEdges = edge.node1.outEdges.filter((edge) => {
return edge.node1 !== edge.node2;
});
const allNodes: GraphNode[] = [];
inEdges.forEach((edge) => {
allNodes.push(edge.node1);
});
outEdges.forEach((edge) => {
allNodes.push(edge.node2);
});
const vectors: any[][] = [];
let d = -Infinity;
let pt1: number[] = [];
let pt2: number[] = [];
if (allNodes.length > 1) {
allNodes.forEach(node => {
HCLacids marked this conversation as resolved.
Show resolved Hide resolved
const v: any[] = [];
vec2.sub(v, node.getLayout(), edge.node1.getLayout());
vec2.normalize(v, v);
vectors.push(v);
});
// find the max angle
for (let i = 0; i < vectors.length; i++) {
for (let j = i + 1; j < vectors.length; j++) {
if (vec2.distSquare(vectors[i], vectors[j]) > d) {
d = vec2.distSquare(vectors[i], vectors[j]);
pt1 = vectors[i];
pt2 = vectors[j];
}
}
}
// if the angle is more than sixty degree
if (vec2.distSquare(pt1, pt2) > Math.sqrt(3)) {
vec2.scaleAndAdd(pt1, p1, pt1, radius);
vec2.scaleAndAdd(pt2, p2, pt2, radius);
const point1 = cubicPosition(pt1, p1, 10 * radius);
const point2 = cubicPosition(pt2, p2, 10 * radius);
const mid = [(point1[0] + point2[0]) / 2, (point1[1] + point2[1]) / 2];
vec2.sub(mid, mid, p1);
const degree = Math.atan2(mid[1], mid[0]) / Math.PI * 180;
const v1 = [Math.cos((degree - 30) * Math.PI / 180), Math.sin((degree - 30) * Math.PI / 180)];
const v2 = [Math.cos((degree + 30) * Math.PI / 180), Math.sin((degree + 30) * Math.PI / 180)];
vec2.scaleAndAdd(v1, p1, v1, 10 * radius);
vec2.scaleAndAdd(v2, p2, v2, 10 * radius);
cp1 = v1;
cp2 = v2;
}
else {
vec2.scaleAndAdd(pt1, p1, pt1, radius);
vec2.scaleAndAdd(pt2, p2, pt2, radius);
cp1 = cubicPosition(pt1, p1, 10 * radius);
cp2 = cubicPosition(pt2, p2, 10 * radius);
}
}
else {
cp1 = [p1[0] - radius * 2, p2[1] - radius * 4];
cp2 = [p1[0] + radius * 2, p2[1] - radius * 4];
}
}
else if (+curveness) {
curveness *= 3;
cp1 = [
cx * curveness + x12 * (1 - curveness),
cy * curveness + y12 * (1 - curveness)
];
}
edge.setLayout([p1, p2, cp1]);
edge.setLayout([p1, p2, cp1, cp2]);
});
}

Expand Down
24 changes: 24 additions & 0 deletions src/chart/graph/edgeVisual.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import GlobalModel from '../../model/Global';
import GraphSeriesModel, { GraphEdgeItemOption } from './GraphSeries';
import { extend } from 'zrender/src/core/util';
import { intersectCurveCircle } from './adjustEdge'
HCLacids marked this conversation as resolved.
Show resolved Hide resolved
import { getNodeGlobalScale, getSymbolSize } from './graphHelper';
import { cubicDerivativeAt } from 'zrender/src/core/curve';

function normalize(a: string | string[]): string[];
function normalize(a: number | number[]): number[];
Expand Down Expand Up @@ -50,6 +53,7 @@ export default function graphEdgeVisual(ecModel: GlobalModel) {
edgeData.each(function (idx) {
const itemModel = edgeData.getItemModel<GraphEdgeItemOption>(idx);
const edge = graph.getEdgeByIndex(idx);
const toSymbol = edge.getVisual('toSymbol');
const symbolType = normalize(itemModel.getShallow('symbol', true));
const symbolSize = normalize(itemModel.getShallow('symbolSize', true));
// Edge visual must after node visual
Expand All @@ -75,6 +79,26 @@ export default function graphEdgeVisual(ecModel: GlobalModel) {
symbolType[1] && edge.setVisual('toSymbol', symbolType[1]);
symbolSize[0] && edge.setVisual('fromSymbolSize', symbolSize[0]);
symbolSize[1] && edge.setVisual('toSymbolSize', symbolSize[1]);


if (edge.node1 === edge.node2 && toSymbol && toSymbol !== 'none') {
HCLacids marked this conversation as resolved.
Show resolved Hide resolved
const edgeData = edge.getLayout();
const size = getSymbolSize(edge.node1);
const radius = getNodeGlobalScale(seriesModel) * size / 2;

let t = intersectCurveCircle(edgeData, edgeData[0], radius);
if (t < 0.5) {
t = 1 - t;
}
const tdx = cubicDerivativeAt(edgeData[0][0], edgeData[1][0], edgeData[2][0], edgeData[3][0], t);
const tdy = cubicDerivativeAt(edgeData[0][1], edgeData[1][1], edgeData[2][1], edgeData[3][1], t);
const degree = Math.atan2(tdy, tdx) / Math.PI * 180;
if( degree > 90 || degree < 0 && degree > -90) {
HCLacids marked this conversation as resolved.
Show resolved Hide resolved
edge.setVisual('toSymbolRotate', degree + 188);
HCLacids marked this conversation as resolved.
Show resolved Hide resolved
} else {
edge.setVisual('toSymbolRotate', degree - 8);
}
}
});
});
}
Loading