From 0e67fd7300d03725994f81c444dfdd6e3372fed2 Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Sun, 29 Sep 2024 16:29:29 +0800 Subject: [PATCH 01/14] fix: fix issue with dirtyBounds incorrectly while set visible --- .../fix-visible-bounds_2024-09-29-08-30.json | 10 ++++++++++ .../src/graphic/graphic-service/graphic-service.ts | 10 +++++----- packages/vrender/__tests__/browser/src/pages/text.ts | 2 ++ 3 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 common/changes/@visactor/vrender-core/fix-visible-bounds_2024-09-29-08-30.json diff --git a/common/changes/@visactor/vrender-core/fix-visible-bounds_2024-09-29-08-30.json b/common/changes/@visactor/vrender-core/fix-visible-bounds_2024-09-29-08-30.json new file mode 100644 index 000000000..e590b282f --- /dev/null +++ b/common/changes/@visactor/vrender-core/fix-visible-bounds_2024-09-29-08-30.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vrender-core", + "comment": "fix: fix issue with dirtyBounds incorrectly while set visible", + "type": "none" + } + ], + "packageName": "@visactor/vrender-core" +} \ No newline at end of file diff --git a/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts b/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts index 186d5535e..f345b256c 100644 --- a/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts +++ b/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts @@ -23,6 +23,7 @@ import { BoundsContext } from '../../common/bounds-context'; import { renderCommandList } from '../../common/render-command-list'; import { GraphicCreator } from '../constants'; import { identityMat4, multiplyMat4Mat4, rotateX, rotateY, rotateZ, scaleMat4, translate } from '../../common/matrix'; +import { application } from '../../application'; export function getExtraModelMatrix(dx: number, dy: number, graphic: IGraphic): mat4 | null { const { alpha, beta } = graphic.attribute; @@ -366,13 +367,12 @@ export class DefaultGraphicService implements IGraphicService { return true; } - if (!graphic.valid) { - aabbBounds.clear(); - return false; - } const { visible = theme.visible } = attribute; - if (!visible) { + + if (!(graphic.valid && visible)) { + application.graphicService.beforeUpdateAABBBounds(graphic, graphic.stage, true, aabbBounds); aabbBounds.clear(); + application.graphicService.afterUpdateAABBBounds(graphic, graphic.stage, aabbBounds, graphic, true); return false; } return true; diff --git a/packages/vrender/__tests__/browser/src/pages/text.ts b/packages/vrender/__tests__/browser/src/pages/text.ts index 14c410ad3..b182b9298 100644 --- a/packages/vrender/__tests__/browser/src/pages/text.ts +++ b/packages/vrender/__tests__/browser/src/pages/text.ts @@ -190,6 +190,8 @@ export const page = () => { // scaleY: 2 }); graphics.push(text); + text.setAttributes({ visible: false }); + console.log(text.AABBBounds); const b = text.OBBBounds; const circle = createCircle({ x: (b.x1 + b.x2) / 2, From 7b8372c9a717b68f80941fe6693badf0167c2059 Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Sun, 29 Sep 2024 16:47:30 +0800 Subject: [PATCH 02/14] fix: add clearAABBBounds interface --- .../graphic/graphic-service/graphic-service.ts | 17 +++++++++++++---- .../src/interface/graphic-service.ts | 2 ++ .../builtin-plugin/dirty-bounds-plugin.ts | 15 +++++++++++++++ .../vrender/__tests__/browser/src/pages/text.ts | 8 ++++++-- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts b/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts index f345b256c..5ad5802a3 100644 --- a/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts +++ b/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts @@ -176,6 +176,7 @@ export class DefaultGraphicService implements IGraphicService { onClearIncremental: ISyncHook<[IGroup, IStage]>; beforeUpdateAABBBounds: ISyncHook<[IGraphic, IStage, boolean, IAABBBounds]>; afterUpdateAABBBounds: ISyncHook<[IGraphic, IStage, IAABBBounds, { globalAABBBounds: IAABBBounds }, boolean]>; + clearAABBBounds: ISyncHook<[IGraphic, IStage, IAABBBounds]>; }; // 临时bounds,用作缓存 @@ -201,7 +202,8 @@ export class DefaultGraphicService implements IGraphicService { 'aabbBounds', 'globalAABBBounds', 'selfChange' - ]) + ]), + clearAABBBounds: new SyncHook<[IGraphic, IStage, IAABBBounds]>(['graphic', 'stage', 'aabbBounds']) }; this.tempAABBBounds1 = new AABBBounds(); this.tempAABBBounds2 = new AABBBounds(); @@ -252,6 +254,11 @@ export class DefaultGraphicService implements IGraphicService { this.hooks.afterUpdateAABBBounds.call(graphic, stage, bounds, params, selfChange); } } + clearAABBBounds(graphic: IGraphic, stage: IStage, b: IAABBBounds) { + if (this.hooks.clearAABBBounds.taps.length) { + this.hooks.clearAABBBounds.call(graphic, stage, b); + } + } // TODO delete updatePathProxyAABBBounds(aabbBounds: IAABBBounds, graphic?: IGraphic): boolean { const path = typeof graphic.pathProxy === 'function' ? graphic.pathProxy(graphic.attribute) : graphic.pathProxy; @@ -370,9 +377,11 @@ export class DefaultGraphicService implements IGraphicService { const { visible = theme.visible } = attribute; if (!(graphic.valid && visible)) { - application.graphicService.beforeUpdateAABBBounds(graphic, graphic.stage, true, aabbBounds); - aabbBounds.clear(); - application.graphicService.afterUpdateAABBBounds(graphic, graphic.stage, aabbBounds, graphic, true); + // application.graphicService.beforeUpdateAABBBounds(graphic, graphic.stage, true, aabbBounds); + if (!aabbBounds.empty()) { + application.graphicService.clearAABBBounds(graphic, graphic.stage, aabbBounds); + aabbBounds.clear(); + } return false; } return true; diff --git a/packages/vrender-core/src/interface/graphic-service.ts b/packages/vrender-core/src/interface/graphic-service.ts index 19e0464f6..c5ba53f5e 100644 --- a/packages/vrender-core/src/interface/graphic-service.ts +++ b/packages/vrender-core/src/interface/graphic-service.ts @@ -51,6 +51,7 @@ export interface IGraphicService { onClearIncremental: ISyncHook<[IGroup, IStage]>; beforeUpdateAABBBounds: ISyncHook<[IGraphic, IStage, boolean, IAABBBounds]>; afterUpdateAABBBounds: ISyncHook<[IGraphic, IStage, IAABBBounds, { globalAABBBounds: IAABBBounds }, boolean]>; + clearAABBBounds: ISyncHook<[IGraphic, IStage, IAABBBounds]>; }; beforeUpdateAABBBounds: (graphic: IGraphic, stage: IStage, willUpdate: boolean, bounds: IAABBBounds) => void; afterUpdateAABBBounds: ( @@ -60,6 +61,7 @@ export interface IGraphicService { params: { globalAABBBounds: IAABBBounds }, selfChange: boolean ) => void; + clearAABBBounds: (graphic: IGraphic, stage: IStage, b: IAABBBounds) => void; creator: IGraphicCreator; validCheck: ( diff --git a/packages/vrender-core/src/plugins/builtin-plugin/dirty-bounds-plugin.ts b/packages/vrender-core/src/plugins/builtin-plugin/dirty-bounds-plugin.ts index 4b9115062..9e4557724 100644 --- a/packages/vrender-core/src/plugins/builtin-plugin/dirty-bounds-plugin.ts +++ b/packages/vrender-core/src/plugins/builtin-plugin/dirty-bounds-plugin.ts @@ -59,6 +59,17 @@ export class DirtyBoundsPlugin implements IPlugin { stage.dirty(params.globalAABBBounds); } ); + application.graphicService.hooks.clearAABBBounds.tap( + this.key, + (graphic: IGraphic, stage: IStage, bounds: IAABBBounds) => { + if (!(stage && stage === this.pluginService.stage && stage.renderCount)) { + return; + } + if (stage) { + stage.dirty(bounds); + } + } + ); application.graphicService.hooks.onRemove.tap(this.key, (graphic: IGraphic) => { const stage = graphic.stage; if (!(stage && stage === this.pluginService.stage && stage.renderCount)) { @@ -78,6 +89,10 @@ export class DirtyBoundsPlugin implements IPlugin { application.graphicService.hooks.afterUpdateAABBBounds.taps.filter(item => { return item.name !== this.key; }); + application.graphicService.hooks.clearAABBBounds.taps = + application.graphicService.hooks.clearAABBBounds.taps.filter(item => { + return item.name !== this.key; + }); context.stage.hooks.afterRender.taps = context.stage.hooks.afterRender.taps.filter(item => { return item.name !== this.key; }); diff --git a/packages/vrender/__tests__/browser/src/pages/text.ts b/packages/vrender/__tests__/browser/src/pages/text.ts index b182b9298..ed9685436 100644 --- a/packages/vrender/__tests__/browser/src/pages/text.ts +++ b/packages/vrender/__tests__/browser/src/pages/text.ts @@ -190,8 +190,11 @@ export const page = () => { // scaleY: 2 }); graphics.push(text); - text.setAttributes({ visible: false }); - console.log(text.AABBBounds); + setTimeout(() => { + debugger; + text.setAttributes({ visible: false }); + console.log(text.AABBBounds); + }, 1000); const b = text.OBBBounds; const circle = createCircle({ x: (b.x1 + b.x2) / 2, @@ -235,6 +238,7 @@ export const page = () => { const stage = createStage({ canvas: 'main', autoRender: true, + disableDirtyBounds: false, pluginList: ['poptipForText'] }); From 9b12fa5131747968d64576a259bac0d03082a350 Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Mon, 30 Sep 2024 11:16:54 +0800 Subject: [PATCH 03/14] fix: fix issue with dirtyBounds by calc globalAABBBounds --- .../vrender-core/src/graphic/graphic-service/graphic-service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts b/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts index 5ad5802a3..cc5276501 100644 --- a/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts +++ b/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts @@ -379,6 +379,7 @@ export class DefaultGraphicService implements IGraphicService { if (!(graphic.valid && visible)) { // application.graphicService.beforeUpdateAABBBounds(graphic, graphic.stage, true, aabbBounds); if (!aabbBounds.empty()) { + aabbBounds.transformWithMatrix((graphic.parent as IGroup).globalTransMatrix); application.graphicService.clearAABBBounds(graphic, graphic.stage, aabbBounds); aabbBounds.clear(); } From 241e539c07897d0a68065de24d9d899ac09ae88a Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Mon, 30 Sep 2024 14:44:11 +0800 Subject: [PATCH 04/14] fix: fix bug where clearAABBSounds is called when graphic.parent is null --- .../vrender-core/src/graphic/graphic-service/graphic-service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts b/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts index cc5276501..115c94ba6 100644 --- a/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts +++ b/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts @@ -379,7 +379,7 @@ export class DefaultGraphicService implements IGraphicService { if (!(graphic.valid && visible)) { // application.graphicService.beforeUpdateAABBBounds(graphic, graphic.stage, true, aabbBounds); if (!aabbBounds.empty()) { - aabbBounds.transformWithMatrix((graphic.parent as IGroup).globalTransMatrix); + graphic.parent && aabbBounds.transformWithMatrix((graphic.parent as IGroup).globalTransMatrix); application.graphicService.clearAABBBounds(graphic, graphic.stage, aabbBounds); aabbBounds.clear(); } From b293c4c30ef6688cc6b00cedbc97aba3f302a57a Mon Sep 17 00:00:00 2001 From: zhouxinyu Date: Sat, 12 Oct 2024 15:58:25 +0800 Subject: [PATCH 05/14] fix: group bounds valid check ignore visible --- .../src/graphic/graphic-service/graphic-service.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts b/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts index 115c94ba6..a184ff5bf 100644 --- a/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts +++ b/packages/vrender-core/src/graphic/graphic-service/graphic-service.ts @@ -370,7 +370,8 @@ export class DefaultGraphicService implements IGraphicService { return true; } - if (graphic.shadowRoot) { + // 是Group或者有影子节点的话,就直接认为是合法的 + if (graphic.shadowRoot || graphic.isContainer) { return true; } From db0155eee6037c41cd8f65c6f2bfac83a2a097bc Mon Sep 17 00:00:00 2001 From: neuqzxy Date: Wed, 16 Oct 2024 03:15:54 +0000 Subject: [PATCH 06/14] build: prelease version 0.21.0-alpha.2 --- common/config/rush/pnpm-lock.yaml | 26 +++++++++++------------ common/config/rush/version-policies.json | 2 +- docs/package.json | 2 +- packages/react-vrender-utils/package.json | 6 +++--- packages/react-vrender/package.json | 4 ++-- packages/vrender-components/package.json | 6 +++--- packages/vrender-core/package.json | 2 +- packages/vrender-kits/package.json | 4 ++-- packages/vrender/package.json | 6 +++--- tools/bugserver-trigger/package.json | 8 +++---- 10 files changed, 33 insertions(+), 33 deletions(-) diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 817588127..e96208e3f 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -14,7 +14,7 @@ importers: '@types/react-dom': ^18.0.0 '@visactor/vchart': 1.3.0 '@visactor/vgrammar': ~0.5.7 - '@visactor/vrender': workspace:0.20.9 + '@visactor/vrender': workspace:0.21.0-alpha.2 '@visactor/vutils': ~0.18.17 '@vitejs/plugin-react': 3.1.0 axios: ^1.4.0 @@ -71,7 +71,7 @@ importers: '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 '@types/react-reconciler': ^0.28.2 - '@visactor/vrender': workspace:0.20.9 + '@visactor/vrender': workspace:0.21.0-alpha.2 '@visactor/vutils': ~0.18.17 '@vitejs/plugin-react': 3.1.0 cross-env: ^7.0.3 @@ -111,8 +111,8 @@ importers: '@rushstack/eslint-patch': ~1.1.4 '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 - '@visactor/react-vrender': workspace:0.20.9 - '@visactor/vrender': workspace:0.20.9 + '@visactor/react-vrender': workspace:0.21.0-alpha.2 + '@visactor/vrender': workspace:0.21.0-alpha.2 '@visactor/vutils': ~0.18.17 '@vitejs/plugin-react': 3.1.0 cross-env: ^7.0.3 @@ -153,8 +153,8 @@ importers: '@types/jest': ^26.0.0 '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 - '@visactor/vrender-core': workspace:0.20.9 - '@visactor/vrender-kits': workspace:0.20.9 + '@visactor/vrender-core': workspace:0.21.0-alpha.2 + '@visactor/vrender-kits': workspace:0.21.0-alpha.2 '@visactor/vutils': ~0.18.17 '@vitejs/plugin-react': 3.1.0 canvas: 2.11.2 @@ -200,8 +200,8 @@ importers: '@internal/ts-config': workspace:* '@rushstack/eslint-patch': ~1.1.4 '@types/jest': ^26.0.0 - '@visactor/vrender-core': workspace:0.20.9 - '@visactor/vrender-kits': workspace:0.20.9 + '@visactor/vrender-core': workspace:0.21.0-alpha.2 + '@visactor/vrender-kits': workspace:0.21.0-alpha.2 '@visactor/vscale': ~0.18.17 '@visactor/vutils': ~0.18.17 cross-env: ^7.0.3 @@ -287,7 +287,7 @@ importers: '@types/node-fetch': 2.6.4 '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 - '@visactor/vrender-core': workspace:0.20.9 + '@visactor/vrender-core': workspace:0.21.0-alpha.2 '@visactor/vutils': ~0.18.17 '@vitejs/plugin-react': 3.1.0 canvas: 2.11.2 @@ -369,10 +369,10 @@ importers: '@rushstack/eslint-patch': ~1.1.4 '@types/node': '*' '@types/node-fetch': 2.6.4 - '@visactor/vrender': workspace:0.20.9 - '@visactor/vrender-components': workspace:0.20.9 - '@visactor/vrender-core': workspace:0.20.9 - '@visactor/vrender-kits': workspace:0.20.9 + '@visactor/vrender': workspace:0.21.0-alpha.2 + '@visactor/vrender-components': workspace:0.21.0-alpha.2 + '@visactor/vrender-core': workspace:0.21.0-alpha.2 + '@visactor/vrender-kits': workspace:0.21.0-alpha.2 cross-env: ^7.0.3 eslint: ~8.18.0 form-data: ~4.0.0 diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json index b14988c71..abe6bf99f 100644 --- a/common/config/rush/version-policies.json +++ b/common/config/rush/version-policies.json @@ -1 +1 @@ -[{"definitionName":"lockStepVersion","policyName":"vrenderMain","version":"0.20.9","nextBump":"patch"}] +[{"definitionName":"lockStepVersion","policyName":"vrenderMain","version":"0.20.9","nextBump":"minor"}] diff --git a/docs/package.json b/docs/package.json index c73efafa9..048d719a9 100644 --- a/docs/package.json +++ b/docs/package.json @@ -13,7 +13,7 @@ "@visactor/vchart": "1.3.0", "@visactor/vutils": "~0.18.17", "@visactor/vgrammar": "~0.5.7", - "@visactor/vrender": "workspace:0.20.9", + "@visactor/vrender": "workspace:0.21.0-alpha.2", "markdown-it": "^13.0.0", "highlight.js": "^11.8.0", "axios": "^1.4.0", diff --git a/packages/react-vrender-utils/package.json b/packages/react-vrender-utils/package.json index 8bbdb1f6c..973a303d2 100644 --- a/packages/react-vrender-utils/package.json +++ b/packages/react-vrender-utils/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/react-vrender-utils", - "version": "0.20.9", + "version": "0.21.0-alpha.2", "description": "", "sideEffects": false, "main": "cjs/index.js", @@ -24,8 +24,8 @@ "react-dom": "^18.2.0" }, "dependencies": { - "@visactor/vrender": "workspace:0.20.9", - "@visactor/react-vrender": "workspace:0.20.9", + "@visactor/vrender": "workspace:0.21.0-alpha.2", + "@visactor/react-vrender": "workspace:0.21.0-alpha.2", "@visactor/vutils": "~0.18.17", "react-reconciler": "^0.29.0", "tslib": "^2.3.1" diff --git a/packages/react-vrender/package.json b/packages/react-vrender/package.json index e466816fe..46620f0f4 100644 --- a/packages/react-vrender/package.json +++ b/packages/react-vrender/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/react-vrender", - "version": "0.20.9", + "version": "0.21.0-alpha.2", "description": "", "sideEffects": false, "main": "cjs/index.js", @@ -23,7 +23,7 @@ "react": "^18.2.0" }, "dependencies": { - "@visactor/vrender": "workspace:0.20.9", + "@visactor/vrender": "workspace:0.21.0-alpha.2", "@visactor/vutils": "~0.18.17", "react-reconciler": "^0.29.0", "tslib": "^2.3.1" diff --git a/packages/vrender-components/package.json b/packages/vrender-components/package.json index b3f7b5994..d6240b0f6 100644 --- a/packages/vrender-components/package.json +++ b/packages/vrender-components/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vrender-components", - "version": "0.20.9", + "version": "0.21.0-alpha.2", "description": "components library for dp visualization", "sideEffects": false, "main": "cjs/index.js", @@ -26,8 +26,8 @@ "dependencies": { "@visactor/vutils": "~0.18.17", "@visactor/vscale": "~0.18.17", - "@visactor/vrender-core": "workspace:0.20.9", - "@visactor/vrender-kits": "workspace:0.20.9" + "@visactor/vrender-core": "workspace:0.21.0-alpha.2", + "@visactor/vrender-kits": "workspace:0.21.0-alpha.2" }, "devDependencies": { "@internal/bundler": "workspace:*", diff --git a/packages/vrender-core/package.json b/packages/vrender-core/package.json index bc1fc2927..66d4e394c 100644 --- a/packages/vrender-core/package.json +++ b/packages/vrender-core/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vrender-core", - "version": "0.20.9", + "version": "0.21.0-alpha.2", "description": "", "sideEffects": [ "./src/modules.ts", diff --git a/packages/vrender-kits/package.json b/packages/vrender-kits/package.json index f31c24184..d305fc310 100644 --- a/packages/vrender-kits/package.json +++ b/packages/vrender-kits/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vrender-kits", - "version": "0.20.9", + "version": "0.21.0-alpha.2", "description": "", "sideEffects": false, "main": "cjs/index.js", @@ -21,7 +21,7 @@ }, "dependencies": { "@visactor/vutils": "~0.18.17", - "@visactor/vrender-core": "workspace:0.20.9", + "@visactor/vrender-core": "workspace:0.21.0-alpha.2", "@resvg/resvg-js": "2.4.1", "roughjs": "4.5.2" }, diff --git a/packages/vrender/package.json b/packages/vrender/package.json index fc16f3f3e..619b1d3f7 100644 --- a/packages/vrender/package.json +++ b/packages/vrender/package.json @@ -1,6 +1,6 @@ { "name": "@visactor/vrender", - "version": "0.20.9", + "version": "0.21.0-alpha.2", "description": "", "sideEffects": true, "main": "cjs/index.js", @@ -24,8 +24,8 @@ "test-watch": "cross-env DEBUG_MODE=1 jest --watch" }, "dependencies": { - "@visactor/vrender-core": "workspace:0.20.9", - "@visactor/vrender-kits": "workspace:0.20.9" + "@visactor/vrender-core": "workspace:0.21.0-alpha.2", + "@visactor/vrender-kits": "workspace:0.21.0-alpha.2" }, "devDependencies": { "@internal/bundler": "workspace:*", diff --git a/tools/bugserver-trigger/package.json b/tools/bugserver-trigger/package.json index 84cee3fbe..9890f8277 100644 --- a/tools/bugserver-trigger/package.json +++ b/tools/bugserver-trigger/package.json @@ -8,10 +8,10 @@ "ci": "ts-node --transpileOnly --skipProject ./scripts/trigger-test.ts" }, "dependencies": { - "@visactor/vrender": "workspace:0.20.9", - "@visactor/vrender-core": "workspace:0.20.9", - "@visactor/vrender-kits": "workspace:0.20.9", - "@visactor/vrender-components": "workspace:0.20.9" + "@visactor/vrender": "workspace:0.21.0-alpha.2", + "@visactor/vrender-core": "workspace:0.21.0-alpha.2", + "@visactor/vrender-kits": "workspace:0.21.0-alpha.2", + "@visactor/vrender-components": "workspace:0.21.0-alpha.2" }, "devDependencies": { "@rushstack/eslint-patch": "~1.1.4", From 1ca4b7098b94febd7f380d30f95e6f9f76188fcf Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Wed, 13 Nov 2024 15:41:54 +0800 Subject: [PATCH 07/14] feat: add gifImage in vrender-components --- common/config/rush/pnpm-lock.yaml | 12 ++ .../__tests__/browser/examples/gif.ts | 49 +++++++ .../__tests__/browser/main.ts | 4 + .../__tests__/browser/sources/loading-1.gif | Bin 0 -> 11698 bytes .../__tests__/browser/sources/loading.gif | Bin 0 -> 10402 bytes packages/vrender-components/package.json | 3 +- packages/vrender-components/src/gif/gif.ts | 134 ++++++++++++++++++ packages/vrender-components/src/gif/index.ts | 1 + packages/vrender-components/src/index.ts | 1 + .../image-contribution-render.ts | 34 +++-- .../contributions/render/image-render.ts | 27 ++-- .../src/resource-loader/loader.ts | 4 +- 12 files changed, 239 insertions(+), 30 deletions(-) create mode 100644 packages/vrender-components/__tests__/browser/examples/gif.ts create mode 100644 packages/vrender-components/__tests__/browser/sources/loading-1.gif create mode 100644 packages/vrender-components/__tests__/browser/sources/loading.gif create mode 100644 packages/vrender-components/src/gif/gif.ts create mode 100644 packages/vrender-components/src/gif/index.ts diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index aa7b8c1cf..940b7ccec 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -206,6 +206,7 @@ importers: '@visactor/vutils': ~0.18.18 cross-env: ^7.0.3 eslint: ~8.18.0 + gifuct-js: 2.1.2 jest: ^26.0.0 jest-electron: ^0.1.12 lil-gui: ^0.17.0 @@ -217,6 +218,7 @@ importers: '@visactor/vrender-kits': link:../vrender-kits '@visactor/vscale': 0.18.18 '@visactor/vutils': 0.18.18 + gifuct-js: 2.1.2 devDependencies: '@internal/bundler': link:../../tools/bundler '@internal/eslint-config': link:../../share/eslint-config @@ -6348,6 +6350,12 @@ packages: assert-plus: 1.0.0 dev: true + /gifuct-js/2.1.2: + resolution: {integrity: sha512-rI2asw77u0mGgwhV3qA+OEgYqaDn5UNqgs+Bx0FGwSpuqfYn+Ir6RQY5ENNQ8SbIiG/m5gVa7CD5RriO4f4Lsg==} + dependencies: + js-binary-schema-parser: 2.0.3 + dev: false + /glob-parent/3.1.0: resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} dependencies: @@ -8261,6 +8269,10 @@ packages: - ts-node - utf-8-validate + /js-binary-schema-parser/2.0.3: + resolution: {integrity: sha512-xezGJmOb4lk/M1ZZLTR/jaBHQ4gG/lqQnJqdIv4721DMggsa1bDVlHXNeHYogaIEHD9vCRv0fcL4hMA+Coarkg==} + dev: false + /js-string-escape/1.0.1: resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} engines: {node: '>= 0.8'} diff --git a/packages/vrender-components/__tests__/browser/examples/gif.ts b/packages/vrender-components/__tests__/browser/examples/gif.ts new file mode 100644 index 000000000..1169a0f37 --- /dev/null +++ b/packages/vrender-components/__tests__/browser/examples/gif.ts @@ -0,0 +1,49 @@ +import '@visactor/vrender'; +import render from '../../util/render'; +import { GifImage, IGifImageGraphicAttribute } from '../../../src'; + +export function run() { + const radios: GifImage[] = []; + + radios.push( + new GifImage({ + x: 100, + y: 100, + width: 50, + height: 50, + gifImage: './sources/loading.gif' + } as IGifImageGraphicAttribute) + ); + + radios.push( + new GifImage({ + x: 200, + y: 100, + width: 50, + height: 50, + gifImage: './sources/loading.gif' + } as IGifImageGraphicAttribute) + ); + + radios.push( + new GifImage({ + x: 100, + y: 200, + width: 50, + height: 50, + gifImage: './sources/loading-1.gif' + } as IGifImageGraphicAttribute) + ); + + radios.push( + new GifImage({ + x: 200, + y: 200, + width: 50, + height: 50, + gifImage: './sources/loading-1.gif' + } as IGifImageGraphicAttribute) + ); + + const stage = render(radios, 'main'); +} diff --git a/packages/vrender-components/__tests__/browser/main.ts b/packages/vrender-components/__tests__/browser/main.ts index 595d01510..d7a43b928 100644 --- a/packages/vrender-components/__tests__/browser/main.ts +++ b/packages/vrender-components/__tests__/browser/main.ts @@ -285,6 +285,10 @@ const specs = [ { path: 'timeline', name: 'timeline' + }, + { + path: 'gif', + name: 'gif' } ]; diff --git a/packages/vrender-components/__tests__/browser/sources/loading-1.gif b/packages/vrender-components/__tests__/browser/sources/loading-1.gif new file mode 100644 index 0000000000000000000000000000000000000000..20ac5cb44a0e62e1e8839c309f50f3204ce7e0b3 GIT binary patch literal 11698 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 literal 0 HcmV?d00001 diff --git a/packages/vrender-components/package.json b/packages/vrender-components/package.json index d6c23e0a1..ce8bbaba8 100644 --- a/packages/vrender-components/package.json +++ b/packages/vrender-components/package.json @@ -27,7 +27,8 @@ "@visactor/vutils": "~0.18.18", "@visactor/vscale": "~0.18.18", "@visactor/vrender-core": "workspace:0.20.12", - "@visactor/vrender-kits": "workspace:0.20.12" + "@visactor/vrender-kits": "workspace:0.20.12", + "gifuct-js": "2.1.2" }, "devDependencies": { "@internal/bundler": "workspace:*", diff --git a/packages/vrender-components/src/gif/gif.ts b/packages/vrender-components/src/gif/gif.ts new file mode 100644 index 000000000..e46b3fadc --- /dev/null +++ b/packages/vrender-components/src/gif/gif.ts @@ -0,0 +1,134 @@ +import type { IImageGraphicAttribute } from '@visactor/vrender-core'; +import { application, Image, ResourceLoader } from '@visactor/vrender-core'; +import type { ITimeline } from '@visactor/vrender-core'; +import { isString } from '@visactor/vutils'; +import type { ParsedFrame } from 'gifuct-js'; +import { decompressFrames, parseGIF } from 'gifuct-js'; + +export interface IGifImageGraphicAttribute extends IImageGraphicAttribute { + timeline?: ITimeline; + gifImage?: string | ArrayBuffer; +} + +export class GifImage extends Image { + declare attribute: IGifImageGraphicAttribute; + + frameImageData?: ImageData; + tempCanvas?: HTMLCanvasElement; + tempCtx?: CanvasRenderingContext2D; + gifCanvas?: HTMLCanvasElement; + gifCtx?: CanvasRenderingContext2D; + loadedFrames?: ParsedFrame[]; + frameIndex?: number; + playing?: boolean; + lastTime?: number; + + isGifImage = true; + + constructor(params: IGifImageGraphicAttribute) { + super(params); + + if (isString(this.attribute.gifImage)) { + ResourceLoader.GetFile(this.attribute.gifImage, 'arrayBuffer') + .then((res: ArrayBuffer) => { + const gif = parseGIF(res); + const frames = decompressFrames(gif, true); + this.renderGIF(frames); + }) + .catch(e => { + console.error('Gif load error: ', e); + }); + } else if (this.attribute.gifImage instanceof ArrayBuffer) { + const gif = parseGIF(this.attribute.gifImage); + const frames = decompressFrames(gif, true); + this.renderGIF(frames); + } + } + + renderGIF(frames: ParsedFrame[]) { + this.loadedFrames = frames; + this.frameIndex = 0; + + if (!this.tempCanvas) { + this.tempCanvas = application.global.createCanvas({}); + this.tempCtx = this.tempCanvas.getContext('2d'); + } + + if (!this.gifCanvas) { + this.gifCanvas = application.global.createCanvas({}); + this.gifCtx = this.gifCanvas.getContext('2d'); + } + + this.gifCanvas.width = frames[0].dims.width; + this.gifCanvas.height = frames[0].dims.height; + + this.playing = true; + this.lastTime = new Date().getTime(); + const animation = this.animate(); + if (this.attribute.timeline) { + animation.setTimeline(this.attribute.timeline); + } + animation.to({}, 1000, 'linear').loop(Infinity); + } + + renderFrame(context: CanvasRenderingContext2D, x: number, y: number) { + // get the frame + const frame = this.loadedFrames[this.frameIndex || 0]; + + if (frame.disposalType === 2) { + this.gifCtx.clearRect(0, 0, this.attribute.width, this.attribute.height); + } + + // draw image into gifCanvas + this.drawPatch(frame); + + // draw gifCanvas into stage + this.manipulate(context, x, y); + + // update the frame index + const diff = new Date().getTime() - this.lastTime; + if (frame.delay < diff) { + this.frameIndex++; + this.lastTime = new Date().getTime(); + } + if (this.frameIndex >= this.loadedFrames.length) { + this.frameIndex = 0; + } + } + + drawPatch(frame: ParsedFrame) { + const dims = frame.dims; + + if ( + !this.frameImageData || + dims.width !== this.frameImageData.width || + dims.height !== this.frameImageData.height + ) { + this.tempCanvas.width = dims.width; + this.tempCanvas.height = dims.height; + this.frameImageData = this.tempCtx.createImageData(dims.width, dims.height); + } + + // set the patch data as an override + this.frameImageData.data.set(frame.patch); + + // draw the patch back over the canvas + this.tempCtx.putImageData(this.frameImageData, 0, 0); + + this.gifCtx.drawImage(this.tempCanvas, dims.left, dims.top); + } + + manipulate(context: CanvasRenderingContext2D, x: number, y: number) { + context.drawImage( + this.gifCanvas, + 0, + 0, + this.gifCanvas.width, + this.gifCanvas.height, + x, + y, + this.attribute.width, + this.attribute.height + ); + } +} diff --git a/packages/vrender-components/src/gif/index.ts b/packages/vrender-components/src/gif/index.ts new file mode 100644 index 000000000..e595f706d --- /dev/null +++ b/packages/vrender-components/src/gif/index.ts @@ -0,0 +1 @@ +export * from './gif'; diff --git a/packages/vrender-components/src/index.ts b/packages/vrender-components/src/index.ts index 7e3f5da76..681a77ab0 100644 --- a/packages/vrender-components/src/index.ts +++ b/packages/vrender-components/src/index.ts @@ -29,3 +29,4 @@ export * from './checkbox'; export * from './radio'; export * from './empty-tip'; export * from './util'; +export * from './gif'; diff --git a/packages/vrender-core/src/render/contributions/render/contributions/image-contribution-render.ts b/packages/vrender-core/src/render/contributions/render/contributions/image-contribution-render.ts index 9fecb04a2..804645506 100644 --- a/packages/vrender-core/src/render/contributions/render/contributions/image-contribution-render.ts +++ b/packages/vrender-core/src/render/contributions/render/contributions/image-contribution-render.ts @@ -144,7 +144,7 @@ export class DefaultImageRenderContribution extends DefaultRectRenderContributio useStyle: boolean = true; order: number = 0; drawShape( - rect: any, + image: any, context: IContext2d, x: number, y: number, @@ -165,20 +165,24 @@ export class DefaultImageRenderContribution extends DefaultRectRenderContributio themeAttribute: IThemeAttribute ) => boolean ) { - return super.drawShape( - rect, - context, - x, - y, - doFill, - doStroke, - fVisible, - sVisible, - rectAttribute, - drawContext, - fillCb, - strokeCb - ); + if (image.isGifImage && image.renderFrame && image.playing) { + image.renderFrame(context, x, y); + } else { + return super.drawShape( + image, + context, + x, + y, + doFill, + doStroke, + fVisible, + sVisible, + rectAttribute, + drawContext, + fillCb, + strokeCb + ); + } } } diff --git a/packages/vrender-core/src/render/contributions/render/image-render.ts b/packages/vrender-core/src/render/contributions/render/image-render.ts index 71aaa4b17..8267d6911 100644 --- a/packages/vrender-core/src/render/contributions/render/image-render.ts +++ b/packages/vrender-core/src/render/contributions/render/image-render.ts @@ -162,18 +162,21 @@ export class DefaultCanvasImageRender extends BaseRender implements IGra draw(image: IImage, renderService: IRenderService, drawContext: IDrawContext) { const { image: url } = image.attribute; - if (!url || !image.resources) { - return; - } - const res = image.resources.get(url); - // if (res.state !== 'success') { - // return; - // } - if (res.state === 'loading' && isString(url)) { - ResourceLoader.improveImageLoading(url); - return; - } else if (res.state !== 'success') { - return; + + if (!image.isGifImage) { + if (!url || !image.resources) { + return; + } + const res = image.resources.get(url); + // if (res.state !== 'success') { + // return; + // } + if (res.state === 'loading' && isString(url)) { + ResourceLoader.improveImageLoading(url); + return; + } else if (res.state !== 'success') { + return; + } } const { context } = renderService.drawParams; diff --git a/packages/vrender-core/src/resource-loader/loader.ts b/packages/vrender-core/src/resource-loader/loader.ts index 55c779829..f40326744 100644 --- a/packages/vrender-core/src/resource-loader/loader.ts +++ b/packages/vrender-core/src/resource-loader/loader.ts @@ -108,9 +108,9 @@ export class ResourceLoader { let data = ResourceLoader.cache.get(url); if (data) { // 存在缓存 - if (data.loadState === 'init' || data.loadState === 'fail') { + if (data.loadState === 'fail') { return Promise.reject(); - } else if (data.loadState === 'loading') { + } else if (data.loadState === 'init' || data.loadState === 'loading') { return data.dataPromise.then(data => data.data); } return Promise.resolve(data.data); From 45b6b26727798c3ca6dac88436ee47549186451f Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Wed, 13 Nov 2024 17:10:07 +0800 Subject: [PATCH 08/14] docs: add disableAutoClipedPoptip in text documentation --- docs/assets/api/en/common/text.md | 4 ++++ docs/assets/api/zh/common/text.md | 4 ++++ docs/assets/option/en/common/text.md | 4 ++++ docs/assets/option/zh/common/text.md | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/docs/assets/api/en/common/text.md b/docs/assets/api/en/common/text.md index d28e2e8df..c21774b92 100644 --- a/docs/assets/api/en/common/text.md +++ b/docs/assets/api/en/common/text.md @@ -36,3 +36,7 @@ Roboto,Helvetica,Arial,sans-serif, apple color emoji,segoe ui emoji,segoe ui sym #${prefix} lineThrough(number) = 0 中划线线粗 + +#${prefix} disableAutoClipedPoptip(boolean) = false + +禁用省略hover展示poptip \ No newline at end of file diff --git a/docs/assets/api/zh/common/text.md b/docs/assets/api/zh/common/text.md index d28e2e8df..c21774b92 100644 --- a/docs/assets/api/zh/common/text.md +++ b/docs/assets/api/zh/common/text.md @@ -36,3 +36,7 @@ Roboto,Helvetica,Arial,sans-serif, apple color emoji,segoe ui emoji,segoe ui sym #${prefix} lineThrough(number) = 0 中划线线粗 + +#${prefix} disableAutoClipedPoptip(boolean) = false + +禁用省略hover展示poptip \ No newline at end of file diff --git a/docs/assets/option/en/common/text.md b/docs/assets/option/en/common/text.md index d28e2e8df..c21774b92 100644 --- a/docs/assets/option/en/common/text.md +++ b/docs/assets/option/en/common/text.md @@ -36,3 +36,7 @@ Roboto,Helvetica,Arial,sans-serif, apple color emoji,segoe ui emoji,segoe ui sym #${prefix} lineThrough(number) = 0 中划线线粗 + +#${prefix} disableAutoClipedPoptip(boolean) = false + +禁用省略hover展示poptip \ No newline at end of file diff --git a/docs/assets/option/zh/common/text.md b/docs/assets/option/zh/common/text.md index d28e2e8df..c21774b92 100644 --- a/docs/assets/option/zh/common/text.md +++ b/docs/assets/option/zh/common/text.md @@ -36,3 +36,7 @@ Roboto,Helvetica,Arial,sans-serif, apple color emoji,segoe ui emoji,segoe ui sym #${prefix} lineThrough(number) = 0 中划线线粗 + +#${prefix} disableAutoClipedPoptip(boolean) = false + +禁用省略hover展示poptip \ No newline at end of file From 2c6759e49c84e39b20b0b4346aaa89d78330d5b5 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Wed, 13 Nov 2024 19:28:11 +0800 Subject: [PATCH 09/14] feat: add update in gif-image component --- packages/vrender-components/src/gif/gif.ts | 24 +++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/vrender-components/src/gif/gif.ts b/packages/vrender-components/src/gif/gif.ts index e46b3fadc..eac331cd1 100644 --- a/packages/vrender-components/src/gif/gif.ts +++ b/packages/vrender-components/src/gif/gif.ts @@ -1,4 +1,4 @@ -import type { IImageGraphicAttribute } from '@visactor/vrender-core'; +import type { IImageGraphicAttribute, ISetAttributeContext } from '@visactor/vrender-core'; import { application, Image, ResourceLoader } from '@visactor/vrender-core'; import type { ITimeline } from '@visactor/vrender-core'; import { isString } from '@visactor/vutils'; @@ -28,6 +28,10 @@ export class GifImage extends Image { constructor(params: IGifImageGraphicAttribute) { super(params); + this.loadGif(); + } + + loadGif() { if (isString(this.attribute.gifImage)) { ResourceLoader.GetFile(this.attribute.gifImage, 'arrayBuffer') .then((res: ArrayBuffer) => { @@ -131,4 +135,22 @@ export class GifImage extends Image { this.attribute.height ); } + + setAttribute(key: string, value: any, forceUpdateTag?: boolean, context?: ISetAttributeContext): void { + super.setAttribute(key, value, forceUpdateTag, context); + if (key === 'gifImage') { + this.loadGif(); + } + } + + setAttributes( + params: Partial, + forceUpdateTag?: boolean, + context?: ISetAttributeContext + ): void { + super.setAttributes(params, forceUpdateTag, context); + if (params.gifImage) { + this.loadGif(); + } + } } From 3a7e86df814da2450926a731b6c96fe55924e344 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Wed, 13 Nov 2024 20:34:36 +0800 Subject: [PATCH 10/14] fix: fix gif-canvas clear in GifImage --- packages/vrender-components/src/gif/gif.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vrender-components/src/gif/gif.ts b/packages/vrender-components/src/gif/gif.ts index eac331cd1..0b10bddcc 100644 --- a/packages/vrender-components/src/gif/gif.ts +++ b/packages/vrender-components/src/gif/gif.ts @@ -80,7 +80,7 @@ export class GifImage extends Image { const frame = this.loadedFrames[this.frameIndex || 0]; if (frame.disposalType === 2) { - this.gifCtx.clearRect(0, 0, this.attribute.width, this.attribute.height); + this.gifCtx.clearRect(0, 0, this.gifCanvas.width, this.gifCanvas.height); } // draw image into gifCanvas From 9f1f39c2ffac5c1b1f1dfaf36d19fac382d01e09 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Thu, 14 Nov 2024 15:44:14 +0800 Subject: [PATCH 11/14] feat: add animation & name in JSX --- packages/vrender-kits/src/jsx/jsx-classic.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/vrender-kits/src/jsx/jsx-classic.ts b/packages/vrender-kits/src/jsx/jsx-classic.ts index ad56ff823..f6ea0fdb2 100644 --- a/packages/vrender-kits/src/jsx/jsx-classic.ts +++ b/packages/vrender-kits/src/jsx/jsx-classic.ts @@ -10,7 +10,7 @@ function flatten(list: any, out: any[]): void { } export function jsx(type: string | any, config: Record, ...children: any) { - const { key, name, id, attribute, stateProxy, ...props } = config || {}; + const { key, name, id, attribute, stateProxy, animation, timeline, ...props } = config || {}; let c = type; if (isString(type)) { @@ -29,6 +29,22 @@ export function jsx(type: string | any, config: Record, ...children g.stateProxy = stateProxy; } + if (name) { + g.name = name; + } + + if (isArray(animation)) { + // animation={[ + // ['to', { angle: 2 * Math.PI }, 1000, 'linear'], + // ['loop', Infinity] + // ]} + const animate = g.animate(); + timeline && animate.setTimeline(timeline); + animation.forEach((item: any[]) => { + animate[item[0]](...item.slice(1)); + }); + } + return g; } From 7e6f13386404b038fb320403c22b283777911d14 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Thu, 14 Nov 2024 16:34:01 +0800 Subject: [PATCH 12/14] chore: add rush change --- .../feat-gif-image_2024-11-14-08-33.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 common/changes/@visactor/vrender-components/feat-gif-image_2024-11-14-08-33.json diff --git a/common/changes/@visactor/vrender-components/feat-gif-image_2024-11-14-08-33.json b/common/changes/@visactor/vrender-components/feat-gif-image_2024-11-14-08-33.json new file mode 100644 index 000000000..beccac877 --- /dev/null +++ b/common/changes/@visactor/vrender-components/feat-gif-image_2024-11-14-08-33.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@visactor/vrender-components", + "comment": "feat: add GifImage component", + "type": "none" + } + ], + "packageName": "@visactor/vrender-components" +} \ No newline at end of file From 6148c392efc22dccbb89fa6b07eaecf5cec3b3af Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Mon, 18 Nov 2024 14:47:11 +0800 Subject: [PATCH 13/14] feat: move GifImage from vrender-components to vrender-kits --- common/config/rush/pnpm-lock.yaml | 4 +- .../__tests__/browser/examples/gif.ts | 49 ---------- .../__tests__/browser/main.ts | 4 - packages/vrender-components/package.json | 3 +- packages/vrender-components/src/gif/index.ts | 1 - packages/vrender-components/src/index.ts | 1 - .../vrender-core/src/interface/graphic.ts | 3 +- .../image-contribution-render.ts | 32 +++---- .../contributions/render/image-render.ts | 26 +++--- packages/vrender-kits/package.json | 3 +- .../vrender-kits/src/graphic/constants.ts | 3 + .../src/graphic/gif-image.ts} | 18 ++-- packages/vrender-kits/src/index.ts | 4 + .../vrender-kits/src/interface/gif-image.ts | 19 ++++ .../canvas-picker/gif-image-module.ts | 14 +++ .../canvas-picker/gif-image-picker.ts | 31 +++++++ .../src/picker/contributions/constants.ts | 1 + .../contributions/canvas/gif-image-module.ts | 13 +++ .../contributions/canvas/gif-image-render.ts | 87 ++++++++++++++++++ .../__tests__/browser/sources/loading-1.gif | Bin 0 -> 11698 bytes .../__tests__/browser/sources/loading.gif | Bin 0 -> 10402 bytes .../__tests__/browser/src/pages/gif-image.ts | 64 +++++++++++++ .../__tests__/browser/src/pages/index.ts | 4 + 23 files changed, 282 insertions(+), 102 deletions(-) delete mode 100644 packages/vrender-components/__tests__/browser/examples/gif.ts delete mode 100644 packages/vrender-components/src/gif/index.ts create mode 100644 packages/vrender-kits/src/graphic/constants.ts rename packages/{vrender-components/src/gif/gif.ts => vrender-kits/src/graphic/gif-image.ts} (91%) create mode 100644 packages/vrender-kits/src/interface/gif-image.ts create mode 100644 packages/vrender-kits/src/picker/contributions/canvas-picker/gif-image-module.ts create mode 100644 packages/vrender-kits/src/picker/contributions/canvas-picker/gif-image-picker.ts create mode 100644 packages/vrender-kits/src/render/contributions/canvas/gif-image-module.ts create mode 100644 packages/vrender-kits/src/render/contributions/canvas/gif-image-render.ts create mode 100644 packages/vrender/__tests__/browser/sources/loading-1.gif create mode 100644 packages/vrender/__tests__/browser/sources/loading.gif create mode 100644 packages/vrender/__tests__/browser/src/pages/gif-image.ts diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 5dfdceee1..d8b047d61 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -206,7 +206,6 @@ importers: '@visactor/vutils': ~0.18.17 cross-env: ^7.0.3 eslint: ~8.18.0 - gifuct-js: 2.1.2 jest: ^26.0.0 jest-electron: ^0.1.12 lil-gui: ^0.17.0 @@ -218,7 +217,6 @@ importers: '@visactor/vrender-kits': link:../vrender-kits '@visactor/vscale': 0.18.18 '@visactor/vutils': 0.18.18 - gifuct-js: 2.1.2 devDependencies: '@internal/bundler': link:../../tools/bundler '@internal/eslint-config': link:../../share/eslint-config @@ -295,6 +293,7 @@ importers: canvas: 2.11.2 cross-env: ^7.0.3 eslint: ~8.18.0 + gifuct-js: 2.1.2 node-fetch: 2.6.6 react: ^18.0.0 react-dom: ^18.0.0 @@ -305,6 +304,7 @@ importers: '@resvg/resvg-js': 2.4.1 '@visactor/vrender-core': link:../vrender-core '@visactor/vutils': 0.18.18 + gifuct-js: 2.1.2 roughjs: 4.5.2 devDependencies: '@internal/bundler': link:../../tools/bundler diff --git a/packages/vrender-components/__tests__/browser/examples/gif.ts b/packages/vrender-components/__tests__/browser/examples/gif.ts deleted file mode 100644 index 1169a0f37..000000000 --- a/packages/vrender-components/__tests__/browser/examples/gif.ts +++ /dev/null @@ -1,49 +0,0 @@ -import '@visactor/vrender'; -import render from '../../util/render'; -import { GifImage, IGifImageGraphicAttribute } from '../../../src'; - -export function run() { - const radios: GifImage[] = []; - - radios.push( - new GifImage({ - x: 100, - y: 100, - width: 50, - height: 50, - gifImage: './sources/loading.gif' - } as IGifImageGraphicAttribute) - ); - - radios.push( - new GifImage({ - x: 200, - y: 100, - width: 50, - height: 50, - gifImage: './sources/loading.gif' - } as IGifImageGraphicAttribute) - ); - - radios.push( - new GifImage({ - x: 100, - y: 200, - width: 50, - height: 50, - gifImage: './sources/loading-1.gif' - } as IGifImageGraphicAttribute) - ); - - radios.push( - new GifImage({ - x: 200, - y: 200, - width: 50, - height: 50, - gifImage: './sources/loading-1.gif' - } as IGifImageGraphicAttribute) - ); - - const stage = render(radios, 'main'); -} diff --git a/packages/vrender-components/__tests__/browser/main.ts b/packages/vrender-components/__tests__/browser/main.ts index d7a43b928..595d01510 100644 --- a/packages/vrender-components/__tests__/browser/main.ts +++ b/packages/vrender-components/__tests__/browser/main.ts @@ -285,10 +285,6 @@ const specs = [ { path: 'timeline', name: 'timeline' - }, - { - path: 'gif', - name: 'gif' } ]; diff --git a/packages/vrender-components/package.json b/packages/vrender-components/package.json index 8a42021ba..d6240b0f6 100644 --- a/packages/vrender-components/package.json +++ b/packages/vrender-components/package.json @@ -27,8 +27,7 @@ "@visactor/vutils": "~0.18.17", "@visactor/vscale": "~0.18.17", "@visactor/vrender-core": "workspace:0.21.0-alpha.2", - "@visactor/vrender-kits": "workspace:0.21.0-alpha.2", - "gifuct-js": "2.1.2" + "@visactor/vrender-kits": "workspace:0.21.0-alpha.2" }, "devDependencies": { "@internal/bundler": "workspace:*", diff --git a/packages/vrender-components/src/gif/index.ts b/packages/vrender-components/src/gif/index.ts deleted file mode 100644 index e595f706d..000000000 --- a/packages/vrender-components/src/gif/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './gif'; diff --git a/packages/vrender-components/src/index.ts b/packages/vrender-components/src/index.ts index 681a77ab0..7e3f5da76 100644 --- a/packages/vrender-components/src/index.ts +++ b/packages/vrender-components/src/index.ts @@ -29,4 +29,3 @@ export * from './checkbox'; export * from './radio'; export * from './empty-tip'; export * from './util'; -export * from './gif'; diff --git a/packages/vrender-core/src/interface/graphic.ts b/packages/vrender-core/src/interface/graphic.ts index 63279cd60..10c59a413 100644 --- a/packages/vrender-core/src/interface/graphic.ts +++ b/packages/vrender-core/src/interface/graphic.ts @@ -38,7 +38,8 @@ export type GraphicType = | 'shadowroot' | 'polygon' | 'pyramid3d' - | 'glyph'; + | 'glyph' + | string; // Cursor style // See: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor diff --git a/packages/vrender-core/src/render/contributions/render/contributions/image-contribution-render.ts b/packages/vrender-core/src/render/contributions/render/contributions/image-contribution-render.ts index 804645506..84158e633 100644 --- a/packages/vrender-core/src/render/contributions/render/contributions/image-contribution-render.ts +++ b/packages/vrender-core/src/render/contributions/render/contributions/image-contribution-render.ts @@ -165,24 +165,20 @@ export class DefaultImageRenderContribution extends DefaultRectRenderContributio themeAttribute: IThemeAttribute ) => boolean ) { - if (image.isGifImage && image.renderFrame && image.playing) { - image.renderFrame(context, x, y); - } else { - return super.drawShape( - image, - context, - x, - y, - doFill, - doStroke, - fVisible, - sVisible, - rectAttribute, - drawContext, - fillCb, - strokeCb - ); - } + return super.drawShape( + image, + context, + x, + y, + doFill, + doStroke, + fVisible, + sVisible, + rectAttribute, + drawContext, + fillCb, + strokeCb + ); } } diff --git a/packages/vrender-core/src/render/contributions/render/image-render.ts b/packages/vrender-core/src/render/contributions/render/image-render.ts index 8267d6911..6c0316b9f 100644 --- a/packages/vrender-core/src/render/contributions/render/image-render.ts +++ b/packages/vrender-core/src/render/contributions/render/image-render.ts @@ -163,20 +163,18 @@ export class DefaultCanvasImageRender extends BaseRender implements IGra draw(image: IImage, renderService: IRenderService, drawContext: IDrawContext) { const { image: url } = image.attribute; - if (!image.isGifImage) { - if (!url || !image.resources) { - return; - } - const res = image.resources.get(url); - // if (res.state !== 'success') { - // return; - // } - if (res.state === 'loading' && isString(url)) { - ResourceLoader.improveImageLoading(url); - return; - } else if (res.state !== 'success') { - return; - } + if (!url || !image.resources) { + return; + } + const res = image.resources.get(url); + // if (res.state !== 'success') { + // return; + // } + if (res.state === 'loading' && isString(url)) { + ResourceLoader.improveImageLoading(url); + return; + } else if (res.state !== 'success') { + return; } const { context } = renderService.drawParams; diff --git a/packages/vrender-kits/package.json b/packages/vrender-kits/package.json index d305fc310..e825118fd 100644 --- a/packages/vrender-kits/package.json +++ b/packages/vrender-kits/package.json @@ -23,7 +23,8 @@ "@visactor/vutils": "~0.18.17", "@visactor/vrender-core": "workspace:0.21.0-alpha.2", "@resvg/resvg-js": "2.4.1", - "roughjs": "4.5.2" + "roughjs": "4.5.2", + "gifuct-js": "2.1.2" }, "devDependencies": { "@internal/bundler": "workspace:*", diff --git a/packages/vrender-kits/src/graphic/constants.ts b/packages/vrender-kits/src/graphic/constants.ts new file mode 100644 index 000000000..c234ac0eb --- /dev/null +++ b/packages/vrender-kits/src/graphic/constants.ts @@ -0,0 +1,3 @@ +import { Generator } from '@visactor/vrender-core'; + +export const GIFIMAGE_NUMBER_TYPE = Generator.GenAutoIncrementId(); diff --git a/packages/vrender-components/src/gif/gif.ts b/packages/vrender-kits/src/graphic/gif-image.ts similarity index 91% rename from packages/vrender-components/src/gif/gif.ts rename to packages/vrender-kits/src/graphic/gif-image.ts index 0b10bddcc..2e930233d 100644 --- a/packages/vrender-components/src/gif/gif.ts +++ b/packages/vrender-kits/src/graphic/gif-image.ts @@ -4,13 +4,11 @@ import type { ITimeline } from '@visactor/vrender-core'; import { isString } from '@visactor/vutils'; import type { ParsedFrame } from 'gifuct-js'; import { decompressFrames, parseGIF } from 'gifuct-js'; +import type { IGifImage, IGifImageGraphicAttribute } from '../interface/gif-image'; +import { GIFIMAGE_NUMBER_TYPE } from './constants'; -export interface IGifImageGraphicAttribute extends IImageGraphicAttribute { - timeline?: ITimeline; - gifImage?: string | ArrayBuffer; -} - -export class GifImage extends Image { +export class GifImage extends Image implements IGifImage { + type: any = 'gif-image'; declare attribute: IGifImageGraphicAttribute; frameImageData?: ImageData; @@ -23,11 +21,9 @@ export class GifImage extends Image { playing?: boolean; lastTime?: number; - isGifImage = true; - constructor(params: IGifImageGraphicAttribute) { super(params); - + this.numberType = GIFIMAGE_NUMBER_TYPE; this.loadGif(); } @@ -154,3 +150,7 @@ export class GifImage extends Image { } } } + +export function createGifImage(attributes: IGifImageGraphicAttribute): IGifImage { + return new GifImage(attributes); +} diff --git a/packages/vrender-kits/src/index.ts b/packages/vrender-kits/src/index.ts index 9a24112ec..6b68fef67 100644 --- a/packages/vrender-kits/src/index.ts +++ b/packages/vrender-kits/src/index.ts @@ -51,6 +51,10 @@ export * from './picker/contributions/canvas-picker/arc3d-module'; export * from './picker/contributions/canvas-picker/pyramid3d-module'; +export * from './graphic/gif-image'; +export * from './picker/contributions/canvas-picker/gif-image-module'; +export * from './render/contributions/canvas/gif-image-module'; + export * from './register/register-arc'; export * from './register/register-arc3d'; export * from './register/register-area'; diff --git a/packages/vrender-kits/src/interface/gif-image.ts b/packages/vrender-kits/src/interface/gif-image.ts new file mode 100644 index 000000000..891c3dbde --- /dev/null +++ b/packages/vrender-kits/src/interface/gif-image.ts @@ -0,0 +1,19 @@ +import type { IGraphic, IImageGraphicAttribute, ITimeline } from '@visactor/vrender-core'; +import type { ParsedFrame } from 'gifuct-js'; + +export interface IGifImageGraphicAttribute extends IImageGraphicAttribute { + timeline?: ITimeline; + gifImage?: string | ArrayBuffer; +} + +export interface IGifImage extends IGraphic { + frameImageData?: ImageData; + tempCanvas?: HTMLCanvasElement; + tempCtx?: CanvasRenderingContext2D; + gifCanvas?: HTMLCanvasElement; + gifCtx?: CanvasRenderingContext2D; + loadedFrames?: ParsedFrame[]; + frameIndex?: number; + playing?: boolean; + lastTime?: number; +} diff --git a/packages/vrender-kits/src/picker/contributions/canvas-picker/gif-image-module.ts b/packages/vrender-kits/src/picker/contributions/canvas-picker/gif-image-module.ts new file mode 100644 index 000000000..755c5eec0 --- /dev/null +++ b/packages/vrender-kits/src/picker/contributions/canvas-picker/gif-image-module.ts @@ -0,0 +1,14 @@ +import { ContainerModule } from '@visactor/vrender-core'; +import { CanvasGifImagePicker, CanvasPickerContribution } from '../constants'; +import { DefaultCanvasGifImagePicker } from './gif-image-picker'; + +let loadGifImagePick = false; +export const gifImageCanvasPickModule = new ContainerModule((bind, unbind, isBound, rebind) => { + if (loadGifImagePick) { + return; + } + loadGifImagePick = true; + // gifGifImage picker + bind(CanvasGifImagePicker).to(DefaultCanvasGifImagePicker).inSingletonScope(); + bind(CanvasPickerContribution).toService(CanvasGifImagePicker); +}); diff --git a/packages/vrender-kits/src/picker/contributions/canvas-picker/gif-image-picker.ts b/packages/vrender-kits/src/picker/contributions/canvas-picker/gif-image-picker.ts new file mode 100644 index 000000000..4a7634db5 --- /dev/null +++ b/packages/vrender-kits/src/picker/contributions/canvas-picker/gif-image-picker.ts @@ -0,0 +1,31 @@ +import type { IPoint } from '@visactor/vutils'; +import { injectable } from '@visactor/vrender-core'; +import type { IGraphicPicker, IPickParams } from '@visactor/vrender-core'; +import type { IGifImage } from '../../../interface/gif-image'; +import { GIFIMAGE_NUMBER_TYPE } from '../../../graphic/constants'; + +@injectable() +export class DefaultCanvasGifImagePicker implements IGraphicPicker { + type: string = 'gif-image'; + numberType: number = GIFIMAGE_NUMBER_TYPE; + + contains(gifImage: IGifImage, point: IPoint, params?: IPickParams): boolean { + // const { gifImageAttribute } = graphicService.themeService.getCurrentTheme(); + // const { + // x = gifImageAttribute.x, + // y = gifImageAttribute.y, + // } = gifImage.attribute; + + const { pickContext } = params ?? {}; + if (!pickContext) { + return false; + } + + if (!gifImage.AABBBounds.containsPoint(point)) { + return false; + } + + // TODO: 详细形状判断 + return true; + } +} diff --git a/packages/vrender-kits/src/picker/contributions/constants.ts b/packages/vrender-kits/src/picker/contributions/constants.ts index 4ce53d35b..f2c09d01f 100644 --- a/packages/vrender-kits/src/picker/contributions/constants.ts +++ b/packages/vrender-kits/src/picker/contributions/constants.ts @@ -19,6 +19,7 @@ export const CanvasArc3dPicker = Symbol.for('CanvasArc3dPicker'); export const CanvasAreaPicker = Symbol.for('CanvasAreaPicker'); export const CanvasCirclePicker = Symbol.for('CanvasCirclePicker'); export const CanvasImagePicker = Symbol.for('CanvasImagePicker'); +export const CanvasGifImagePicker = Symbol.for('CanvasGifImagePicker'); export const CanvasLinePicker = Symbol.for('CanvasLinePicker'); export const CanvasPathPicker = Symbol.for('CanvasPathPicker'); export const CanvasRectPicker = Symbol.for('CanvasRectPicker'); diff --git a/packages/vrender-kits/src/render/contributions/canvas/gif-image-module.ts b/packages/vrender-kits/src/render/contributions/canvas/gif-image-module.ts new file mode 100644 index 000000000..be568f750 --- /dev/null +++ b/packages/vrender-kits/src/render/contributions/canvas/gif-image-module.ts @@ -0,0 +1,13 @@ +import { ContainerModule, GraphicRender } from '@visactor/vrender-core'; +import { DefaultCanvasGifImageRender } from './gif-image-render'; + +let loadGifImageModule = false; +export const gifImageModule = new ContainerModule(bind => { + if (loadGifImageModule) { + return; + } + loadGifImageModule = true; + // gifImage渲染器 + bind(DefaultCanvasGifImageRender).toSelf().inSingletonScope(); + bind(GraphicRender).toService(DefaultCanvasGifImageRender); +}); diff --git a/packages/vrender-kits/src/render/contributions/canvas/gif-image-render.ts b/packages/vrender-kits/src/render/contributions/canvas/gif-image-render.ts new file mode 100644 index 000000000..d65f4976f --- /dev/null +++ b/packages/vrender-kits/src/render/contributions/canvas/gif-image-render.ts @@ -0,0 +1,87 @@ +import type { + IContext2d, + IContributionProvider, + IDrawContext, + IGraphicAttribute, + IGraphicRender, + IImageRenderContribution, + IMarkAttribute, + IRenderService, + IThemeAttribute +} from '@visactor/vrender-core'; +import { + BaseRenderContributionTime, + ContributionProvider, + DefaultCanvasImageRender, + DefaultRectRenderContribution, + getTheme, + ImageRenderContribution, + inject, + injectable, + named +} from '@visactor/vrender-core'; +import { GIFIMAGE_NUMBER_TYPE } from '../../../graphic/constants'; +import type { IGifImage } from '../../../interface/gif-image'; + +@injectable() +export class DefaultCanvasGifImageRender extends DefaultCanvasImageRender implements IGraphicRender { + type: 'image'; + numberType: number = GIFIMAGE_NUMBER_TYPE; + + constructor( + @inject(ContributionProvider) + @named(ImageRenderContribution) + protected readonly imageRenderContribitions: IContributionProvider + ) { + super(imageRenderContribitions); + this._renderContribitions = undefined; + this.builtinContributions = [defaultGifImageRenderContribution]; + this.init(imageRenderContribitions); + } + + draw(image: IGifImage, renderService: IRenderService, drawContext: IDrawContext) { + const { context } = renderService.drawParams; + if (!context) { + return; + } + const imageAttribute = getTheme(image).image; + this._draw(image, imageAttribute, false, drawContext); + } +} + +export class DefaultGifImageRenderContribution + extends DefaultRectRenderContribution + implements IImageRenderContribution +{ + time: BaseRenderContributionTime = BaseRenderContributionTime.afterFillStroke; + useStyle: boolean = true; + order: number = 0; + drawShape( + image: any, + context: IContext2d, + x: number, + y: number, + doFill: boolean, + doStroke: boolean, + fVisible: boolean, + sVisible: boolean, + rectAttribute: any, + drawContext: IDrawContext, + fillCb?: ( + ctx: IContext2d, + markAttribute: Partial, + themeAttribute: IThemeAttribute + ) => boolean, + strokeCb?: ( + ctx: IContext2d, + markAttribute: Partial, + themeAttribute: IThemeAttribute + ) => boolean + ) { + if (image.renderFrame && image.playing) { + image.renderFrame(context, x, y); + } + } +} + +export const defaultGifImageRenderContribution = new DefaultGifImageRenderContribution(); diff --git a/packages/vrender/__tests__/browser/sources/loading-1.gif b/packages/vrender/__tests__/browser/sources/loading-1.gif new file mode 100644 index 0000000000000000000000000000000000000000..20ac5cb44a0e62e1e8839c309f50f3204ce7e0b3 GIT binary patch literal 11698 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 literal 0 HcmV?d00001 diff --git a/packages/vrender/__tests__/browser/src/pages/gif-image.ts b/packages/vrender/__tests__/browser/src/pages/gif-image.ts new file mode 100644 index 000000000..8900d5098 --- /dev/null +++ b/packages/vrender/__tests__/browser/src/pages/gif-image.ts @@ -0,0 +1,64 @@ +import { createStage, container } from '@visactor/vrender-core'; +import { GifImage, IGifImageGraphicAttribute, gifImageModule, gifImageCanvasPickModule } from '@visactor/vrender-kits'; +import { addShapesToStage, colorPools } from '../utils'; + +container.load(gifImageModule); +container.load(gifImageCanvasPickModule); + +export const page = () => { + const shapes = []; + shapes.push( + new GifImage({ + x: 100, + y: 100, + width: 50, + height: 50, + gifImage: './sources/loading.gif' + } as IGifImageGraphicAttribute) + ); + + shapes.push( + new GifImage({ + x: 200, + y: 100, + width: 50, + height: 50, + gifImage: './sources/loading.gif' + } as IGifImageGraphicAttribute) + ); + + shapes.push( + new GifImage({ + x: 100, + y: 200, + width: 50, + height: 50, + gifImage: './sources/loading-1.gif' + } as IGifImageGraphicAttribute) + ); + + shapes.push( + new GifImage({ + x: 200, + y: 200, + width: 50, + height: 50, + gifImage: './sources/loading-1.gif' + } as IGifImageGraphicAttribute) + ); + + const stage = createStage({ + canvas: 'main', + width: 1200, + height: 600, + viewWidth: 1200, + viewHeight: 600 + }); + + addShapesToStage(stage, shapes as any, true); + stage.render(); + + stage.addEventListener('click', e => { + console.log('target', e.target); + }); +}; diff --git a/packages/vrender/__tests__/browser/src/pages/index.ts b/packages/vrender/__tests__/browser/src/pages/index.ts index 8eff30472..2fed4b3de 100644 --- a/packages/vrender/__tests__/browser/src/pages/index.ts +++ b/packages/vrender/__tests__/browser/src/pages/index.ts @@ -190,6 +190,10 @@ export const pages = [ { name: 'react', path: 'react' + }, + { + name: 'gif-image', + path: 'gif-image' } ] }, From a766717fa9a0b49e809ccc6f28862d1e5802a686 Mon Sep 17 00:00:00 2001 From: Rui-Sun Date: Mon, 6 Jan 2025 17:15:37 +0800 Subject: [PATCH 14/14] chore: update merge request --- .../fix-visible-bounds_2024-09-29-08-30.json | 10 ---------- common/config/rush/pnpm-lock.yaml | 1 + .../__tests__/browser/sources/loading-1.gif | Bin 11698 -> 0 bytes .../__tests__/browser/sources/loading.gif | Bin 10402 -> 0 bytes 4 files changed, 1 insertion(+), 10 deletions(-) delete mode 100644 common/changes/@visactor/vrender-core/fix-visible-bounds_2024-09-29-08-30.json delete mode 100644 packages/vrender-components/__tests__/browser/sources/loading-1.gif delete mode 100644 packages/vrender-components/__tests__/browser/sources/loading.gif diff --git a/common/changes/@visactor/vrender-core/fix-visible-bounds_2024-09-29-08-30.json b/common/changes/@visactor/vrender-core/fix-visible-bounds_2024-09-29-08-30.json deleted file mode 100644 index e590b282f..000000000 --- a/common/changes/@visactor/vrender-core/fix-visible-bounds_2024-09-29-08-30.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@visactor/vrender-core", - "comment": "fix: fix issue with dirtyBounds incorrectly while set visible", - "type": "none" - } - ], - "packageName": "@visactor/vrender-core" -} \ No newline at end of file diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 81634baa3..d2f963e62 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -304,6 +304,7 @@ importers: '@resvg/resvg-js': 2.4.1 '@visactor/vrender-core': link:../vrender-core '@visactor/vutils': 0.19.3 + gifuct-js: 2.1.2 roughjs: 4.5.2 devDependencies: '@internal/bundler': link:../../tools/bundler diff --git a/packages/vrender-components/__tests__/browser/sources/loading-1.gif b/packages/vrender-components/__tests__/browser/sources/loading-1.gif deleted file mode 100644 index 20ac5cb44a0e62e1e8839c309f50f3204ce7e0b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11698 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