feat(edge): add quadratic edge element (#5402)
* feat(edge): add quadratic edge element * test(edge): add quadratic unit tests * fix(edge): fix code review --------- Co-authored-by: yvonneyx <banxuan.zyx@antgroup.com>
34
packages/g6/__tests__/demo/animation/edge-quadratic.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { Quadratic } from '../../../src/elements/edges';
|
||||
import type { AnimationTestCase } from '../types';
|
||||
|
||||
export const edgeQuadratic: AnimationTestCase = async (context) => {
|
||||
const { canvas } = context;
|
||||
|
||||
const quadratic = new Quadratic({
|
||||
style: {
|
||||
sourcePoint: [100, 50],
|
||||
targetPoint: [300, 50],
|
||||
lineWidth: 2,
|
||||
stroke: '#1890FF',
|
||||
labelText: 'quadratic-edge',
|
||||
labelFontSize: 12,
|
||||
endArrow: true,
|
||||
},
|
||||
});
|
||||
|
||||
await canvas.init();
|
||||
|
||||
canvas.appendChild(quadratic);
|
||||
|
||||
const result = quadratic.animate(
|
||||
[
|
||||
{ sourcePoint: [100, 150], targetPoint: [300, 200], lineWidth: 2 },
|
||||
{ sourcePoint: [100, 150], targetPoint: [450, 350], lineWidth: 10 },
|
||||
],
|
||||
{ duration: 1000, fill: 'both' },
|
||||
);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
edgeQuadratic.times = [0, 500, 1000];
|
@ -5,4 +5,6 @@ export * from './animation-fade-in';
|
||||
export * from './animation-translate';
|
||||
export * from './animation-wave';
|
||||
export * from './animation-zoom-in';
|
||||
export * from './edge-line';
|
||||
export * from './edge-quadratic';
|
||||
export * from './shape-label';
|
||||
|
@ -0,0 +1,82 @@
|
||||
import { Quadratic } from '../../../src/elements/edges';
|
||||
import type { StaticTestCase } from '../types';
|
||||
|
||||
export const edgeQuadratic: StaticTestCase = async (context) => {
|
||||
const { canvas } = context;
|
||||
|
||||
const quadratic1 = new Quadratic({
|
||||
style: {
|
||||
// key shape
|
||||
sourcePoint: [100, 50],
|
||||
targetPoint: [300, 50],
|
||||
stroke: '#1890FF',
|
||||
lineWidth: 2,
|
||||
// halo
|
||||
halo: true,
|
||||
haloOpacity: 0.25,
|
||||
haloLineWidth: 12,
|
||||
// label
|
||||
labelText: 'default quadratic',
|
||||
labelFontSize: 12,
|
||||
// end arrow
|
||||
endArrow: true,
|
||||
},
|
||||
});
|
||||
|
||||
const quadratic2 = new Quadratic({
|
||||
style: {
|
||||
// key shape
|
||||
sourcePoint: [100, 150],
|
||||
targetPoint: [300, 150],
|
||||
controlPoint: [200, 200],
|
||||
stroke: '#1890FF',
|
||||
lineWidth: 2,
|
||||
// label
|
||||
labelText: 'controlPoint=[200, 200]',
|
||||
labelFontSize: 12,
|
||||
// end arrow
|
||||
endArrow: true,
|
||||
},
|
||||
});
|
||||
|
||||
const quadratic3 = new Quadratic({
|
||||
style: {
|
||||
// key shape
|
||||
sourcePoint: [100, 250],
|
||||
targetPoint: [300, 250],
|
||||
curveOffset: 50,
|
||||
curvePosition: 0.5,
|
||||
stroke: '#1890FF',
|
||||
lineWidth: 2,
|
||||
// label
|
||||
labelText: 'curveOffset=50, curvePosition:0.5',
|
||||
labelFontSize: 12,
|
||||
// end arrow
|
||||
endArrow: true,
|
||||
},
|
||||
});
|
||||
|
||||
const quadratic4 = new Quadratic({
|
||||
style: {
|
||||
// key shape
|
||||
sourcePoint: [100, 350],
|
||||
targetPoint: [300, 350],
|
||||
curveOffset: 50,
|
||||
curvePosition: 0.25,
|
||||
stroke: '#1890FF',
|
||||
lineWidth: 2,
|
||||
// label
|
||||
labelText: 'curveOffset=50, curvePosition:0.25',
|
||||
labelFontSize: 12,
|
||||
// end arrow
|
||||
endArrow: true,
|
||||
},
|
||||
});
|
||||
|
||||
await canvas.init();
|
||||
|
||||
canvas.appendChild(quadratic1);
|
||||
canvas.appendChild(quadratic2);
|
||||
canvas.appendChild(quadratic3);
|
||||
canvas.appendChild(quadratic4);
|
||||
};
|
@ -1,4 +1,5 @@
|
||||
export * from './edge-line';
|
||||
export * from './edge-quadratic';
|
||||
export * from './layered-canvas';
|
||||
export * from './node-circle';
|
||||
export * from './shape-badge';
|
||||
|
@ -1,135 +0,0 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="500"
|
||||
height="500"
|
||||
style="background: transparent; position: absolute; outline: none;"
|
||||
color-interpolation-filters="sRGB"
|
||||
tabindex="1"
|
||||
>
|
||||
<defs />
|
||||
<g id="g-svg-camera" transform="matrix(1,0,0,1,0,0)">
|
||||
<g
|
||||
id="g-root"
|
||||
fill="none"
|
||||
stroke="none"
|
||||
visibility="visible"
|
||||
font-size="16px"
|
||||
font-family="sans-serif"
|
||||
font-style="normal"
|
||||
font-weight="normal"
|
||||
font-variant="normal"
|
||||
text-anchor="left"
|
||||
stroke-dashoffset="0px"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g
|
||||
id="g-svg-5"
|
||||
fill="none"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
stroke-width="2px"
|
||||
marker-start="true"
|
||||
marker-end="true"
|
||||
stroke-dasharray="10px,10px"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g
|
||||
opacity="0"
|
||||
pointer-events="none"
|
||||
stroke-width="12px"
|
||||
stroke-dasharray="0px,0px"
|
||||
transform="matrix(1,0,0,1,100,150)"
|
||||
>
|
||||
<line
|
||||
id="halo"
|
||||
fill="none"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="200"
|
||||
y2="50"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
stroke-width="2px"
|
||||
stroke-dasharray="10px,10px"
|
||||
transform="matrix(1,0,0,1,100,150)"
|
||||
>
|
||||
<line
|
||||
id="key"
|
||||
fill="none"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="200"
|
||||
y2="50"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
<g
|
||||
stroke-width="2px"
|
||||
stroke-dasharray="0px,0px"
|
||||
transform="matrix(0.970143,0.242536,-0.242536,0.970143,0,0)"
|
||||
>
|
||||
<path
|
||||
id="g-svg-8"
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 A 5 5 0 1 0 10 5 A 5 5 0 1 0 0 5 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke="none"
|
||||
width="10px"
|
||||
height="10px"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
stroke-width="2px"
|
||||
stroke-dasharray="0px,0px"
|
||||
transform="matrix(-0.970143,-0.242536,0.242536,-0.970143,200,50)"
|
||||
>
|
||||
<path
|
||||
id="g-svg-10"
|
||||
fill="rgba(255,0,0,1)"
|
||||
d="M 0,5 L 10,0 L 10,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke="none"
|
||||
width="10px"
|
||||
height="10px"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="label"
|
||||
fill="rgba(0,0,0,1)"
|
||||
stroke="none"
|
||||
font-size="12px"
|
||||
text-anchor="middle"
|
||||
transform="matrix(0.970143,0.242536,-0.242536,0.970143,205.335785,170.149292)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,-33.187069,-28.430592)">
|
||||
<path
|
||||
id="background"
|
||||
fill="none"
|
||||
d="M 0,0 l 68.37411720861238,0 l 0,50.86117678317855 l-68.37411720861238 0 z"
|
||||
stroke="none"
|
||||
width="68.37411720861238px"
|
||||
height="50.86117678317855px"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
font-size="12px"
|
||||
text-anchor="middle"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<text
|
||||
id="text"
|
||||
fill="rgba(0,0,0,1)"
|
||||
dominant-baseline="alphabetic"
|
||||
paint-order="stroke"
|
||||
dx="1"
|
||||
stroke="none"
|
||||
>
|
||||
line-edge
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.5 KiB |
@ -0,0 +1,97 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="500"
|
||||
height="500"
|
||||
style="background: transparent; position: absolute; outline: none;"
|
||||
color-interpolation-filters="sRGB"
|
||||
tabindex="1"
|
||||
>
|
||||
<defs />
|
||||
<g id="g-svg-camera" transform="matrix(1,0,0,1,0,0)">
|
||||
<g id="g-root" fill="none" transform="matrix(1,0,0,1,0,0)">
|
||||
<g
|
||||
id="g-svg-5"
|
||||
fill="none"
|
||||
marker-start="true"
|
||||
marker-end="true"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,100,50)">
|
||||
<line
|
||||
id="halo"
|
||||
fill="none"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="200"
|
||||
y2="150"
|
||||
stroke-width="12"
|
||||
stroke-dasharray="0,0"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
pointer-events="none"
|
||||
opacity="0"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,100,50)">
|
||||
<line
|
||||
id="key"
|
||||
fill="none"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="200"
|
||||
y2="150"
|
||||
stroke-width="2"
|
||||
stroke-dasharray="10,10"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
<g transform="matrix(0.800000,0.600000,-0.600000,0.800000,0,0)">
|
||||
<path
|
||||
id="g-svg-8"
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 A 5 5 0 1 0 10 5 A 5 5 0 1 0 0 5 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke-width="2"
|
||||
stroke-dasharray="0,0"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(-0.800000,-0.600000,0.600000,-0.800000,200,150)">
|
||||
<path
|
||||
id="g-svg-10"
|
||||
fill="rgba(255,0,0,1)"
|
||||
d="M 0,5 L 10,0 L 10,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke-width="2"
|
||||
stroke-dasharray="0,0"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="label" fill="none" transform="matrix(1,0,0,1,204,44)">
|
||||
<g transform="matrix(1,0,0,1,-27.540001,-23)">
|
||||
<path
|
||||
id="background"
|
||||
fill="none"
|
||||
d="M 0,0 l 56.080000000000005,0 l 0,23 l-56.080000000000005 0 z"
|
||||
width="56.080000000000005"
|
||||
height="23"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,0)">
|
||||
<text
|
||||
id="text"
|
||||
fill="rgba(0,0,0,1)"
|
||||
dominant-baseline="central"
|
||||
paint-order="stroke"
|
||||
dx="0.5"
|
||||
dy="-11.5px"
|
||||
text-anchor="middle"
|
||||
font-size="12"
|
||||
>
|
||||
line-edge
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
@ -1,135 +0,0 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="500"
|
||||
height="500"
|
||||
style="background: transparent; position: absolute; outline: none;"
|
||||
color-interpolation-filters="sRGB"
|
||||
tabindex="1"
|
||||
>
|
||||
<defs />
|
||||
<g id="g-svg-camera" transform="matrix(1,0,0,1,0,0)">
|
||||
<g
|
||||
id="g-root"
|
||||
fill="none"
|
||||
stroke="none"
|
||||
visibility="visible"
|
||||
font-size="16px"
|
||||
font-family="sans-serif"
|
||||
font-style="normal"
|
||||
font-weight="normal"
|
||||
font-variant="normal"
|
||||
text-anchor="left"
|
||||
stroke-dashoffset="0px"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g
|
||||
id="g-svg-5"
|
||||
fill="none"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
stroke-width="2px"
|
||||
marker-start="true"
|
||||
marker-end="true"
|
||||
stroke-dasharray="10px,10px"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g
|
||||
opacity="0.25"
|
||||
pointer-events="none"
|
||||
stroke-width="12px"
|
||||
stroke-dasharray="0px,0px"
|
||||
transform="matrix(1,0,0,1,100,150)"
|
||||
>
|
||||
<line
|
||||
id="halo"
|
||||
fill="none"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="350"
|
||||
y2="200"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
stroke-width="2px"
|
||||
stroke-dasharray="10px,10px"
|
||||
transform="matrix(1,0,0,1,100,150)"
|
||||
>
|
||||
<line
|
||||
id="key"
|
||||
fill="none"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="350"
|
||||
y2="200"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
<g
|
||||
stroke-width="2px"
|
||||
stroke-dasharray="0px,0px"
|
||||
transform="matrix(0.868243,0.496139,-0.496139,0.868243,0,0)"
|
||||
>
|
||||
<path
|
||||
id="g-svg-8"
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 A 5 5 0 1 0 10 5 A 5 5 0 1 0 0 5 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke="none"
|
||||
width="10px"
|
||||
height="10px"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
stroke-width="2px"
|
||||
stroke-dasharray="0px,0px"
|
||||
transform="matrix(-0.868243,-0.496139,0.496139,-0.868243,350,200)"
|
||||
>
|
||||
<path
|
||||
id="g-svg-10"
|
||||
fill="rgba(255,0,0,1)"
|
||||
d="M 0,5 L 10,0 L 10,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke="none"
|
||||
width="10px"
|
||||
height="10px"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="label"
|
||||
fill="rgba(0,0,0,1)"
|
||||
stroke="none"
|
||||
font-size="12px"
|
||||
text-anchor="middle"
|
||||
transform="matrix(0.970143,0.242536,-0.242536,0.970143,205.335785,170.149292)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,-33.187069,-28.430592)">
|
||||
<path
|
||||
id="background"
|
||||
fill="none"
|
||||
d="M 0,0 l 68.37411720861238,0 l 0,50.86117678317855 l-68.37411720861238 0 z"
|
||||
stroke="none"
|
||||
width="68.37411720861238px"
|
||||
height="50.86117678317855px"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
font-size="12px"
|
||||
text-anchor="middle"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<text
|
||||
id="text"
|
||||
fill="rgba(0,0,0,1)"
|
||||
dominant-baseline="alphabetic"
|
||||
paint-order="stroke"
|
||||
dx="1"
|
||||
stroke="none"
|
||||
>
|
||||
line-edge
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.5 KiB |
@ -0,0 +1,97 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="500"
|
||||
height="500"
|
||||
style="background: transparent; position: absolute; outline: none;"
|
||||
color-interpolation-filters="sRGB"
|
||||
tabindex="1"
|
||||
>
|
||||
<defs />
|
||||
<g id="g-svg-camera" transform="matrix(1,0,0,1,0,0)">
|
||||
<g id="g-root" fill="none" transform="matrix(1,0,0,1,0,0)">
|
||||
<g
|
||||
id="g-svg-5"
|
||||
fill="none"
|
||||
marker-start="true"
|
||||
marker-end="true"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,100,50)">
|
||||
<line
|
||||
id="halo"
|
||||
fill="none"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="350"
|
||||
y2="300"
|
||||
stroke-width="12"
|
||||
stroke-dasharray="0,0"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
pointer-events="none"
|
||||
opacity="0.25"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,100,50)">
|
||||
<line
|
||||
id="key"
|
||||
fill="none"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="350"
|
||||
y2="300"
|
||||
stroke-width="2"
|
||||
stroke-dasharray="10,10"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
<g transform="matrix(0.759257,0.650791,-0.650791,0.759257,0,0)">
|
||||
<path
|
||||
id="g-svg-8"
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 A 5 5 0 1 0 10 5 A 5 5 0 1 0 0 5 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke-width="2"
|
||||
stroke-dasharray="0,0"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(-0.759257,-0.650791,0.650791,-0.759257,350,300)">
|
||||
<path
|
||||
id="g-svg-10"
|
||||
fill="rgba(255,0,0,1)"
|
||||
d="M 0,5 L 10,0 L 10,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke-width="2"
|
||||
stroke-dasharray="0,0"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="label" fill="none" transform="matrix(1,0,0,1,204,44)">
|
||||
<g transform="matrix(1,0,0,1,-27.540001,-23)">
|
||||
<path
|
||||
id="background"
|
||||
fill="none"
|
||||
d="M 0,0 l 56.080000000000005,0 l 0,23 l-56.080000000000005 0 z"
|
||||
width="56.080000000000005"
|
||||
height="23"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,0)">
|
||||
<text
|
||||
id="text"
|
||||
fill="rgba(0,0,0,1)"
|
||||
dominant-baseline="central"
|
||||
paint-order="stroke"
|
||||
dx="0.5"
|
||||
dy="-11.5px"
|
||||
text-anchor="middle"
|
||||
font-size="12"
|
||||
>
|
||||
line-edge
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
@ -0,0 +1,97 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="500"
|
||||
height="500"
|
||||
style="background: transparent; position: absolute; outline: none;"
|
||||
color-interpolation-filters="sRGB"
|
||||
tabindex="1"
|
||||
>
|
||||
<defs />
|
||||
<g id="g-svg-camera" transform="matrix(1,0,0,1,0,0)">
|
||||
<g id="g-root" fill="none" transform="matrix(1,0,0,1,0,0)">
|
||||
<g
|
||||
id="g-svg-5"
|
||||
fill="none"
|
||||
marker-start="true"
|
||||
marker-end="true"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,100,50)">
|
||||
<line
|
||||
id="halo"
|
||||
fill="none"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="275"
|
||||
y2="225"
|
||||
stroke-width="12"
|
||||
stroke-dasharray="0,0"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
pointer-events="none"
|
||||
opacity="0.125"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,100,50)">
|
||||
<line
|
||||
id="key"
|
||||
fill="none"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="275"
|
||||
y2="225"
|
||||
stroke-width="2"
|
||||
stroke-dasharray="10,10"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
<g transform="matrix(0.773957,0.633238,-0.633238,0.773957,0,0)">
|
||||
<path
|
||||
id="g-svg-8"
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 A 5 5 0 1 0 10 5 A 5 5 0 1 0 0 5 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke-width="2"
|
||||
stroke-dasharray="0,0"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(-0.773957,-0.633238,0.633238,-0.773957,275,225)">
|
||||
<path
|
||||
id="g-svg-10"
|
||||
fill="rgba(255,0,0,1)"
|
||||
d="M 0,5 L 10,0 L 10,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke-width="2"
|
||||
stroke-dasharray="0,0"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="label" fill="none" transform="matrix(1,0,0,1,204,44)">
|
||||
<g transform="matrix(1,0,0,1,-27.540001,-23)">
|
||||
<path
|
||||
id="background"
|
||||
fill="none"
|
||||
d="M 0,0 l 56.080000000000005,0 l 0,23 l-56.080000000000005 0 z"
|
||||
width="56.080000000000005"
|
||||
height="23"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,0)">
|
||||
<text
|
||||
id="text"
|
||||
fill="rgba(0,0,0,1)"
|
||||
dominant-baseline="central"
|
||||
paint-order="stroke"
|
||||
dx="0.5"
|
||||
dy="-11.5px"
|
||||
text-anchor="middle"
|
||||
font-size="12"
|
||||
>
|
||||
line-edge
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
@ -0,0 +1,71 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="500"
|
||||
height="500"
|
||||
style="background: transparent; position: absolute; outline: none;"
|
||||
color-interpolation-filters="sRGB"
|
||||
tabindex="1"
|
||||
>
|
||||
<defs />
|
||||
<g id="g-svg-camera" transform="matrix(1,0,0,1,0,0)">
|
||||
<g id="g-root" fill="none" transform="matrix(1,0,0,1,0,0)">
|
||||
<g
|
||||
id="g-svg-5"
|
||||
fill="none"
|
||||
marker-start="false"
|
||||
marker-end="true"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,100,149.710602)">
|
||||
<path
|
||||
id="key"
|
||||
fill="none"
|
||||
d="M 0,0.2893917355592919 Q 92.72393124891002 -3.8148832688006564,200 50.28939173555929"
|
||||
stroke-width="2"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
<g transform="matrix(-0.892870,-0.450315,0.450315,-0.892870,200,50.289391)">
|
||||
<path
|
||||
id="g-svg-8"
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 L 10,0 L 10,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke-width="2"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
stroke-dasharray="0,0"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="label"
|
||||
fill="none"
|
||||
transform="matrix(0.999550,0.029986,-0.029986,0.999550,204.178116,29.122644)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,-50.449379,-30.713144)">
|
||||
<path
|
||||
id="background"
|
||||
fill="none"
|
||||
d="M 0,0 l 101.89874994810936,0 l 0,38.42628857535926 l-101.89874994810936 0 z"
|
||||
width="101.89874994810936"
|
||||
height="38.42628857535926"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,0)">
|
||||
<text
|
||||
id="text"
|
||||
fill="rgba(0,0,0,1)"
|
||||
dominant-baseline="central"
|
||||
paint-order="stroke"
|
||||
dx="0.5"
|
||||
dy="-11.5px"
|
||||
text-anchor="middle"
|
||||
font-size="12"
|
||||
>
|
||||
quadratic-edge
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
@ -0,0 +1,71 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="500"
|
||||
height="500"
|
||||
style="background: transparent; position: absolute; outline: none;"
|
||||
color-interpolation-filters="sRGB"
|
||||
tabindex="1"
|
||||
>
|
||||
<defs />
|
||||
<g id="g-svg-camera" transform="matrix(1,0,0,1,0,0)">
|
||||
<g id="g-root" fill="none" transform="matrix(1,0,0,1,0,0)">
|
||||
<g
|
||||
id="g-svg-5"
|
||||
fill="none"
|
||||
marker-start="false"
|
||||
marker-end="true"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,100,150)">
|
||||
<path
|
||||
id="key"
|
||||
fill="none"
|
||||
d="M 0,0 Q 160.11583184929498 73.95270573626621,350 200"
|
||||
stroke-width="10"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
<g transform="matrix(-0.833147,-0.553052,0.553052,-0.833147,350,200)">
|
||||
<path
|
||||
id="g-svg-8"
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 L 10,0 L 10,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke-width="2"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
stroke-dasharray="0,0"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="label"
|
||||
fill="none"
|
||||
transform="matrix(0.999550,0.029986,-0.029986,0.999550,204.178116,29.122644)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,-50.449379,-30.713144)">
|
||||
<path
|
||||
id="background"
|
||||
fill="none"
|
||||
d="M 0,0 l 101.89874994810936,0 l 0,38.42628857535926 l-101.89874994810936 0 z"
|
||||
width="101.89874994810936"
|
||||
height="38.42628857535926"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,0)">
|
||||
<text
|
||||
id="text"
|
||||
fill="rgba(0,0,0,1)"
|
||||
dominant-baseline="central"
|
||||
paint-order="stroke"
|
||||
dx="0.5"
|
||||
dy="-11.5px"
|
||||
text-anchor="middle"
|
||||
font-size="12"
|
||||
>
|
||||
quadratic-edge
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
@ -0,0 +1,71 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="500"
|
||||
height="500"
|
||||
style="background: transparent; position: absolute; outline: none;"
|
||||
color-interpolation-filters="sRGB"
|
||||
tabindex="1"
|
||||
>
|
||||
<defs />
|
||||
<g id="g-svg-camera" transform="matrix(1,0,0,1,0,0)">
|
||||
<g id="g-root" fill="none" transform="matrix(1,0,0,1,0,0)">
|
||||
<g
|
||||
id="g-svg-5"
|
||||
fill="none"
|
||||
marker-start="false"
|
||||
marker-end="true"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,100,150)">
|
||||
<path
|
||||
id="key"
|
||||
fill="none"
|
||||
d="M 0,0 C 84.27992103273499 23.282810243968754,175.94658769940168 64.94947691063538,275 125"
|
||||
stroke-width="6"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
<g transform="matrix(-0.855128,-0.518416,0.518416,-0.855128,275,125)">
|
||||
<path
|
||||
id="g-svg-8"
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 L 10,0 L 10,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke-width="2"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
stroke-dasharray="0,0"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="label"
|
||||
fill="none"
|
||||
transform="matrix(0.999550,0.029986,-0.029986,0.999550,204.178116,29.122644)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,-50.449379,-30.713144)">
|
||||
<path
|
||||
id="background"
|
||||
fill="none"
|
||||
d="M 0,0 l 101.89874994810936,0 l 0,38.42628857535926 l-101.89874994810936 0 z"
|
||||
width="101.89874994810936"
|
||||
height="38.42628857535926"
|
||||
/>
|
||||
</g>
|
||||
<g transform="matrix(1,0,0,1,0,0)">
|
||||
<text
|
||||
id="text"
|
||||
fill="rgba(0,0,0,1)"
|
||||
dominant-baseline="central"
|
||||
paint-order="stroke"
|
||||
dx="0.5"
|
||||
dy="-11.5px"
|
||||
text-anchor="middle"
|
||||
font-size="12"
|
||||
>
|
||||
quadratic-edge
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
@ -51,9 +51,7 @@
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 L 5,0 L 10,5 L 5,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke="none"
|
||||
width="10px"
|
||||
height="10px"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
@ -144,9 +142,7 @@
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 A 5 5 0 1 0 10 5 A 5 5 0 1 0 0 5 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke="none"
|
||||
width="10px"
|
||||
height="10px"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
@ -159,9 +155,7 @@
|
||||
fill="rgba(255,0,0,1)"
|
||||
d="M 0,5 L 10,0 L 10,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke="none"
|
||||
width="10px"
|
||||
height="10px"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
@ -254,10 +248,7 @@
|
||||
x="0"
|
||||
y="0"
|
||||
href="https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*N4ZMS7gHsUIAAAAAAAAAAABkARQnAQ"
|
||||
transform="translate(-25,-25)"
|
||||
stroke="none"
|
||||
width="50px"
|
||||
height="50px"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
@ -273,8 +264,6 @@
|
||||
cy="25"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
r="25px"
|
||||
width="10px"
|
||||
height="10px"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.0 KiB |
@ -0,0 +1,305 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="500"
|
||||
height="500"
|
||||
style="background: transparent; position: absolute; outline: none;"
|
||||
color-interpolation-filters="sRGB"
|
||||
tabindex="1"
|
||||
>
|
||||
<defs />
|
||||
<g id="g-svg-camera" transform="matrix(1,0,0,1,0,0)">
|
||||
<g
|
||||
id="g-root"
|
||||
fill="none"
|
||||
stroke="none"
|
||||
visibility="visible"
|
||||
font-size="16px"
|
||||
font-family="sans-serif"
|
||||
font-style="normal"
|
||||
font-weight="normal"
|
||||
font-variant="normal"
|
||||
text-anchor="left"
|
||||
stroke-dashoffset="0px"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g
|
||||
id="g-svg-5"
|
||||
fill="none"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
stroke-width="2px"
|
||||
marker-start="false"
|
||||
marker-end="true"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g
|
||||
opacity="0.25"
|
||||
pointer-events="none"
|
||||
stroke-width="12px"
|
||||
stroke-dasharray="0px,0px"
|
||||
transform="matrix(1,0,0,1,100,35)"
|
||||
>
|
||||
<path
|
||||
id="halo"
|
||||
fill="none"
|
||||
d="M 0,15 Q 100 -15,200 15"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
<g stroke-width="2px" transform="matrix(1,0,0,1,100,35)">
|
||||
<path
|
||||
id="key"
|
||||
fill="none"
|
||||
d="M 0,15 Q 100 -15,200 15"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
<g
|
||||
stroke-width="2px"
|
||||
stroke-dasharray="0px,0px"
|
||||
transform="matrix(-0.957826,-0.287348,0.287348,-0.957826,200,15)"
|
||||
>
|
||||
<path
|
||||
id="g-svg-8"
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 L 10,0 L 10,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="label"
|
||||
fill="none"
|
||||
stroke="none"
|
||||
font-size="12px"
|
||||
text-anchor="middle"
|
||||
transform="matrix(0.999550,0.029986,-0.029986,0.999550,204.178116,29.122644)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,-55.159351,-23.023664)">
|
||||
<path
|
||||
id="background"
|
||||
fill="none"
|
||||
d="M 0,0 l 112.31869543715979,0 l 0,40.047326504443134 l-112.31869543715979 0 z"
|
||||
stroke="none"
|
||||
width="112.31869543715979px"
|
||||
height="40.047326504443134px"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
font-size="12px"
|
||||
text-anchor="middle"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<text
|
||||
id="text"
|
||||
fill="none"
|
||||
dominant-baseline="alphabetic"
|
||||
paint-order="stroke"
|
||||
dx="1"
|
||||
stroke="none"
|
||||
>
|
||||
default quadratic
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g-svg-13"
|
||||
fill="none"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
stroke-width="2px"
|
||||
marker-start="false"
|
||||
marker-end="true"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g stroke-width="2px" transform="matrix(1,0,0,1,100,150)">
|
||||
<path
|
||||
id="key"
|
||||
fill="none"
|
||||
d="M 0,0 Q 100 50,200 0"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
<g
|
||||
stroke-width="2px"
|
||||
stroke-dasharray="0px,0px"
|
||||
transform="matrix(-0.894427,0.447214,-0.447214,-0.894427,200,0)"
|
||||
>
|
||||
<path
|
||||
id="g-svg-16"
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 L 10,0 L 10,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="label"
|
||||
fill="none"
|
||||
stroke="none"
|
||||
font-size="12px"
|
||||
text-anchor="middle"
|
||||
transform="matrix(0.998752,-0.049935,0.049935,0.998752,203.695404,168.807739)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,-85.936951,-28.053503)">
|
||||
<path
|
||||
id="background"
|
||||
fill="none"
|
||||
d="M 0,0 l 173.87391428120713,0 l 0,50.1070253812409 l-173.87391428120713 0 z"
|
||||
stroke="none"
|
||||
width="173.87391428120713px"
|
||||
height="50.1070253812409px"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
font-size="12px"
|
||||
text-anchor="middle"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<text
|
||||
id="text"
|
||||
fill="none"
|
||||
dominant-baseline="alphabetic"
|
||||
paint-order="stroke"
|
||||
dx="1"
|
||||
stroke="none"
|
||||
>
|
||||
controlPoint=[200, 200]
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g-svg-20"
|
||||
fill="none"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
stroke-width="2px"
|
||||
marker-start="false"
|
||||
marker-end="true"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g stroke-width="2px" transform="matrix(1,0,0,1,100,225)">
|
||||
<path
|
||||
id="key"
|
||||
fill="none"
|
||||
d="M 0,25 Q 100 -25,200 25"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
<g
|
||||
stroke-width="2px"
|
||||
stroke-dasharray="0px,0px"
|
||||
transform="matrix(-0.894427,-0.447214,0.447214,-0.894427,200,25)"
|
||||
>
|
||||
<path
|
||||
id="g-svg-23"
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 L 10,0 L 10,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="label"
|
||||
fill="none"
|
||||
stroke="none"
|
||||
font-size="12px"
|
||||
text-anchor="middle"
|
||||
transform="matrix(0.998752,0.049935,-0.049935,0.998752,204.294617,219.207230)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,-108.496948,-30.303787)">
|
||||
<path
|
||||
id="background"
|
||||
fill="none"
|
||||
d="M 0,0 l 218.99391546491714,0 l 0,54.60757626551481 l-218.99391546491714 0 z"
|
||||
stroke="none"
|
||||
width="218.99391546491714px"
|
||||
height="54.60757626551481px"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
font-size="12px"
|
||||
text-anchor="middle"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<text
|
||||
id="text"
|
||||
fill="none"
|
||||
dominant-baseline="alphabetic"
|
||||
paint-order="stroke"
|
||||
dx="1"
|
||||
stroke="none"
|
||||
>
|
||||
curveOffset=50, curvePosition:0.5
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g-svg-27"
|
||||
fill="none"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
stroke-width="2px"
|
||||
marker-start="false"
|
||||
marker-end="true"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<g stroke-width="2px" transform="matrix(1,0,0,1,100,325)">
|
||||
<path
|
||||
id="key"
|
||||
fill="none"
|
||||
d="M 0,25 Q 50 -25,200 25"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
<g
|
||||
stroke-width="2px"
|
||||
stroke-dasharray="0px,0px"
|
||||
transform="matrix(-0.948683,-0.316228,0.316228,-0.948683,200,25)"
|
||||
>
|
||||
<path
|
||||
id="g-svg-30"
|
||||
fill="rgba(24,144,255,1)"
|
||||
d="M 0,5 L 10,0 L 10,10 Z"
|
||||
transform="translate(-5,-5)"
|
||||
stroke="rgba(24,144,255,1)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="label"
|
||||
fill="none"
|
||||
stroke="none"
|
||||
font-size="12px"
|
||||
text-anchor="middle"
|
||||
transform="matrix(0.991600,0.129341,-0.129341,0.991600,203.144791,320.881134)"
|
||||
>
|
||||
<g transform="matrix(1,0,0,1,-114.098114,-47.451683)">
|
||||
<path
|
||||
id="background"
|
||||
fill="none"
|
||||
d="M 0,0 l 230.1962301306265,0 l 0,88.90336656842001 l-230.1962301306265 0 z"
|
||||
stroke="none"
|
||||
width="230.1962301306265px"
|
||||
height="88.90336656842001px"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
font-size="12px"
|
||||
text-anchor="middle"
|
||||
transform="matrix(1,0,0,1,0,0)"
|
||||
>
|
||||
<text
|
||||
id="text"
|
||||
fill="none"
|
||||
dominant-baseline="alphabetic"
|
||||
paint-order="stroke"
|
||||
dx="1"
|
||||
stroke="none"
|
||||
>
|
||||
curveOffset=50, curvePosition:0.25
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.4 KiB |
@ -1,81 +1,110 @@
|
||||
import { Line } from '@antv/g';
|
||||
import { getLabelPositionStyle } from '../../../src/utils/edge';
|
||||
import { Point } from '../../../src/types';
|
||||
import { getLabelPositionStyle, getQuadraticPath } from '../../../src/utils/edge';
|
||||
|
||||
describe('edge', () => {
|
||||
// horizontal line
|
||||
const line = new Line({
|
||||
style: {
|
||||
x1: 0,
|
||||
y1: 100,
|
||||
x2: 100,
|
||||
y2: 100,
|
||||
},
|
||||
describe('getLabelPositionStyle', () => {
|
||||
it('should return correctly label position style', () => {
|
||||
// horizontal line
|
||||
const line = new Line({
|
||||
style: {
|
||||
x1: 0,
|
||||
y1: 100,
|
||||
x2: 100,
|
||||
y2: 100,
|
||||
},
|
||||
});
|
||||
|
||||
// with rotation angle below Math.PI
|
||||
const line1 = new Line({
|
||||
style: {
|
||||
x1: 0,
|
||||
y1: 100,
|
||||
x2: 100,
|
||||
y2: 200,
|
||||
},
|
||||
});
|
||||
|
||||
// with rotation angle over Math.PI
|
||||
const line2 = new Line({
|
||||
style: {
|
||||
x1: 0,
|
||||
y1: 200,
|
||||
x2: 100,
|
||||
y2: 100,
|
||||
},
|
||||
});
|
||||
|
||||
const labelPosition = getLabelPositionStyle(line, 'center', false);
|
||||
expect(labelPosition.textAlign).toEqual('center');
|
||||
expect(labelPosition.x).toEqual(50);
|
||||
expect(labelPosition.y).toEqual(100);
|
||||
|
||||
const labelPosition2 = getLabelPositionStyle(line, 'center', true, 5, 5);
|
||||
expect(labelPosition2.textAlign).toEqual('center');
|
||||
expect(labelPosition2.x).toEqual(55);
|
||||
expect(labelPosition2.y).toEqual(105);
|
||||
|
||||
const labelPosition3 = getLabelPositionStyle(line, 'start', true, 5, 5);
|
||||
expect(labelPosition3.textAlign).toEqual('left');
|
||||
expect(labelPosition3.x).toEqual(5);
|
||||
expect(labelPosition3.y).toEqual(105);
|
||||
|
||||
const labelPosition4 = getLabelPositionStyle(line, 'end', true, 5, 5);
|
||||
expect(labelPosition4.textAlign).toEqual('right');
|
||||
expect(labelPosition4.x).toBeCloseTo(100 * 0.99 + 5);
|
||||
expect(labelPosition4.y).toEqual(105);
|
||||
|
||||
const labelPosition5 = getLabelPositionStyle(line, 0.5, true, 5, 5);
|
||||
expect(labelPosition5.textAlign).toEqual('center');
|
||||
expect(labelPosition5.x).toEqual(55);
|
||||
expect(labelPosition5.y).toEqual(105);
|
||||
|
||||
// with rotation angle below Math.PI
|
||||
const labelPosition6 = getLabelPositionStyle(line1, 'center', true, 5, 5);
|
||||
expect(labelPosition6.textAlign).toEqual('center');
|
||||
expect(labelPosition6.transform).toEqual('rotate(45deg)');
|
||||
expect(labelPosition6.x).toEqual(50 + 5 * Math.cos(Math.PI / 4) - 5 * Math.sin(Math.PI / 4));
|
||||
expect(labelPosition6.y).toEqual(150 + 5 * Math.sin(Math.PI / 4) + 5 * Math.cos(Math.PI / 4));
|
||||
|
||||
const labelPosition7 = getLabelPositionStyle(line1, 'start', true, 5, 5);
|
||||
expect(labelPosition7.textAlign).toEqual('left');
|
||||
|
||||
const labelPosition8 = getLabelPositionStyle(line1, 'end', true, 5, 5);
|
||||
expect(labelPosition8.textAlign).toEqual('right');
|
||||
|
||||
// with rotation angle over Math.PI
|
||||
const labelPosition9 = getLabelPositionStyle(line2, 'center', true, 5, 5);
|
||||
expect(labelPosition9.textAlign).toEqual('center');
|
||||
expect(labelPosition9.transform).toEqual('rotate(-45deg)');
|
||||
expect(labelPosition9.x).toEqual(50 + 5 * Math.cos(-Math.PI / 4) - 5 * Math.sin(-Math.PI / 4));
|
||||
expect(labelPosition9.y).toEqual(150 + 5 * Math.sin(-Math.PI / 4) + 5 * Math.cos(-Math.PI / 4));
|
||||
});
|
||||
});
|
||||
|
||||
// with rotation angle below Math.PI
|
||||
const line1 = new Line({
|
||||
style: {
|
||||
x1: 0,
|
||||
y1: 100,
|
||||
x2: 100,
|
||||
y2: 200,
|
||||
},
|
||||
});
|
||||
describe('getQuadraticPath', () => {
|
||||
const sourcePoint: Point = [0, 10];
|
||||
const targetPoint: Point = [10, 10];
|
||||
const curvePosition = 0.5;
|
||||
const curveOffset = 5;
|
||||
const controlPoint: Point = [100, 100];
|
||||
|
||||
// with rotation angle over Math.PI
|
||||
const line2 = new Line({
|
||||
style: {
|
||||
x1: 0,
|
||||
y1: 200,
|
||||
x2: 100,
|
||||
y2: 100,
|
||||
},
|
||||
});
|
||||
it('should return the correct path for given source and target points with a control point', () => {
|
||||
const path = getQuadraticPath(sourcePoint, targetPoint, curvePosition, curveOffset, controlPoint);
|
||||
|
||||
it('getLabelPositionStyle', () => {
|
||||
const labelPosition = getLabelPositionStyle(line, 'center', false);
|
||||
expect(labelPosition.textAlign).toEqual('center');
|
||||
expect(labelPosition.x).toEqual(50);
|
||||
expect(labelPosition.y).toEqual(100);
|
||||
expect(path).toEqual([
|
||||
['M', 0, 10],
|
||||
['Q', 100, 100, 10, 10],
|
||||
]);
|
||||
});
|
||||
|
||||
const labelPosition2 = getLabelPositionStyle(line, 'center', true, 5, 5);
|
||||
expect(labelPosition2.textAlign).toEqual('center');
|
||||
expect(labelPosition2.x).toEqual(55);
|
||||
expect(labelPosition2.y).toEqual(105);
|
||||
it('should return the correct path for given source and target points without a control point', () => {
|
||||
const path = getQuadraticPath(sourcePoint, targetPoint, curvePosition, curveOffset);
|
||||
|
||||
const labelPosition3 = getLabelPositionStyle(line, 'start', true, 5, 5);
|
||||
expect(labelPosition3.textAlign).toEqual('left');
|
||||
expect(labelPosition3.x).toEqual(5);
|
||||
expect(labelPosition3.y).toEqual(105);
|
||||
|
||||
const labelPosition4 = getLabelPositionStyle(line, 'end', true, 5, 5);
|
||||
expect(labelPosition4.textAlign).toEqual('right');
|
||||
expect(labelPosition4.x).toBeCloseTo(100 * 0.99 + 5);
|
||||
expect(labelPosition4.y).toEqual(105);
|
||||
|
||||
const labelPosition5 = getLabelPositionStyle(line, 0.5, true, 5, 5);
|
||||
expect(labelPosition5.textAlign).toEqual('center');
|
||||
expect(labelPosition5.x).toEqual(55);
|
||||
expect(labelPosition5.y).toEqual(105);
|
||||
|
||||
// with rotation angle below Math.PI
|
||||
const labelPosition6 = getLabelPositionStyle(line1, 'center', true, 5, 5);
|
||||
expect(labelPosition6.textAlign).toEqual('center');
|
||||
expect(labelPosition6.transform).toEqual('rotate(45deg)');
|
||||
expect(labelPosition6.x).toEqual(50 + 5 * Math.cos(Math.PI / 4) - 5 * Math.sin(Math.PI / 4));
|
||||
expect(labelPosition6.y).toEqual(150 + 5 * Math.sin(Math.PI / 4) + 5 * Math.cos(Math.PI / 4));
|
||||
|
||||
const labelPosition7 = getLabelPositionStyle(line1, 'start', true, 5, 5);
|
||||
expect(labelPosition7.textAlign).toEqual('left');
|
||||
|
||||
const labelPosition8 = getLabelPositionStyle(line1, 'end', true, 5, 5);
|
||||
expect(labelPosition8.textAlign).toEqual('right');
|
||||
|
||||
// with rotation angle over Math.PI
|
||||
const labelPosition9 = getLabelPositionStyle(line2, 'center', true, 5, 5);
|
||||
expect(labelPosition9.textAlign).toEqual('center');
|
||||
expect(labelPosition9.transform).toEqual('rotate(-45deg)');
|
||||
expect(labelPosition9.x).toEqual(50 + 5 * Math.cos(-Math.PI / 4) - 5 * Math.sin(-Math.PI / 4));
|
||||
expect(labelPosition9.y).toEqual(150 + 5 * Math.sin(-Math.PI / 4) + 5 * Math.cos(-Math.PI / 4));
|
||||
expect(path).toEqual([
|
||||
['M', 0, 10],
|
||||
['Q', 5, 5, 10, 10],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
31
packages/g6/__tests__/unit/utils/vector.spec.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { add, distance, divide, multiply, normalize, perpendicular, subtract } from '../../../src/utils/vector';
|
||||
|
||||
describe('Vector Functions', () => {
|
||||
it('add', () => {
|
||||
expect(add([0, 1], [2, 3])).toEqual([2, 4]);
|
||||
});
|
||||
|
||||
it('subtract', () => {
|
||||
expect(subtract([0, 1], [2, 3])).toEqual([-2, -2]);
|
||||
});
|
||||
|
||||
it('multiply', () => {
|
||||
expect(multiply([0, 1], [2, 3])).toEqual([0, 3]);
|
||||
});
|
||||
|
||||
it('divide', () => {
|
||||
expect(divide([0, 1], [2, 3])).toEqual([0, 1 / 3]);
|
||||
});
|
||||
|
||||
it('distance', () => {
|
||||
expect(distance([0, 0], [3, 4])).toEqual(5);
|
||||
});
|
||||
|
||||
it('normalize', () => {
|
||||
expect(normalize([3, 4])).toEqual([0.6, 0.8]);
|
||||
});
|
||||
|
||||
it('perpendicular', () => {
|
||||
expect(perpendicular([1, 0])).toEqual([-0, -1]);
|
||||
});
|
||||
});
|
@ -8,7 +8,7 @@ import type {
|
||||
} from '@antv/g';
|
||||
import { Path } from '@antv/g';
|
||||
import { deepMix, isFunction } from '@antv/util';
|
||||
import type { Point, PrefixObject } from '../../types';
|
||||
import type { PrefixObject } from '../../types';
|
||||
import type { EdgeKey, EdgeLabelStyleProps } from '../../types/edge';
|
||||
import { getLabelPositionStyle } from '../../utils/edge';
|
||||
import { omitStyleProps, subStyleProps } from '../../utils/prefix';
|
||||
@ -31,8 +31,6 @@ type EdgeArrowStyleProps = {
|
||||
|
||||
export type BaseEdgeStyleProps<KT extends object> = BaseShapeStyleProps &
|
||||
KT & {
|
||||
sourcePoint?: Point;
|
||||
targetPoint?: Point;
|
||||
label?: boolean;
|
||||
halo?: boolean;
|
||||
startArrow?: boolean;
|
||||
@ -128,7 +126,7 @@ export abstract class BaseEdge<KT extends object, KS extends DisplayObject> exte
|
||||
}
|
||||
|
||||
private getArrowStyle(attributes: ParsedBaseEdgeStyleProps<KT>, isStart: boolean) {
|
||||
const { stroke, ...keyStyle } = this.getKeyStyle(attributes) as BaseStyleProps;
|
||||
const keyStyle = this.getKeyStyle(attributes) as BaseStyleProps;
|
||||
const arrowType = isStart ? 'startArrow' : 'endArrow';
|
||||
const { width, height, type, ctor, ...arrowStyle } = subStyleProps<Required<EdgeArrowStyleProps>>(
|
||||
this.getGraphicStyle(attributes),
|
||||
@ -140,12 +138,9 @@ export abstract class BaseEdge<KT extends object, KS extends DisplayObject> exte
|
||||
const arrowFn = isFunction(type) ? type : Symbol[type] || Symbol.triangle;
|
||||
path = arrowFn(width, height);
|
||||
}
|
||||
|
||||
return {
|
||||
...keyStyle,
|
||||
...(path && { path, fill: type === 'simple' ? '' : stroke }),
|
||||
width,
|
||||
height,
|
||||
...(path && { path, fill: type === 'simple' ? '' : keyStyle.stroke }),
|
||||
...arrowStyle,
|
||||
};
|
||||
}
|
||||
@ -182,6 +177,8 @@ export abstract class BaseEdge<KT extends object, KS extends DisplayObject> exte
|
||||
|
||||
result.onframe = () => {
|
||||
this.drawLabelShape(this.parsedAttributes, this);
|
||||
// this.drawArrow(this.parsedAttributes, true);
|
||||
// this.drawArrow(this.parsedAttributes, false);
|
||||
};
|
||||
|
||||
return result;
|
||||
|
@ -1,3 +1,5 @@
|
||||
export { Line } from './line';
|
||||
export { Quadratic } from './quadratic';
|
||||
|
||||
export type { LineStyleProps } from './line';
|
||||
export type { QuadraticStyleProps } from './quadratic';
|
||||
|
@ -1,12 +1,24 @@
|
||||
import type { DisplayObjectConfig, LineStyleProps as GLineStyleProps, Group } from '@antv/g';
|
||||
import { Line as GLine } from '@antv/g';
|
||||
import { deepMix } from '@antv/util';
|
||||
import type { Point } from '../../types';
|
||||
import type { BaseEdgeStyleProps } from './base-edge';
|
||||
import { BaseEdge } from './base-edge';
|
||||
|
||||
export type LineStyleProps = BaseEdgeStyleProps<LineKeyStyleProps>;
|
||||
type LineKeyStyleProps = Partial<GLineStyleProps> & {
|
||||
/**
|
||||
* <zh/> 边的起点
|
||||
* <en/> The source point. Represents the start of the edge
|
||||
*/
|
||||
sourcePoint: Point;
|
||||
/**
|
||||
* <zh/> 边的终点
|
||||
* <en/> The target point. Represents the end of the edge
|
||||
*/
|
||||
targetPoint: Point;
|
||||
};
|
||||
|
||||
type LineKeyStyleProps = Omit<GLineStyleProps, 'x1' | 'y1' | 'x2' | 'y2'>;
|
||||
export type LineStyleProps = BaseEdgeStyleProps<LineKeyStyleProps>;
|
||||
|
||||
type ParsedLineStyleProps = Required<LineStyleProps>;
|
||||
|
||||
@ -15,9 +27,11 @@ type LineOptions = DisplayObjectConfig<LineStyleProps>;
|
||||
/**
|
||||
* Draw line based on BaseEdge, override drawKeyShape
|
||||
*/
|
||||
export class Line extends BaseEdge<LineKeyStyleProps, GLine> {
|
||||
export class Line extends BaseEdge<GLineStyleProps, GLine> {
|
||||
static defaultStyleProps: Partial<LineStyleProps> = {};
|
||||
|
||||
constructor(options: LineOptions) {
|
||||
super(options);
|
||||
super(deepMix({}, { style: Line.defaultStyleProps }, options));
|
||||
}
|
||||
|
||||
protected drawKeyShape(attributes: ParsedLineStyleProps, container: Group): GLine | undefined {
|
||||
@ -25,10 +39,8 @@ export class Line extends BaseEdge<LineKeyStyleProps, GLine> {
|
||||
}
|
||||
|
||||
protected getKeyStyle(attributes: ParsedLineStyleProps): GLineStyleProps {
|
||||
const { sourcePoint, targetPoint, ...keyShape } = super.getKeyStyle(attributes) as unknown as GLineStyleProps & {
|
||||
sourcePoint: Point;
|
||||
targetPoint: Point;
|
||||
};
|
||||
const { sourcePoint, targetPoint, ...keyShape } = super.getKeyStyle(attributes) as LineKeyStyleProps;
|
||||
|
||||
return { ...keyShape, x1: sourcePoint[0], y1: sourcePoint[1], x2: targetPoint[0], y2: targetPoint[1] };
|
||||
}
|
||||
}
|
||||
|
68
packages/g6/src/elements/edges/quadratic.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import type { DisplayObjectConfig, Group, PathStyleProps } from '@antv/g';
|
||||
import { Path } from '@antv/g';
|
||||
import { deepMix } from '@antv/util';
|
||||
import type { Point } from '../../types';
|
||||
import { getQuadraticPath } from '../../utils/edge';
|
||||
import type { BaseEdgeStyleProps } from './base-edge';
|
||||
import { BaseEdge } from './base-edge';
|
||||
|
||||
type QuadraticKeyStyleProps = PathStyleProps & {
|
||||
/**
|
||||
* <zh/> 边的起点
|
||||
* <en/> The source point. Represents the start of the edge
|
||||
*/
|
||||
sourcePoint: Point;
|
||||
/**
|
||||
* <zh/> 边的终点
|
||||
* <en/> The target point. Represents the end of the edge
|
||||
*/
|
||||
targetPoint: Point;
|
||||
/**
|
||||
* <zh/> 控制点,用于定义曲线的形状。如果不指定,将会通过`curveOffset`和`curvePosition`来计算控制点
|
||||
* <en/> Control point. Used to define the shape of the curve. If not specified, it will be calculated using `curveOffset` and `curvePosition`.
|
||||
*/
|
||||
controlPoint?: Point;
|
||||
/**
|
||||
* <zh/> 控制点在两端点连线上的相对位置,范围为`0-1`
|
||||
* <en/> The relative position of the control point on the line, ranging from `0-1`
|
||||
*/
|
||||
curvePosition?: number;
|
||||
/**
|
||||
* <zh/> 控制点距离两端点连线的距离,可理解为控制边的弯曲程度
|
||||
* <en/> The distance of the control point from the line
|
||||
*/
|
||||
curveOffset?: number;
|
||||
};
|
||||
|
||||
export type QuadraticStyleProps = BaseEdgeStyleProps<QuadraticKeyStyleProps>;
|
||||
|
||||
type ParsedQuadraticStyleProps = Required<QuadraticStyleProps>;
|
||||
|
||||
type QuadraticOptions = DisplayObjectConfig<QuadraticStyleProps>;
|
||||
|
||||
export class Quadratic extends BaseEdge<PathStyleProps, Path> {
|
||||
static defaultStyleProps: Partial<QuadraticStyleProps> = {
|
||||
curvePosition: 0.5,
|
||||
curveOffset: 30,
|
||||
isBillboard: true,
|
||||
};
|
||||
|
||||
constructor(options: QuadraticOptions) {
|
||||
super(deepMix({}, { style: Quadratic.defaultStyleProps }, options));
|
||||
}
|
||||
|
||||
protected drawKeyShape(attributes: ParsedQuadraticStyleProps, container: Group): Path | undefined {
|
||||
return this.upsert('key', Path, this.getKeyStyle(attributes), container);
|
||||
}
|
||||
|
||||
protected getKeyStyle(attributes: ParsedQuadraticStyleProps): PathStyleProps {
|
||||
const { sourcePoint, targetPoint, controlPoint, curvePosition, curveOffset, ...keyStyle } = super.getKeyStyle(
|
||||
attributes,
|
||||
) as Required<QuadraticKeyStyleProps>;
|
||||
|
||||
return {
|
||||
...keyStyle,
|
||||
path: getQuadraticPath(sourcePoint, targetPoint, curvePosition, curveOffset, controlPoint),
|
||||
};
|
||||
}
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
import type { PathArray } from '@antv/util';
|
||||
import { pick } from '@antv/util';
|
||||
import type { Point, Vector2 } from '../types';
|
||||
import type { EdgeKey, EdgeLabelPosition, EdgeLabelStyleProps } from '../types/edge';
|
||||
import { isHorizontal } from './point';
|
||||
import { normalize, perpendicular, subtract } from './vector';
|
||||
|
||||
/**
|
||||
* <zh/> 获取标签的位置样式
|
||||
@ -92,3 +95,59 @@ function applyAutoRotation(key: EdgeKey, positionStyle: Partial<EdgeLabelStylePr
|
||||
adjustLabelPosition(key, positionStyle, ratio, angle);
|
||||
positionStyle.transform = `rotate(${(angle / Math.PI) * 180}deg)`;
|
||||
}
|
||||
|
||||
/** ==================== Quadratic Edge =========================== */
|
||||
|
||||
/**
|
||||
* <zh/> 获取二次贝塞尔曲线绘制路径
|
||||
*
|
||||
* <en/> Calculate the path for drawing a quadratic Bessel curve
|
||||
* @param sourcePoint - <zh/> 边的起点 | <en/> Source point
|
||||
* @param targetPoint - <zh/> 边的终点 | <en/> Target point
|
||||
* @param curvePosition - <zh/> 控制点在连线上的相对位置(取值范围为 0-1) | <en/> The relative position of the control point on the line (value range from 0 to 1)
|
||||
* @param curveOffset - <zh/> 控制点距离两端点连线的距离 | <en/> The distance between the control point and the line
|
||||
* @param controlPoint - <zh/> 控制点 | <en/> Control point
|
||||
* @returns <zh/> 返回绘制曲线的路径 | <en/> Returns curve path
|
||||
*/
|
||||
export function getQuadraticPath(
|
||||
sourcePoint: Point,
|
||||
targetPoint: Point,
|
||||
curvePosition: number,
|
||||
curveOffset: number,
|
||||
controlPoint?: Point,
|
||||
): PathArray {
|
||||
const actualControlPoint =
|
||||
controlPoint || calculateControlPoint(sourcePoint, targetPoint, curvePosition, curveOffset);
|
||||
|
||||
return [
|
||||
['M', sourcePoint[0], sourcePoint[1]],
|
||||
['Q', actualControlPoint[0], actualControlPoint[1], targetPoint[0], targetPoint[1]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* <zh/> 计算曲线的控制点
|
||||
*
|
||||
* <en/> Calculate the control point of Quadratic Bessel curve
|
||||
* @param sourcePoint - <zh/> 起点 | <en/> Source point
|
||||
* @param targetPoint - <zh/> 终点 | <en/> Target point
|
||||
* @param curvePosition - <zh/> 控制点在连线上的相对位置(取值范围为 0-1) | <en/> The relative position of the control point on the line (value range from 0 to 1)
|
||||
* @param curveOffset - <zh/> 控制点距离两端点连线的距离 | <en/> The distance between the control point and the line
|
||||
* @returns <zh/> 控制点 | <en/> Control points
|
||||
*/
|
||||
function calculateControlPoint(
|
||||
sourcePoint: Point,
|
||||
targetPoint: Point,
|
||||
curvePosition: number,
|
||||
curveOffset: number,
|
||||
): Point {
|
||||
const lineVector = subtract(targetPoint as Vector2, sourcePoint as Vector2);
|
||||
const controlPoint: Point = [
|
||||
sourcePoint[0] + curvePosition * lineVector[0],
|
||||
sourcePoint[1] + curvePosition * lineVector[1],
|
||||
];
|
||||
const perpVector = normalize(perpendicular(lineVector));
|
||||
controlPoint[0] += curveOffset * perpVector[0];
|
||||
controlPoint[1] += curveOffset * perpVector[1];
|
||||
return controlPoint;
|
||||
}
|
||||
|
99
packages/g6/src/utils/vector.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import type { Vector2, Vector3 } from '../types';
|
||||
|
||||
export function add(a: Vector2, b: Vector2): Vector2;
|
||||
export function add(a: Vector3, b: Vector3): Vector3;
|
||||
/**
|
||||
* <zh/> 两个向量求和
|
||||
*
|
||||
* <en/> Adds two vectors
|
||||
* @param a - <zh/> 第一个向量 | <en/> The first vector
|
||||
* @param b - <zh/> 第二个向量 | <en/> The second vector
|
||||
* @returns <zh/> 两个向量的和 | <en/> The sum of the two vectors
|
||||
*/
|
||||
export function add(a: Vector2 | Vector3, b: Vector2 | Vector3): Vector2 | Vector3 {
|
||||
return a.map((v, i) => v + b[i]) as Vector2 | Vector3;
|
||||
}
|
||||
|
||||
export function subtract(a: Vector2, b: Vector2): Vector2;
|
||||
export function subtract(a: Vector3, b: Vector3): Vector3;
|
||||
/**
|
||||
* <zh/> 两个向量求差
|
||||
*
|
||||
* <en/> Subtracts two vectors
|
||||
* @param a - <zh/> 第一个向量 | <en/> The first vector
|
||||
* @param b - <zh/> 第二个向量 | <en/> The second vector
|
||||
* @returns <zh/> 两个向量的差 | <en/> The difference of the two vectors
|
||||
*/
|
||||
export function subtract(a: Vector2 | Vector3, b: Vector2 | Vector3): Vector2 | Vector3 {
|
||||
return a.map((v, i) => v - b[i]) as Vector2 | Vector3;
|
||||
}
|
||||
|
||||
export function multiply(a: Vector2, b: Vector2): Vector2;
|
||||
export function multiply(a: Vector3, b: Vector3): Vector3;
|
||||
/**
|
||||
* <zh/> 两个向量求积
|
||||
*
|
||||
* <en/> Multiplies two vectors
|
||||
* @param a - <zh/> 第一个向量 | <en/> The first vector
|
||||
* @param b - <zh/> 第二个向量 | <en/> The second vector
|
||||
* @returns <zh/> 两个向量的积 | <en/> The product of the two vectors
|
||||
*/
|
||||
export function multiply(a: Vector2 | Vector3, b: Vector2 | Vector3): Vector2 | Vector3 {
|
||||
return a.map((v, i) => v * b[i]) as Vector2 | Vector3;
|
||||
}
|
||||
|
||||
export function divide(a: Vector2, b: Vector2): Vector2;
|
||||
export function divide(a: Vector3, b: Vector3): Vector3;
|
||||
/**
|
||||
* <zh/> 两个向量求商
|
||||
*
|
||||
* <en/> Divides two vectors
|
||||
* @param a - <zh/> 第一个向量 | <en/> The first vector
|
||||
* @param b - <zh/> 第二个向量 | <en/> The second vector
|
||||
* @returns <zh/> 两个向量的商 | <en/> The quotient of the two vectors
|
||||
*/
|
||||
export function divide(a: Vector2 | Vector3, b: Vector2 | Vector3): Vector2 | Vector3 {
|
||||
return a.map((v, i) => v / b[i]) as Vector2 | Vector3;
|
||||
}
|
||||
|
||||
export function distance(a: Vector2, b: Vector2): number;
|
||||
export function distance(a: Vector3, b: Vector3): number;
|
||||
/**
|
||||
* <zh/> 计算两个向量间的欧几里得距离
|
||||
*
|
||||
* <en/> Calculates the Euclidean distance between two vectors
|
||||
* @param a - <zh/> 第一个向量 | <en/> The first vector
|
||||
* @param b - <zh/> 第二个向量 | <en/> The second vector
|
||||
* @returns <zh/> 两个向量间的距离 | <en/> The distance between the two vectors
|
||||
*/
|
||||
export function distance(a: Vector2 | Vector3, b: Vector2 | Vector3): number {
|
||||
let sum = 0;
|
||||
a.forEach((v, i) => (sum += (v - b[i]) ** 2));
|
||||
return Math.sqrt(sum);
|
||||
}
|
||||
|
||||
export function normalize(a: Vector2): Vector2;
|
||||
export function normalize(a: Vector3): Vector3;
|
||||
/**
|
||||
* <zh/> 标准化向量(使长度为 1)
|
||||
*
|
||||
* <en/> Normalizes a vector (making its length 1)
|
||||
* @param a - <zh/> 要标准化的向量 | <en/> The vector to normalize
|
||||
* @returns <zh/> 标准化后的向量 | <en/> The normalized vector
|
||||
*/
|
||||
export function normalize(a: Vector2 | Vector3): Vector2 | Vector3 {
|
||||
let length = 0;
|
||||
a.forEach((v) => (length += v ** 2));
|
||||
return a.map((v) => v / Math.sqrt(length)) as Vector2 | Vector3;
|
||||
}
|
||||
|
||||
/**
|
||||
* <zh/> 计算向量的垂直向量
|
||||
*
|
||||
* <en/> Calculates the perpendicular vector to a given vector
|
||||
* @param a - <zh/> 原始向量 | <en/> The original vector
|
||||
* @returns <zh/> 原始向量的垂直向量 | <en/> The perpendicular vector to the original vector
|
||||
*/
|
||||
export function perpendicular(a: Vector2): Vector2 {
|
||||
return [-a[1], -a[0]];
|
||||
}
|