mirror of
https://gitee.com/antv/g6.git
synced 2024-12-02 03:38:20 +08:00
perf: optimize element dependencies effect trace performance (#6249)
* perf: add baseline performance report * perf: optmize effect performance * perf: generate performance report * test: update test demo --------- Co-authored-by: antv <antv@antfin.com>
This commit is contained in:
parent
8553175ce0
commit
2c21154855
@ -51,7 +51,7 @@
|
|||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-jsdoc": "^46.10.1",
|
"eslint-plugin-jsdoc": "^46.10.1",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"iperf": "^0.1.0-beta.11",
|
"iperf": "^0.1.0-beta.13",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
"jsdom": "^23.2.0",
|
"jsdom": "^23.2.0",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import type { DisplayObject, Group } from '@antv/g';
|
import type { DisplayObject, Group } from '@antv/g';
|
||||||
import type { BaseComboStyleProps, GraphData, HTMLStyleProps, IElementEvent, NodeData } from '@antv/g6';
|
import type { BaseComboStyleProps, GraphData, HTMLStyleProps, IElementEvent, NodeData } from '@antv/g6';
|
||||||
import { BaseCombo, effect, ExtensionCategory, Graph, HTML, isCollapsed, register } from '@antv/g6';
|
import { BaseCombo, ExtensionCategory, Graph, HTML, isCollapsed, register } from '@antv/g6';
|
||||||
|
import { isEqual } from '@antv/util';
|
||||||
|
|
||||||
export const elementHTMLSubGraph: TestCase = async (context) => {
|
export const elementHTMLSubGraph: TestCase = async (context) => {
|
||||||
interface CardNodeData {
|
interface CardNodeData {
|
||||||
@ -38,13 +39,14 @@ export const elementHTMLSubGraph: TestCase = async (context) => {
|
|||||||
|
|
||||||
private graph?: Graph;
|
private graph?: Graph;
|
||||||
|
|
||||||
@effect((self, attributes) => {
|
private previousData?: Record<string, unknown>;
|
||||||
const { data } = self.data;
|
|
||||||
return { data };
|
|
||||||
})
|
|
||||||
private drawSubGraph() {
|
private drawSubGraph() {
|
||||||
if (!this.isConnected) return;
|
if (!this.isConnected) return;
|
||||||
const data = this.data;
|
const data = this.data;
|
||||||
|
if (isEqual(this.previousData, data)) return;
|
||||||
|
this.previousData = data;
|
||||||
|
|
||||||
this.drawGraphNode(data!.data as GraphData);
|
this.drawGraphNode(data!.data as GraphData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,246 @@
|
|||||||
|
{
|
||||||
|
"version": "1.0",
|
||||||
|
"device": {
|
||||||
|
"os": {
|
||||||
|
"arch": "arm64",
|
||||||
|
"distro": "macOS",
|
||||||
|
"serial": "9821ed36011eee5abf6c71d6fc2c03fb4bf4655e674c56b7f50e2560cb6e924a"
|
||||||
|
},
|
||||||
|
"cpu": {
|
||||||
|
"manufacturer": "Apple",
|
||||||
|
"brand": "M1 Pro",
|
||||||
|
"speed": 2.4,
|
||||||
|
"cores": 10
|
||||||
|
},
|
||||||
|
"memory": {
|
||||||
|
"total": 16384,
|
||||||
|
"free": 540.28125
|
||||||
|
},
|
||||||
|
"gpu": {
|
||||||
|
"vendor": "Apple",
|
||||||
|
"model": "Apple M1 Pro",
|
||||||
|
"cores": "16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"repo": "aa87ec67c38f03808c72d82caaa3d064b4ee9c01",
|
||||||
|
"client": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/128.0.6613.18 Safari/537.36",
|
||||||
|
"reports": {
|
||||||
|
"UpdateElementState": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 167.09999999403954,
|
||||||
|
"max": 202.29999999701977,
|
||||||
|
"median": 171.79999999701977,
|
||||||
|
"avg": 172.86250000447035,
|
||||||
|
"variance": 18.562343744896353,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "update element state to selected"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 102.20000000298023,
|
||||||
|
"max": 116.09999999403954,
|
||||||
|
"median": 104.30000001192093,
|
||||||
|
"avg": 105.06250000186265,
|
||||||
|
"variance": 3.0598437559511513,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "update element state to default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 86,
|
||||||
|
"max": 105.8999999910593,
|
||||||
|
"median": 88.5,
|
||||||
|
"avg": 88.51249999925494,
|
||||||
|
"variance": 2.073593743089587,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "update element position"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"dataDiff1000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 2.7000000029802322,
|
||||||
|
"max": 11.300000011920929,
|
||||||
|
"median": 5.5,
|
||||||
|
"avg": 5.512499997392297,
|
||||||
|
"variance": 2.638593754386529,
|
||||||
|
"reliable": false,
|
||||||
|
"key": "data diff"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"dataDiff10000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 2.8999999910593033,
|
||||||
|
"max": 12.099999994039536,
|
||||||
|
"median": 6,
|
||||||
|
"avg": 6.325000004842877,
|
||||||
|
"variance": 4.859374997671694,
|
||||||
|
"reliable": false,
|
||||||
|
"key": "data diff"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"dataDiff100000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 11,
|
||||||
|
"max": 39.29999999701977,
|
||||||
|
"median": 12.700000002980232,
|
||||||
|
"avg": 16.387499999254942,
|
||||||
|
"variance": 60.1160937285237,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "data diff"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"dataDiff5000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 1.8999999910593033,
|
||||||
|
"max": 9.5,
|
||||||
|
"median": 8.099999994039536,
|
||||||
|
"avg": 6.374999998137355,
|
||||||
|
"variance": 6.324374991413206,
|
||||||
|
"reliable": false,
|
||||||
|
"key": "data diff"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"dataDiff50000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 5.700000002980232,
|
||||||
|
"max": 17.899999991059303,
|
||||||
|
"median": 8.299999997019768,
|
||||||
|
"avg": 9.5,
|
||||||
|
"variance": 16.31750000014901,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "data diff"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"elementDrawing100": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 12.700000002980232,
|
||||||
|
"max": 24.600000008940697,
|
||||||
|
"median": 18.899999991059303,
|
||||||
|
"avg": 19.199999999254942,
|
||||||
|
"variance": 8.127499995231629,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "element drawing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 7.9000000059604645,
|
||||||
|
"max": 14.100000008940697,
|
||||||
|
"median": 11.900000005960464,
|
||||||
|
"avg": 11.237500000745058,
|
||||||
|
"variance": 3.8348437521792946,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "grid layout"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"elementDrawing1000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 48.099999994039536,
|
||||||
|
"max": 73.20000000298023,
|
||||||
|
"median": 61.70000000298023,
|
||||||
|
"avg": 61.374999998137355,
|
||||||
|
"variance": 13.14437501249835,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "element drawing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 39.20000000298023,
|
||||||
|
"max": 59.1000000089407,
|
||||||
|
"median": 43.29999999701977,
|
||||||
|
"avg": 44.212499998509884,
|
||||||
|
"variance": 14.278593749292193,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "grid layout"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"elementDrawing10000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 409.3999999910593,
|
||||||
|
"max": 536.2000000029802,
|
||||||
|
"median": 434.3999999910593,
|
||||||
|
"avg": 442.1124999951571,
|
||||||
|
"variance": 829.2260936078895,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "element drawing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 372.90000000596046,
|
||||||
|
"max": 414.20000000298023,
|
||||||
|
"median": 393.29999999701977,
|
||||||
|
"avg": 389.8499999977648,
|
||||||
|
"variance": 108.12999993681908,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "grid layout"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"elementDrawing500": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 28.400000005960464,
|
||||||
|
"max": 51.099999994039536,
|
||||||
|
"median": 41.79999999701977,
|
||||||
|
"avg": 41.07499999925494,
|
||||||
|
"variance": 15.709374984912573,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "element drawing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 22.400000005960464,
|
||||||
|
"max": 29,
|
||||||
|
"median": 25.599999994039536,
|
||||||
|
"avg": 25.399999998509884,
|
||||||
|
"variance": 3.570000005811453,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "grid layout"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"elementDrawing5000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 213.79999999701977,
|
||||||
|
"max": 266.5,
|
||||||
|
"median": 223.09999999403954,
|
||||||
|
"avg": 230.39999999850988,
|
||||||
|
"variance": 165.17250003792344,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "element drawing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 185.79999999701977,
|
||||||
|
"max": 224.1000000089407,
|
||||||
|
"median": 195.70000000298023,
|
||||||
|
"avg": 193.41250000149012,
|
||||||
|
"variance": 35.76859376054257,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "grid layout"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,246 @@
|
|||||||
|
{
|
||||||
|
"version": "1.0",
|
||||||
|
"device": {
|
||||||
|
"os": {
|
||||||
|
"arch": "arm64",
|
||||||
|
"distro": "macOS",
|
||||||
|
"serial": "9821ed36011eee5abf6c71d6fc2c03fb4bf4655e674c56b7f50e2560cb6e924a"
|
||||||
|
},
|
||||||
|
"cpu": {
|
||||||
|
"manufacturer": "Apple",
|
||||||
|
"brand": "M1 Pro",
|
||||||
|
"speed": 2.4,
|
||||||
|
"cores": 10
|
||||||
|
},
|
||||||
|
"memory": {
|
||||||
|
"total": 16384,
|
||||||
|
"free": 224.8125
|
||||||
|
},
|
||||||
|
"gpu": {
|
||||||
|
"vendor": "Apple",
|
||||||
|
"model": "Apple M1 Pro",
|
||||||
|
"cores": "16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"repo": "7fbbb77580d806932e7b777b34856243600dbf35",
|
||||||
|
"client": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/128.0.6613.18 Safari/537.36",
|
||||||
|
"reports": {
|
||||||
|
"UpdateElementState": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 115.70000000298023,
|
||||||
|
"max": 146.29999999701977,
|
||||||
|
"median": 118.5,
|
||||||
|
"avg": 119.1750000026077,
|
||||||
|
"variance": 11.989375011604281,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "update element state to selected"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 72.90000000596046,
|
||||||
|
"max": 81,
|
||||||
|
"median": 75.5,
|
||||||
|
"avg": 75.12500000186265,
|
||||||
|
"variance": 1.299374995883554,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "update element state to default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 61.29999999701977,
|
||||||
|
"max": 73.59999999403954,
|
||||||
|
"median": 63.29999999701977,
|
||||||
|
"avg": 63.28749999962747,
|
||||||
|
"variance": 0.2935937537904829,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "update element position"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"dataDiff1000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 4.399999991059303,
|
||||||
|
"max": 13.900000005960464,
|
||||||
|
"median": 6.4000000059604645,
|
||||||
|
"avg": 6.262500002980232,
|
||||||
|
"variance": 1.0873437525331973,
|
||||||
|
"reliable": false,
|
||||||
|
"key": "data diff"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"dataDiff10000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 2.8999999910593033,
|
||||||
|
"max": 13.700000002980232,
|
||||||
|
"median": 6.0999999940395355,
|
||||||
|
"avg": 6.199999999254942,
|
||||||
|
"variance": 3.767500012814999,
|
||||||
|
"reliable": false,
|
||||||
|
"key": "data diff"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"dataDiff100000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 10.899999991059303,
|
||||||
|
"max": 41.70000000298023,
|
||||||
|
"median": 12.299999997019768,
|
||||||
|
"avg": 17.51249999552965,
|
||||||
|
"variance": 96.928593772389,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "data diff"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"dataDiff5000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 3.0999999940395355,
|
||||||
|
"max": 13,
|
||||||
|
"median": 3.6000000089406967,
|
||||||
|
"avg": 5.262499999254942,
|
||||||
|
"variance": 10.062343739960342,
|
||||||
|
"reliable": false,
|
||||||
|
"key": "data diff"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"dataDiff50000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 5.4000000059604645,
|
||||||
|
"max": 15.400000005960464,
|
||||||
|
"median": 8.399999991059303,
|
||||||
|
"avg": 8.549999998882413,
|
||||||
|
"variance": 8.840000012554228,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "data diff"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"elementDrawing100": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 10.200000002980232,
|
||||||
|
"max": 30.099999994039536,
|
||||||
|
"median": 18.600000008940697,
|
||||||
|
"avg": 19.499999998137355,
|
||||||
|
"variance": 17.06999999091029,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "element drawing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 6.5999999940395355,
|
||||||
|
"max": 11.200000002980232,
|
||||||
|
"median": 8.400000005960464,
|
||||||
|
"avg": 8.550000002607703,
|
||||||
|
"variance": 0.5175000003352761,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "grid layout"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"elementDrawing1000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 55.3999999910593,
|
||||||
|
"max": 75.5,
|
||||||
|
"median": 65.29999999701977,
|
||||||
|
"avg": 65.09999999962747,
|
||||||
|
"variance": 7.902500012740493,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "element drawing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 31.700000002980232,
|
||||||
|
"max": 47,
|
||||||
|
"median": 36.20000000298023,
|
||||||
|
"avg": 36.34999999962747,
|
||||||
|
"variance": 5.345000000037253,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "grid layout"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"elementDrawing10000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 404.40000000596046,
|
||||||
|
"max": 515.7999999970198,
|
||||||
|
"median": 420.6000000089407,
|
||||||
|
"avg": 427.75000000186265,
|
||||||
|
"variance": 282.06500002410263,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "element drawing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 306.70000000298023,
|
||||||
|
"max": 341,
|
||||||
|
"median": 321.6000000089407,
|
||||||
|
"avg": 319.4125000014901,
|
||||||
|
"variance": 58.756093712486326,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "grid layout"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"elementDrawing500": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 25,
|
||||||
|
"max": 59.5,
|
||||||
|
"median": 40.70000000298023,
|
||||||
|
"avg": 42.03749999962747,
|
||||||
|
"variance": 15.694843770219013,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "element drawing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 16.69999998807907,
|
||||||
|
"max": 24.299999997019768,
|
||||||
|
"median": 20.799999997019768,
|
||||||
|
"avg": 20.25,
|
||||||
|
"variance": 5.507500002086163,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "grid layout"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
},
|
||||||
|
"elementDrawing5000": {
|
||||||
|
"time": [
|
||||||
|
{
|
||||||
|
"min": 203.70000000298023,
|
||||||
|
"max": 264.30000001192093,
|
||||||
|
"median": 224.79999999701977,
|
||||||
|
"avg": 225.87499999813735,
|
||||||
|
"variance": 117.29687504237518,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "element drawing"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min": 154.29999999701977,
|
||||||
|
"max": 174.6000000089407,
|
||||||
|
"median": 164.19999998807907,
|
||||||
|
"avg": 161,
|
||||||
|
"variance": 32.70499999940395,
|
||||||
|
"reliable": true,
|
||||||
|
"key": "grid layout"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "passed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
packages/g6/__tests__/perf/update-state.perf.ts
Normal file
38
packages/g6/__tests__/perf/update-state.perf.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { Graph } from '@antv/g6';
|
||||||
|
import type { Test } from 'iperf';
|
||||||
|
|
||||||
|
export const UpdateElementState: Test = async ({ container, perf }) => {
|
||||||
|
const nodes = Array(1000)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => ({ id: `${i}` }));
|
||||||
|
const edges = Array(999)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, i) => ({ id: `edge-${i}`, source: `${i}`, target: `${i + 1}` }));
|
||||||
|
|
||||||
|
const graph = new Graph({
|
||||||
|
container,
|
||||||
|
animation: false,
|
||||||
|
data: { nodes, edges },
|
||||||
|
layout: { type: 'grid' },
|
||||||
|
});
|
||||||
|
|
||||||
|
await graph.render();
|
||||||
|
|
||||||
|
const selected = [...nodes, ...edges].map((element) => [element.id, 'selected']);
|
||||||
|
|
||||||
|
await perf.evaluate('update element state to selected', async () => {
|
||||||
|
await graph.setElementState(Object.fromEntries(selected));
|
||||||
|
});
|
||||||
|
|
||||||
|
const none = [...nodes, ...edges].map((element) => [element.id, []]);
|
||||||
|
|
||||||
|
await perf.evaluate('update element state to default', async () => {
|
||||||
|
await graph.setElementState(Object.fromEntries(none));
|
||||||
|
});
|
||||||
|
|
||||||
|
const position = nodes.map((node) => [node.id, [10, 10]]);
|
||||||
|
|
||||||
|
await perf.evaluate('update element position', async () => {
|
||||||
|
await graph.translateElementBy(Object.fromEntries(position), false);
|
||||||
|
});
|
||||||
|
};
|
@ -154,9 +154,10 @@ export abstract class BaseCombo<S extends BaseComboStyleProps = BaseComboStylePr
|
|||||||
return getExpandedBBox(childrenBBox, padding);
|
return getExpandedBBox(childrenBBox, padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
@effect((self, attributes) => self.getCollapsedMarkerStyle(attributes))
|
|
||||||
protected drawCollapsedMarkerShape(attributes: Required<S>, container: Group): void {
|
protected drawCollapsedMarkerShape(attributes: Required<S>, container: Group): void {
|
||||||
this.upsert('collapsed-marker', Icon, this.getCollapsedMarkerStyle(attributes), container);
|
const style = this.getCollapsedMarkerStyle(attributes);
|
||||||
|
if (!effect(this, 'collapsedMarker', style)) return;
|
||||||
|
this.upsert('collapsed-marker', Icon, style, container);
|
||||||
connectImage(this);
|
connectImage(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,6 +335,8 @@ export abstract class BaseEdge extends BaseElement<BaseEdgeStyleProps> implement
|
|||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
const arrowStyle = this.getArrowStyle(attributes, isStart);
|
const arrowStyle = this.getArrowStyle(attributes, isStart);
|
||||||
|
if (!effect(this, `arrow-${type}`, arrowStyle)) return;
|
||||||
|
|
||||||
const [marker, markerOffset, arrowOffset] = isStart
|
const [marker, markerOffset, arrowOffset] = isStart
|
||||||
? (['markerStart', 'markerStartOffset', 'startArrowOffset'] as const)
|
? (['markerStart', 'markerStartOffset', 'startArrowOffset'] as const)
|
||||||
: (['markerEnd', 'markerEndOffset', 'endArrowOffset'] as const);
|
: (['markerEnd', 'markerEndOffset', 'endArrowOffset'] as const);
|
||||||
@ -376,35 +378,36 @@ export abstract class BaseEdge extends BaseElement<BaseEdgeStyleProps> implement
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@effect((self, attributes) => self.getLabelStyle(attributes))
|
|
||||||
protected drawLabelShape(attributes: ParsedBaseEdgeStyleProps, container: Group) {
|
protected drawLabelShape(attributes: ParsedBaseEdgeStyleProps, container: Group) {
|
||||||
this.upsert('label', Label, this.getLabelStyle(attributes), container);
|
const style = this.getLabelStyle(attributes);
|
||||||
|
if (!effect(this, 'label', style)) return;
|
||||||
|
this.upsert('label', Label, style, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
@effect((self, attributes) => self.getHaloStyle(attributes))
|
|
||||||
protected drawHaloShape(attributes: ParsedBaseEdgeStyleProps, container: Group) {
|
protected drawHaloShape(attributes: ParsedBaseEdgeStyleProps, container: Group) {
|
||||||
this.upsert('halo', Path, this.getHaloStyle(attributes), container);
|
const style = this.getHaloStyle(attributes);
|
||||||
|
if (!effect(this, 'halo', style)) return;
|
||||||
|
this.upsert('halo', Path, style, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
@effect((self, attributes) => self.getBadgeStyle(attributes))
|
|
||||||
protected drawBadgeShape(attributes: ParsedBaseEdgeStyleProps, container: Group) {
|
protected drawBadgeShape(attributes: ParsedBaseEdgeStyleProps, container: Group) {
|
||||||
this.upsert('badge', Badge, this.getBadgeStyle(attributes), container);
|
const style = this.getBadgeStyle(attributes);
|
||||||
|
if (!effect(this, 'badge', style)) return;
|
||||||
|
this.upsert('badge', Badge, style, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
@effect((self, attributes) => self.getArrowStyle(attributes, 'start'))
|
|
||||||
protected drawSourceArrow(attributes: ParsedBaseEdgeStyleProps) {
|
protected drawSourceArrow(attributes: ParsedBaseEdgeStyleProps) {
|
||||||
this.drawArrow(attributes, 'start');
|
this.drawArrow(attributes, 'start');
|
||||||
}
|
}
|
||||||
|
|
||||||
@effect((self, attributes) => self.getArrowStyle(attributes, 'end'))
|
|
||||||
protected drawTargetArrow(attributes: ParsedBaseEdgeStyleProps) {
|
protected drawTargetArrow(attributes: ParsedBaseEdgeStyleProps) {
|
||||||
this.drawArrow(attributes, 'end');
|
this.drawArrow(attributes, 'end');
|
||||||
}
|
}
|
||||||
|
|
||||||
@effect((self, attributes) => self.getKeyStyle(attributes))
|
|
||||||
protected drawKeyShape(attributes: ParsedBaseEdgeStyleProps, container: Group): Path | undefined {
|
protected drawKeyShape(attributes: ParsedBaseEdgeStyleProps, container: Group): Path | undefined {
|
||||||
const key = this.upsert('key', Path, this.getKeyStyle(attributes), container);
|
const style = this.getKeyStyle(attributes);
|
||||||
return key;
|
if (!effect(this, 'key', style)) return;
|
||||||
|
return this.upsert('key', Path, style, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(attributes = this.parsedAttributes, container: Group = this): void {
|
public render(attributes = this.parsedAttributes, container: Group = this): void {
|
||||||
|
@ -1,61 +1,27 @@
|
|||||||
import type { Element } from '../types';
|
import type { Element } from '../types';
|
||||||
import { getCachedStyle, setCacheStyle } from '../utils/cache';
|
|
||||||
|
const EFFECT_WEAKMAP = new WeakMap<Element, Record<string, any>>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <zh/> 优化方法执行次数,仅在样式属性发生变化时执行函数
|
* <zh/> 判定给定样式是否与上一次的样式相同
|
||||||
*
|
*
|
||||||
* <en/> Optimize the number of method executions, and only execute the function when the style attributes change
|
* <en/> Determine whether the given style are the same as the previous ones
|
||||||
* @param styler - <zh/> 获取样式属性函数 | <en/> Get style attribute function
|
* @param target - <zh/> 目标元素 | <en/> Target element
|
||||||
* @returns <zh/> 装饰器 | <en/> Decorator
|
* @param key - <zh/> 缓存 key | <en/> Cache key
|
||||||
* @remarks
|
* @param style - <zh/> 样式属性 | <en/> Style attribute
|
||||||
* <zh/> 仅指定 getStyle 的情况下,会分别使用当前的 attributes 和 新的 attributes 调用函数,若两者相同,则不执行函数。
|
* @returns <zh/> 是否执行函数 | <en/> Whether to execute the function
|
||||||
*
|
|
||||||
* 如果指定了 shapeKey, 则会直接获取该图形的 attributes 作为原始样式属性,通常在 getStyle 函数中获取了包围盒时使用。
|
|
||||||
*
|
|
||||||
* <en/> Only when getStyle is specified, the function will be called with the current attributes and the new attributes respectively. If they are the same, the function will not be executed.
|
|
||||||
*
|
|
||||||
* If shapeKey is specified, the attributes of the shape will be directly obtained as the original style attributes, which is usually used when the bounding box of the element is used in the getStyle function.
|
|
||||||
* @example
|
|
||||||
* <zh/> 仅当 value 发生变化时执行函数
|
|
||||||
*
|
|
||||||
* <en/> Execute the function only when value changes
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* class CustomNode extends BaseNode {
|
|
||||||
*
|
|
||||||
* @effect((self, attributes) => {
|
|
||||||
* const { value } = attributes;
|
|
||||||
* return { value }
|
|
||||||
* })
|
|
||||||
* drawCustomShape(attributes, container) {
|
|
||||||
* this.upsert('custom', 'circle', { ...attributes }, container);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
*/
|
||||||
export function effect(styler: (self: any, attributes: Record<string, unknown>) => Record<string, unknown>) {
|
export function effect<T extends false | Record<string, any>>(target: Element, key: string, style: T): boolean {
|
||||||
return function (target: Element, propertyKey: string, descriptor: PropertyDescriptor) {
|
if (!EFFECT_WEAKMAP.has(target)) EFFECT_WEAKMAP.set(target, {});
|
||||||
const fn = descriptor.value;
|
const cache = EFFECT_WEAKMAP.get(target)!;
|
||||||
|
if (!cache[key]) {
|
||||||
descriptor.value = function (this: Element, attr: Record<string, unknown>, ...rest: unknown[]) {
|
cache[key] = style;
|
||||||
// 初始化后需要执行首次调用 / First call after initialization
|
return true;
|
||||||
const initKey = `${propertyKey}_invoke`;
|
}
|
||||||
if (!getCachedStyle(this, initKey)) {
|
const original = cache[key];
|
||||||
setCacheStyle(this, initKey, true);
|
if (isStyleEqual(original, style)) return false;
|
||||||
return fn.call(this, attr, ...rest);
|
cache[key] = style;
|
||||||
}
|
return true;
|
||||||
|
|
||||||
const styleKey = `${propertyKey}_style`;
|
|
||||||
const original = getCachedStyle(this, styleKey);
|
|
||||||
const modified = styler(this, attr);
|
|
||||||
setCacheStyle(this, styleKey, modified);
|
|
||||||
|
|
||||||
if (isStyleEqual(original, modified)) return null;
|
|
||||||
|
|
||||||
return fn.call(this, attr, ...rest);
|
|
||||||
};
|
|
||||||
return descriptor;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,7 +37,7 @@ export function effect(styler: (self: any, attributes: Record<string, unknown>)
|
|||||||
*
|
*
|
||||||
* <en/> Perform a second-level shallow comparison to compare complex shape attributes such as badges and ports
|
* <en/> Perform a second-level shallow comparison to compare complex shape attributes such as badges and ports
|
||||||
*/
|
*/
|
||||||
const isStyleEqual = (a: Record<string, unknown>, b: Record<string, unknown>, depth = 2): boolean => {
|
const isStyleEqual = (a: false | Record<string, unknown>, b: false | Record<string, unknown>, depth = 2): boolean => {
|
||||||
if (typeof a !== 'object' || typeof b !== 'object') return a === b;
|
if (typeof a !== 'object' || typeof b !== 'object') return a === b;
|
||||||
|
|
||||||
const keys1 = Object.keys(a);
|
const keys1 = Object.keys(a);
|
||||||
|
@ -361,49 +361,54 @@ export abstract class BaseNode<S extends BaseNodeStyleProps = BaseNodeStyleProps
|
|||||||
return getRectIntersectPoint(point, keyShapeBounds);
|
return getRectIntersectPoint(point, keyShapeBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@effect((self, attributes) => self.getHaloStyle(attributes))
|
|
||||||
protected drawHaloShape(attributes: Required<S>, container: Group): void {
|
protected drawHaloShape(attributes: Required<S>, container: Group): void {
|
||||||
|
const style = this.getHaloStyle(attributes);
|
||||||
|
if (!effect(this, 'halo', style)) return;
|
||||||
|
|
||||||
const keyShape = this.getShape('key');
|
const keyShape = this.getShape('key');
|
||||||
this.upsert(
|
this.upsert('halo', keyShape.constructor as new (...args: unknown[]) => DisplayObject, style, container);
|
||||||
'halo',
|
|
||||||
keyShape.constructor as new (...args: unknown[]) => DisplayObject,
|
|
||||||
this.getHaloStyle(attributes),
|
|
||||||
container,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@effect((self, attributes) => self.getIconStyle(attributes))
|
|
||||||
protected drawIconShape(attributes: Required<S>, container: Group): void {
|
protected drawIconShape(attributes: Required<S>, container: Group): void {
|
||||||
this.upsert('icon', Icon, this.getIconStyle(attributes), container);
|
const style = this.getIconStyle(attributes);
|
||||||
|
if (!effect(this, 'icon', style)) return;
|
||||||
|
|
||||||
|
this.upsert('icon', Icon, style, container);
|
||||||
connectImage(this);
|
connectImage(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@effect((self, attributes) => self.getBadgesStyle(attributes))
|
|
||||||
protected drawBadgeShapes(attributes: Required<S>, container: Group): void {
|
protected drawBadgeShapes(attributes: Required<S>, container: Group): void {
|
||||||
const badgesStyle = this.getBadgesStyle(attributes);
|
const badgesStyle = this.getBadgesStyle(attributes);
|
||||||
Object.keys(badgesStyle).forEach((key) => {
|
Object.keys(badgesStyle).forEach((key) => {
|
||||||
this.upsert(`badge-${key}`, Badge, badgesStyle[key], container);
|
const style = badgesStyle[key];
|
||||||
|
if (!effect(this, `badge-${key}`, style)) return;
|
||||||
|
|
||||||
|
this.upsert(`badge-${key}`, Badge, style, container);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@effect((self, attributes) => self.getPortsStyle(attributes))
|
|
||||||
protected drawPortShapes(attributes: Required<S>, container: Group): void {
|
protected drawPortShapes(attributes: Required<S>, container: Group): void {
|
||||||
const portsStyle = this.getPortsStyle(attributes);
|
const portsStyle = this.getPortsStyle(attributes);
|
||||||
|
|
||||||
Object.keys(portsStyle).forEach((key) => {
|
Object.keys(portsStyle).forEach((key) => {
|
||||||
this.upsert(`port-${key}`, GCircle, portsStyle[key] as CircleStyleProps, container);
|
const style = portsStyle[key] as CircleStyleProps;
|
||||||
|
const shapeKey = `port-${key}`;
|
||||||
|
if (!effect(this, shapeKey, style)) return;
|
||||||
|
|
||||||
|
this.upsert(shapeKey, GCircle, style, container);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@effect((self, attributes) => self.getLabelStyle(attributes))
|
|
||||||
protected drawLabelShape(attributes: Required<S>, container: Group): void {
|
protected drawLabelShape(attributes: Required<S>, container: Group): void {
|
||||||
this.upsert('label', Label, this.getLabelStyle(attributes), container);
|
const style = this.getLabelStyle(attributes);
|
||||||
|
if (!effect(this, 'label', style)) return;
|
||||||
|
|
||||||
|
this.upsert('label', Label, style, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract drawKeyShape(attributes: Required<S>, container: Group): DisplayObject | undefined;
|
protected abstract drawKeyShape(attributes: Required<S>, container: Group): DisplayObject | undefined;
|
||||||
|
|
||||||
// 用于装饰抽象方法 / Used to decorate abstract methods
|
// 用于装饰抽象方法 / Used to decorate abstract methods
|
||||||
@effect((self, attributes) => self.getKeyStyle(attributes))
|
|
||||||
private _drawKeyShape(attributes: Required<S>, container: Group) {
|
private _drawKeyShape(attributes: Required<S>, container: Group) {
|
||||||
return this.drawKeyShape(attributes, container);
|
return this.drawKeyShape(attributes, container);
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ export abstract class BaseShape<StyleProps extends BaseShapeStyleProps> extends
|
|||||||
* <en> create, update or remove shape
|
* <en> create, update or remove shape
|
||||||
* @param className - <zh> 图形名称 | <en> shape name
|
* @param className - <zh> 图形名称 | <en> shape name
|
||||||
* @param Ctor - <zh> 图形类型 | <en> shape type
|
* @param Ctor - <zh> 图形类型 | <en> shape type
|
||||||
* @param style - <zh> 图形样式 | <en> shape style
|
* @param style - <zh> 图形样式。若要删除图形,传入 false | <en> shape style. Pass false to remove the shape
|
||||||
* @param container - <zh> 容器 | <en> container
|
* @param container - <zh> 容器 | <en> container
|
||||||
* @param hooks - <zh> 钩子函数 | <en> hooks
|
* @param hooks - <zh> 钩子函数 | <en> hooks
|
||||||
* @returns <zh> 图形实例 | <en> shape instance
|
* @returns <zh> 图形实例 | <en> shape instance
|
||||||
|
@ -28,7 +28,6 @@ export {
|
|||||||
} from './constants';
|
} from './constants';
|
||||||
export { BaseCombo, CircleCombo, RectCombo } from './elements/combos';
|
export { BaseCombo, CircleCombo, RectCombo } from './elements/combos';
|
||||||
export { BaseEdge, Cubic, CubicHorizontal, CubicVertical, Line, Polyline, Quadratic } from './elements/edges';
|
export { BaseEdge, Cubic, CubicHorizontal, CubicVertical, Line, Polyline, Quadratic } from './elements/edges';
|
||||||
export { effect } from './elements/effect';
|
|
||||||
export {
|
export {
|
||||||
BaseNode,
|
BaseNode,
|
||||||
Circle,
|
Circle,
|
||||||
|
Loading…
Reference in New Issue
Block a user