diff --git a/package.json b/package.json index 6fd80f3c9..afc8bf404 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "chai": "^4.3.4", "chai-almost": "^1.0.1", "cross-env": "^6.0.3", + "d3": "latest", "eslint": "^7.28.0", "eslint-plugin-jest": "24.3.6", "father": "^2.30.13", diff --git a/packages/g-camera-api/package.json b/packages/g-camera-api/package.json index cb9fe131d..4a055c6ff 100644 --- a/packages/g-camera-api/package.json +++ b/packages/g-camera-api/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-camera-api", - "version": "1.0.21", + "version": "1.0.22", "description": "A simple implementation of Camera API.", "keywords": [ "antv", diff --git a/packages/g-canvas/package.json b/packages/g-canvas/package.json index 874b53f32..a89934772 100644 --- a/packages/g-canvas/package.json +++ b/packages/g-canvas/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-canvas", - "version": "1.9.20", + "version": "1.9.21", "description": "A renderer implemented by Canvas 2D API", "keywords": [ "antv", @@ -32,12 +32,12 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-plugin-canvas-path-generator": "^1.1.32", - "@antv/g-plugin-canvas-picker": "^1.8.29", - "@antv/g-plugin-canvas-renderer": "^1.7.35", - "@antv/g-plugin-dom-interaction": "^1.7.32", - "@antv/g-plugin-html-renderer": "^1.7.32", - "@antv/g-plugin-image-loader": "^1.1.33", + "@antv/g-plugin-canvas-path-generator": "^1.1.33", + "@antv/g-plugin-canvas-picker": "^1.8.30", + "@antv/g-plugin-canvas-renderer": "^1.7.36", + "@antv/g-plugin-dom-interaction": "^1.7.33", + "@antv/g-plugin-html-renderer": "^1.7.33", + "@antv/g-plugin-image-loader": "^1.1.34", "@antv/util": "^3.3.1", "@types/offscreencanvas": "^2019.6.4", "tslib": "^2.3.1" diff --git a/packages/g-canvaskit/package.json b/packages/g-canvaskit/package.json index 34e169192..badd06082 100644 --- a/packages/g-canvaskit/package.json +++ b/packages/g-canvaskit/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-canvaskit", - "version": "0.8.20", + "version": "0.8.21", "description": "A renderer implemented by CanvasKit", "keywords": [ "antv", @@ -32,12 +32,12 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-plugin-canvas-path-generator": "^1.1.32", - "@antv/g-plugin-canvas-picker": "^1.8.29", - "@antv/g-plugin-canvaskit-renderer": "^1.1.33", - "@antv/g-plugin-dom-interaction": "^1.7.32", - "@antv/g-plugin-html-renderer": "^1.7.32", - "@antv/g-plugin-image-loader": "^1.1.33", + "@antv/g-plugin-canvas-path-generator": "^1.1.33", + "@antv/g-plugin-canvas-picker": "^1.8.30", + "@antv/g-plugin-canvaskit-renderer": "^1.1.34", + "@antv/g-plugin-dom-interaction": "^1.7.33", + "@antv/g-plugin-html-renderer": "^1.7.33", + "@antv/g-plugin-image-loader": "^1.1.34", "@antv/util": "^3.3.1", "canvaskit-wasm": "^0.34.0", "tslib": "^2.3.1" diff --git a/packages/g-components/package.json b/packages/g-components/package.json index 6c5e1a466..a8f6a0241 100644 --- a/packages/g-components/package.json +++ b/packages/g-components/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-components", - "version": "1.7.32", + "version": "1.7.33", "description": "Components for g", "keywords": [ "antv", diff --git a/packages/g-components/src/Arrow.ts b/packages/g-components/src/Arrow.ts index 98977cb89..9d05725b9 100644 --- a/packages/g-components/src/Arrow.ts +++ b/packages/g-components/src/Arrow.ts @@ -58,8 +58,16 @@ export class Arrow extends CustomElement { type: Arrow.tag, }); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { body, startHead, endHead, startHeadOffset, endHeadOffset, ...rest } = this.attributes; + const { + body, + startHead, + endHead, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + startHeadOffset, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + endHeadOffset, + ...rest + } = this.attributes; if (!body) { throw new Error("Arrow's body is required"); @@ -123,24 +131,52 @@ export class Arrow extends CustomElement { name === 'lineWidth' || name === 'increasedLineWidthForHitTesting' ) { - this.applyArrowStyle({ [name]: newValue }, [this.body, this.startHead, this.endHead]); + this.applyArrowStyle({ [name]: newValue }, [ + this.body, + this.startHead, + this.endHead, + ]); } else if (name === 'startHead' || name === 'endHead') { const isStart = name === 'startHead'; // delete existed arrow head first this.destroyArrowHead(isStart); if (newValue) { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { body, startHead, endHead, startHeadOffset, endHeadOffset, ...rest } = - this.attributes; + const { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + body, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + startHead, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + endHead, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + startHeadOffset, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + endHeadOffset, + ...rest + } = this.attributes; // append new arrow head - this.appendArrowHead(this.getArrowHeadType(newValue as ArrowHead), isStart); + this.appendArrowHead( + this.getArrowHeadType(newValue as ArrowHead), + isStart, + ); this.applyArrowStyle(rest, [isStart ? this.startHead : this.endHead]); } } else if (name === 'body') { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { body, startHead, endHead, startHeadOffset, endHeadOffset, ...rest } = this.attributes; + const { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + body, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + startHead, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + endHead, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + startHeadOffset, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + endHeadOffset, + ...rest + } = this.attributes; this.body.destroy(); // @ts-ignore this.body = newValue; @@ -183,7 +219,9 @@ export class Arrow extends CustomElement { this.appendChild(head); - const offset = isStart ? this.attributes.startHeadOffset : this.attributes.endHeadOffset; + const offset = isStart + ? this.attributes.startHeadOffset + : this.attributes.endHeadOffset; if (offset) { this.moveArrowHeadAlongTangent(offset, isStart); } @@ -203,7 +241,12 @@ export class Arrow extends CustomElement { const bodyType = this.body && this.body.nodeName; if (bodyType === Shape.LINE) { - const { x1: _x1, x2: _x2, y1: _y1, y2: _y2 } = (this.body as Line).attributes; + const { + x1: _x1, + x2: _x2, + y1: _y1, + y2: _y2, + } = (this.body as Line).attributes; x1 = isStart ? _x2 : _x1; x2 = isStart ? _x1 : _x2; y1 = isStart ? _y2 : _y1; @@ -237,7 +280,9 @@ export class Arrow extends CustomElement { } head.setLocalPosition(position); - head.setLocalEulerAngles((rad * 180) / Math.PI + head.getLocalEulerAngles()); + head.setLocalEulerAngles( + (rad * 180) / Math.PI + head.getLocalEulerAngles(), + ); } private moveArrowHeadAlongTangent(offset: number, isStart: boolean) { @@ -291,9 +336,9 @@ export class Arrow extends CustomElement { return new Path({ style: { // draw an angle '<' - path: `M${10 * cos(PI / 6)},${10 * sin(PI / 6)} L0,0 L${10 * cos(PI / 6)},-${ - 10 * sin(PI / 6) - }`, + path: `M${10 * cos(PI / 6)},${10 * sin(PI / 6)} L0,0 L${ + 10 * cos(PI / 6) + },-${10 * sin(PI / 6)}`, stroke, lineWidth, transformOrigin: 'center', @@ -302,9 +347,17 @@ export class Arrow extends CustomElement { }); } - private applyArrowStyle(attributes: ArrowStyleProps, objects: (DisplayObject | undefined)[]) { - const { opacity, stroke, strokeOpacity, lineWidth, increasedLineWidthForHitTesting } = - attributes; + private applyArrowStyle( + attributes: ArrowStyleProps, + objects: (DisplayObject | undefined)[], + ) { + const { + opacity, + stroke, + strokeOpacity, + lineWidth, + increasedLineWidthForHitTesting, + } = attributes; objects.forEach((shape) => { if (shape) { if (!isNil(opacity)) { @@ -324,7 +377,8 @@ export class Arrow extends CustomElement { } if (!isNil(increasedLineWidthForHitTesting)) { - shape.style.increasedLineWidthForHitTesting = increasedLineWidthForHitTesting; + shape.style.increasedLineWidthForHitTesting = + increasedLineWidthForHitTesting; } } }); diff --git a/packages/g-components/src/Sector.ts b/packages/g-components/src/Sector.ts new file mode 100644 index 000000000..bd9326565 --- /dev/null +++ b/packages/g-components/src/Sector.ts @@ -0,0 +1,575 @@ +import type { BaseStyleProps, DisplayObjectConfig } from '@antv/g-lite'; +import { + CustomElement, + PropertySyntax, + CSS, + Path, + deg2rad, +} from '@antv/g-lite'; +import { PathArray, isNumberEqual } from '@antv/util'; + +const PI = Math.PI; +const PI2 = PI * 2; +const mathSin = Math.sin; +const mathCos = Math.cos; +const mathACos = Math.acos; +const mathATan2 = Math.atan2; +// const mathAbs = Math.abs; +const mathSqrt = Math.sqrt; +const mathMax = Math.max; +const mathMin = Math.min; +const e = 1e-4; + +// 注册 css 属性 +const SECTOR_CSS_PROPERTY = [ + { + name: 'r', + inherits: false, + interpolable: true, + syntax: PropertySyntax.LENGTH_PERCENTAGE, + }, + { + name: 'r0', + inherits: false, + interpolable: true, + syntax: PropertySyntax.LENGTH_PERCENTAGE, + }, + { + name: 'startAngle', + inherits: false, + interpolable: true, + syntax: PropertySyntax.ANGLE, + }, + { + name: 'endAngle', + inherits: false, + interpolable: true, + syntax: PropertySyntax.ANGLE, + }, +]; +SECTOR_CSS_PROPERTY.forEach((property) => { + CSS.registerProperty(property); +}); + +const polarToCartesian = ( + centerX: number, + centerY: number, + radius: number, + angleInRadian: number, +) => { + return { + x: centerX + radius * Math.cos(angleInRadian), + y: centerY + radius * Math.sin(angleInRadian), + }; +}; + +function intersect( + x0: number, + y0: number, + x1: number, + y1: number, + x2: number, + y2: number, + x3: number, + y3: number, +): [number, number] | undefined { + const dx10 = x1 - x0; + const dy10 = y1 - y0; + const dx32 = x3 - x2; + const dy32 = y3 - y2; + let t = dy32 * dx10 - dx32 * dy10; + if (t * t < e) { + return; + } + t = (dx32 * (y0 - y2) - dy32 * (x0 - x2)) / t; + return [x0 + t * dx10, y0 + t * dy10]; +} + +// Compute perpendicular offset line of length rc. +function computeCornerTangents( + x0: number, + y0: number, + x1: number, + y1: number, + radius: number, + cr: number, + clockwise: boolean, +) { + const x01 = x0 - x1; + const y01 = y0 - y1; + const lo = (clockwise ? cr : -cr) / mathSqrt(x01 * x01 + y01 * y01); + const ox = lo * y01; + const oy = -lo * x01; + const x11 = x0 + ox; + const y11 = y0 + oy; + const x10 = x1 + ox; + const y10 = y1 + oy; + const x00 = (x11 + x10) / 2; + const y00 = (y11 + y10) / 2; + const dx = x10 - x11; + const dy = y10 - y11; + const d2 = dx * dx + dy * dy; + const r = radius - cr; + const s = x11 * y10 - x10 * y11; + const d = (dy < 0 ? -1 : 1) * mathSqrt(mathMax(0, r * r * d2 - s * s)); + let cx0 = (s * dy - dx * d) / d2; + let cy0 = (-s * dx - dy * d) / d2; + const cx1 = (s * dy + dx * d) / d2; + const cy1 = (-s * dx + dy * d) / d2; + const dx0 = cx0 - x00; + const dy0 = cy0 - y00; + const dx1 = cx1 - x00; + const dy1 = cy1 - y00; + + // Pick the closer of the two intersection points + // TODO: Is there a faster way to determine which intersection to use? + if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) { + cx0 = cx1; + cy0 = cy1; + } + + return { + cx: cx0, + cy: cy0, + x0: -ox, + y0: -oy, + x1: cx0 * (radius / r - 1), + y1: cy0 * (radius / r - 1), + }; +} + +function computeArcSweep(startAngle: number, endAngle: number) { + endAngle = endAngle < 0 && startAngle >= 0 ? endAngle + PI2 : endAngle; + return endAngle - startAngle <= PI ? 0 : 1; +} + +export interface SectorStyleProps extends BaseStyleProps { + startAngle: number; + endAngle: number; + sr0: number; + sr: number; + sradius: number; + sx: number; + sy: number; +} + +export class Sector extends CustomElement { + static tag = 'sector'; + + private path: Path; + + constructor(config: DisplayObjectConfig) { + super({ + ...config, + type: Sector.tag, + }); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { startAngle, endAngle, sr, sr0, sradius, sx, sy, ...rest } = + this.attributes; + this.path = new Path({ + style: { ...rest }, + }); + this.updatePath(); + + this.appendChild(this.path); + } + + attributeChangedCallback( + name: Key, + oldValue: SectorStyleProps[Key], + newValue: SectorStyleProps[Key], + ) { + if ( + name === 'startAngle' || + name === 'endAngle' || + name === 'sr' || + name === 'sr0' || + name === 'sradius' || + name === 'sx' || + name === 'sy' + ) { + this.updatePath(); + } + } + + private updatePath() { + const { sx, sy, startAngle, endAngle, sr, sr0, sradius } = this.parsedStyle; + + const path = this.createPath( + sx, + sy, + startAngle ? deg2rad(startAngle) : 0, + endAngle ? deg2rad(endAngle) : Math.PI * 2, + sr ? sr : 0, + sr0 ? sr0 : 0, + sradius ? sradius : [0, 0, 0, 0], + ); + + this.path.style.d = path; + } + + private createPath( + x: number, + y: number, + startAngle: number, + endAngle: number, + r: number, + r0: number, + borderRadius: number[], + ): PathArray | undefined { + if (r <= 0) { + return; + } + const start = polarToCartesian(x, y, r, startAngle); + const end = polarToCartesian(x, y, r, endAngle); + + const innerStart = polarToCartesian(x, y, r0, startAngle); + const innerEnd = polarToCartesian(x, y, r0, endAngle); + + // 整圆 + if (isNumberEqual(endAngle - startAngle, Math.PI * 2)) { + // 整个圆是分割成两个圆 + const middlePoint = polarToCartesian(x, y, r, startAngle + Math.PI); + const innerMiddlePoint = polarToCartesian(x, y, r0, startAngle + Math.PI); + const circlePathCommands = [ + ['M', start.x, start.y], + ['A', r, r, 0, 1, 1, middlePoint.x, middlePoint.y], + ['A', r, r, 0, 1, 1, end.x, end.y], + ['M', innerStart.x, innerStart.y], + ]; + if (r0) { + circlePathCommands.push([ + 'A', + r0, + r0, + 0, + 1, + 0, + innerMiddlePoint.x, + innerMiddlePoint.y, + ]); + circlePathCommands.push(['A', r0, r0, 0, 1, 0, innerEnd.x, innerEnd.y]); + } + + circlePathCommands.push(['M', start.x, start.y]); + circlePathCommands.push(['Z']); + + return circlePathCommands as PathArray; + } + + const angle = endAngle - startAngle; + const xrs = r * mathCos(startAngle); + const yrs = r * mathSin(startAngle); + const xire = r0 * mathCos(endAngle); + const yire = r0 * mathSin(endAngle); + + const xre = r * mathCos(endAngle); + const yre = r * mathSin(endAngle); + const xirs = r0 * mathCos(startAngle); + const yirs = r0 * mathSin(startAngle); + + // 顺时针反向,同 radius + const [outStartRadius, outEndRadius, innerEndRadius, innerStartRadius] = + borderRadius; + + const halfRadius = (r - r0) / 2; + const outStartBorderRadius = mathMin(halfRadius, outStartRadius); + const outEndBorderRadius = mathMin(halfRadius, outEndRadius); + const innerEndBorderRadius = mathMin(halfRadius, innerEndRadius); + const innerStartBorderRadius = mathMin(halfRadius, innerStartRadius); + + const outBorderRadiusMax = mathMax( + outStartBorderRadius, + outEndBorderRadius, + ); + const innerBorderRadiusMax = mathMax( + innerEndBorderRadius, + innerStartBorderRadius, + ); + + let limitedOutBorderRadiusMax = outBorderRadiusMax; + let limitedInnerBorderRadiusMax = innerBorderRadiusMax; + + // draw corner radius + if (outBorderRadiusMax > e || innerBorderRadiusMax > e) { + // restrict the max value of corner radius + if (angle < PI) { + const it = intersect(xrs, yrs, xirs, yirs, xre, yre, xire, yire); + if (it) { + const x0 = xrs - it[0]; + const y0 = yrs - it[1]; + const x1 = xre - it[0]; + const y1 = yre - it[1]; + const a = + 1 / + mathSin( + mathACos( + (x0 * x1 + y0 * y1) / + (mathSqrt(x0 * x0 + y0 * y0) * mathSqrt(x1 * x1 + y1 * y1)), + ) / 2, + ); + const b = mathSqrt(it[0] * it[0] + it[1] * it[1]); + limitedOutBorderRadiusMax = mathMin( + outBorderRadiusMax, + (r - b) / (a + 1), + ); + limitedInnerBorderRadiusMax = mathMin( + innerBorderRadiusMax, + (r0 - b) / (a - 1), + ); + } + } + } + const arcSweep = computeArcSweep(startAngle, endAngle); + const clockwise = true; + const sectorPathCommands: PathArray = [] as unknown as PathArray; + + if (limitedOutBorderRadiusMax > e) { + const crStart = mathMin(outStartRadius, limitedOutBorderRadiusMax); + const crEnd = mathMin(outEndRadius, limitedOutBorderRadiusMax); + const ct0 = computeCornerTangents( + xirs, + yirs, + xrs, + yrs, + r, + crStart, + clockwise, + ); + const ct1 = computeCornerTangents( + xre, + yre, + xire, + yire, + r, + crEnd, + clockwise, + ); + + sectorPathCommands.push(['M', x + ct0.cx + ct0.x0, y + ct0.cy + ct0.y0]); + + // Have the corners merged? + if (limitedOutBorderRadiusMax < outBorderRadiusMax && crStart === crEnd) { + const outStartBorderRadiusStartAngle = mathATan2(ct0.y0, ct0.x0); + const outStartBorderRadiusEndAngle = mathATan2(ct1.y0, ct1.x0); + sectorPathCommands.push([ + 'A', + limitedOutBorderRadiusMax, + limitedOutBorderRadiusMax, + 0, + computeArcSweep( + outStartBorderRadiusStartAngle, + outStartBorderRadiusEndAngle, + ), + 1, + x + ct1.cx + ct1.x0, + y + ct1.cy + ct1.y0, + ]); + } else { + // draw the two corners and the ring + if (crStart > 0) { + const outStartBorderRadiusStartAngle = mathATan2(ct0.y0, ct0.x0); + const outStartBorderRadiusEndAngle = mathATan2(ct0.y1, ct0.x1); + const outStartBorderRadiusEndPoint = polarToCartesian( + x, + y, + r, + outStartBorderRadiusEndAngle, + ); + sectorPathCommands.push([ + 'A', + crStart, + crStart, + 0, + computeArcSweep( + outStartBorderRadiusStartAngle, + outStartBorderRadiusEndAngle, + ), + 1, + outStartBorderRadiusEndPoint.x, + outStartBorderRadiusEndPoint.y, + ]); + } + + const outRadiusStartAngle = mathATan2(ct0.cy + ct0.y1, ct0.cx + ct0.x1); + const outRadiusEndAngle = mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1); + const outRadiusEndPoint = polarToCartesian(x, y, r, outRadiusEndAngle); + sectorPathCommands.push([ + 'A', + r, + r, + 0, + computeArcSweep(outRadiusStartAngle, outRadiusEndAngle), + 1, + outRadiusEndPoint.x, + outRadiusEndPoint.y, + ]); + if (crEnd > 0) { + const outEndBorderRadiusStartAngle = mathATan2(ct1.y1, ct1.x1); + const outEndBorderRadiusEndAngle = mathATan2(ct1.y0, ct1.x0); + sectorPathCommands.push([ + 'A', + crEnd, + crEnd, + 0, + computeArcSweep( + outEndBorderRadiusStartAngle, + outEndBorderRadiusEndAngle, + ), + 1, + x + ct1.cx + ct1.x0, + y + ct1.cy + ct1.y0, + ]); + } + } + } else { + sectorPathCommands.push(['M', start.x, start.y]); + sectorPathCommands.push(['A', r, r, 0, arcSweep, 1, end.x, end.y]); + } + + // no inner ring, is a circular sector + if (r0 < e) { + sectorPathCommands.push(['L', innerEnd.x, innerEnd.y]); + } + // the inner ring has corners + else if (limitedInnerBorderRadiusMax > e) { + const crStart = mathMin(innerStartRadius, limitedInnerBorderRadiusMax); + const crEnd = mathMin(innerEndRadius, limitedInnerBorderRadiusMax); + const ct0 = computeCornerTangents( + xire, + yire, + 0, + 0, + r0 - r, + crEnd, + clockwise, + ); + const ct1 = computeCornerTangents( + 0, + 0, + xirs, + yirs, + r0 - r, + crStart, + clockwise, + ); + + sectorPathCommands.push(['L', x + ct0.cx + ct0.x0, y + ct0.cy + ct0.y0]); + + // Have the corners merged? + if ( + limitedInnerBorderRadiusMax < innerBorderRadiusMax && + crStart === crEnd + ) { + const innerStartBorderRadiusStartAngle = mathATan2(ct0.y0, ct0.x0); + const innerStartBorderRadiusEndAngle = mathATan2(ct1.y0, ct1.x0); + const innerStartBorderRadiusEndPoint = polarToCartesian( + x, + y, + r0, + innerStartBorderRadiusEndAngle, + ); + sectorPathCommands.push([ + 'A', + limitedOutBorderRadiusMax, + limitedOutBorderRadiusMax, + 0, + computeArcSweep( + innerStartBorderRadiusStartAngle, + innerStartBorderRadiusEndAngle, + ), + 1, + innerStartBorderRadiusEndPoint.x, + innerStartBorderRadiusEndPoint.y, + ]); + } + // draw the two corners and the ring + else { + if (crEnd > 0) { + const innerStartBorderRadiusStartAngle = mathATan2(ct0.y0, ct0.x0); + const innerStartBorderRadiusEndAngle = mathATan2(ct0.y1, ct0.x1); + const innerStartBorderRadiusEndPoint = polarToCartesian( + x, + y, + r0 - r, + innerStartBorderRadiusEndAngle, + ); + sectorPathCommands.push([ + 'A', + crEnd, + crEnd, + 0, + computeArcSweep( + innerStartBorderRadiusStartAngle, + innerStartBorderRadiusEndAngle, + ), + 1, + innerStartBorderRadiusEndPoint.x, + innerStartBorderRadiusEndPoint.y, + ]); + } + const innerRadiusStartAngle = mathATan2( + ct0.cy + ct0.y1, + ct0.cx + ct0.x1, + ); + const innerRadiusEndAngle = mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1); + const innerRadiusEndPoint = polarToCartesian( + x, + y, + r0, + innerRadiusEndAngle, + ); + sectorPathCommands.push([ + 'A', + r0, + r0, + 0, + computeArcSweep(innerRadiusEndAngle, innerRadiusStartAngle), + 0, + innerRadiusEndPoint.x, + innerRadiusEndPoint.y, + ]); + sectorPathCommands.push([ + 'L', + innerRadiusEndPoint.x, + innerRadiusEndPoint.y, + ]); + if (crStart > 0) { + const innerEndBorderRadiusStartAngle = mathATan2(ct1.y1, ct1.x1); + const innerEndBorderRadiusEndAngle = mathATan2(ct1.y0, ct1.x0); + sectorPathCommands.push([ + 'A', + crStart, + crStart, + 0, + computeArcSweep( + innerEndBorderRadiusStartAngle, + innerEndBorderRadiusEndAngle, + ), + 1, + x + ct1.cx + ct1.x0, + y + ct1.cy + ct1.y0, + ]); + } + } + } + // the inner ring is just a circular arc + else { + sectorPathCommands.push(['L', innerEnd.x, innerEnd.y]); + sectorPathCommands.push([ + 'A', + r0, + r0, + 0, + arcSweep, + 0, + innerStart.x, + innerStart.y, + ]); + } + sectorPathCommands.push(['Z']); + + return sectorPathCommands as PathArray; + } +} diff --git a/packages/g-components/src/Sector2.ts b/packages/g-components/src/Sector2.ts new file mode 100644 index 000000000..b797b188d --- /dev/null +++ b/packages/g-components/src/Sector2.ts @@ -0,0 +1,531 @@ +import { Path, deg2rad, CSS, PropertySyntax } from '@antv/g-lite'; +import { isNumberEqual, PathArray } from '@antv/util'; + +const PI = Math.PI; +const PI2 = PI * 2; +const mathSin = Math.sin; +const mathCos = Math.cos; +const mathACos = Math.acos; +const mathATan2 = Math.atan2; +// const mathAbs = Math.abs; +const mathSqrt = Math.sqrt; +const mathMax = Math.max; +const mathMin = Math.min; +const e = 1e-4; + +// 注册 css 属性 +const SECTOR_CSS_PROPERTY = [ + { + name: 'sr', + inherits: false, + interpolable: true, + syntax: PropertySyntax.LENGTH_PERCENTAGE, + }, + { + name: 'sr0', + inherits: false, + interpolable: true, + syntax: PropertySyntax.LENGTH_PERCENTAGE, + }, + { + name: 'startAngle', + inherits: false, + interpolable: true, + syntax: PropertySyntax.ANGLE, + }, + { + name: 'endAngle', + inherits: false, + interpolable: true, + syntax: PropertySyntax.ANGLE, + }, +]; +SECTOR_CSS_PROPERTY.forEach((property) => { + CSS.registerProperty(property); +}); + +const polarToCartesian = ( + centerX: number, + centerY: number, + radius: number, + angleInRadian: number, +) => { + return { + x: centerX + radius * Math.cos(angleInRadian), + y: centerY + radius * Math.sin(angleInRadian), + }; +}; + +function intersect( + x0: number, + y0: number, + x1: number, + y1: number, + x2: number, + y2: number, + x3: number, + y3: number, +): [number, number] | undefined { + const dx10 = x1 - x0; + const dy10 = y1 - y0; + const dx32 = x3 - x2; + const dy32 = y3 - y2; + let t = dy32 * dx10 - dx32 * dy10; + if (t * t < e) { + return; + } + t = (dx32 * (y0 - y2) - dy32 * (x0 - x2)) / t; + return [x0 + t * dx10, y0 + t * dy10]; +} + +// Compute perpendicular offset line of length rc. +function computeCornerTangents( + x0: number, + y0: number, + x1: number, + y1: number, + radius: number, + cr: number, + clockwise: boolean, +) { + const x01 = x0 - x1; + const y01 = y0 - y1; + const lo = (clockwise ? cr : -cr) / mathSqrt(x01 * x01 + y01 * y01); + const ox = lo * y01; + const oy = -lo * x01; + const x11 = x0 + ox; + const y11 = y0 + oy; + const x10 = x1 + ox; + const y10 = y1 + oy; + const x00 = (x11 + x10) / 2; + const y00 = (y11 + y10) / 2; + const dx = x10 - x11; + const dy = y10 - y11; + const d2 = dx * dx + dy * dy; + const r = radius - cr; + const s = x11 * y10 - x10 * y11; + const d = (dy < 0 ? -1 : 1) * mathSqrt(mathMax(0, r * r * d2 - s * s)); + let cx0 = (s * dy - dx * d) / d2; + let cy0 = (-s * dx - dy * d) / d2; + const cx1 = (s * dy + dx * d) / d2; + const cy1 = (-s * dx + dy * d) / d2; + const dx0 = cx0 - x00; + const dy0 = cy0 - y00; + const dx1 = cx1 - x00; + const dy1 = cy1 - y00; + + // Pick the closer of the two intersection points + // TODO: Is there a faster way to determine which intersection to use? + if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) { + cx0 = cx1; + cy0 = cy1; + } + + return { + cx: cx0, + cy: cy0, + x0: -ox, + y0: -oy, + x1: cx0 * (radius / r - 1), + y1: cy0 * (radius / r - 1), + }; +} + +function computeArcSweep(startAngle: number, endAngle: number) { + endAngle = endAngle < 0 && startAngle >= 0 ? endAngle + PI2 : endAngle; + return endAngle - startAngle <= PI ? 0 : 1; +} + +export class Sector extends Path { + // parsedStyle: any; + constructor(config) { + super(config); + this.updatePath(); + } + setAttribute(name, value, force?: boolean) { + super.setAttribute(name, value, force); + if (['startAngle', 'endAngle', 'sr', 'sr0', 'radius'].indexOf(name) > -1) { + this.updatePath(); + } + } + + private updatePath() { + // @ts-ignore + const { x, y, startAngle, endAngle, sr, sr0, radius } = this.parsedStyle; + + const path = this.createPath( + x, + y, + startAngle ? deg2rad(startAngle) : 0, + endAngle ? deg2rad(endAngle) : Math.PI * 2, + sr ? sr : 0, + sr0 ? sr0 : 0, + radius ? radius : [0, 0, 0, 0], + ); + super.setAttribute('path', path); + } + + private createPath( + x: number, + y: number, + startAngle: number, + endAngle: number, + r: number, + r0: number, + borderRadius: number[], + ): PathArray | undefined { + if (r <= 0) { + return; + } + const start = polarToCartesian(x, y, r, startAngle); + const end = polarToCartesian(x, y, r, endAngle); + + const innerStart = polarToCartesian(x, y, r0, startAngle); + const innerEnd = polarToCartesian(x, y, r0, endAngle); + + // 整圆 + if (isNumberEqual(endAngle - startAngle, Math.PI * 2)) { + // 整个圆是分割成两个圆 + const middlePoint = polarToCartesian(x, y, r, startAngle + Math.PI); + const innerMiddlePoint = polarToCartesian(x, y, r0, startAngle + Math.PI); + const circlePathCommands = [ + ['M', start.x, start.y], + ['A', r, r, 0, 1, 1, middlePoint.x, middlePoint.y], + ['A', r, r, 0, 1, 1, end.x, end.y], + ['M', innerStart.x, innerStart.y], + ]; + if (r0) { + circlePathCommands.push([ + 'A', + r0, + r0, + 0, + 1, + 0, + innerMiddlePoint.x, + innerMiddlePoint.y, + ]); + circlePathCommands.push(['A', r0, r0, 0, 1, 0, innerEnd.x, innerEnd.y]); + } + + circlePathCommands.push(['M', start.x, start.y]); + circlePathCommands.push(['Z']); + + return circlePathCommands as PathArray; + } + + const angle = endAngle - startAngle; + const xrs = r * mathCos(startAngle); + const yrs = r * mathSin(startAngle); + const xire = r0 * mathCos(endAngle); + const yire = r0 * mathSin(endAngle); + + const xre = r * mathCos(endAngle); + const yre = r * mathSin(endAngle); + const xirs = r0 * mathCos(startAngle); + const yirs = r0 * mathSin(startAngle); + + // 顺时针反向,同 radius + const [outStartRadius, outEndRadius, innerEndRadius, innerStartRadius] = + borderRadius; + + const halfRadius = (r - r0) / 2; + const outStartBorderRadius = mathMin(halfRadius, outStartRadius); + const outEndBorderRadius = mathMin(halfRadius, outEndRadius); + const innerEndBorderRadius = mathMin(halfRadius, innerEndRadius); + const innerStartBorderRadius = mathMin(halfRadius, innerStartRadius); + + const outBorderRadiusMax = mathMax( + outStartBorderRadius, + outEndBorderRadius, + ); + const innerBorderRadiusMax = mathMax( + innerEndBorderRadius, + innerStartBorderRadius, + ); + + let limitedOutBorderRadiusMax = outBorderRadiusMax; + let limitedInnerBorderRadiusMax = innerBorderRadiusMax; + + // draw corner radius + if (outBorderRadiusMax > e || innerBorderRadiusMax > e) { + // restrict the max value of corner radius + if (angle < PI) { + const it = intersect(xrs, yrs, xirs, yirs, xre, yre, xire, yire); + if (it) { + const x0 = xrs - it[0]; + const y0 = yrs - it[1]; + const x1 = xre - it[0]; + const y1 = yre - it[1]; + const a = + 1 / + mathSin( + mathACos( + (x0 * x1 + y0 * y1) / + (mathSqrt(x0 * x0 + y0 * y0) * mathSqrt(x1 * x1 + y1 * y1)), + ) / 2, + ); + const b = mathSqrt(it[0] * it[0] + it[1] * it[1]); + limitedOutBorderRadiusMax = mathMin( + outBorderRadiusMax, + (r - b) / (a + 1), + ); + limitedInnerBorderRadiusMax = mathMin( + innerBorderRadiusMax, + (r0 - b) / (a - 1), + ); + } + } + } + const arcSweep = computeArcSweep(startAngle, endAngle); + const clockwise = true; + const sectorPathCommands: PathArray = [] as unknown as PathArray; + + if (limitedOutBorderRadiusMax > e) { + const crStart = mathMin(outStartRadius, limitedOutBorderRadiusMax); + const crEnd = mathMin(outEndRadius, limitedOutBorderRadiusMax); + const ct0 = computeCornerTangents( + xirs, + yirs, + xrs, + yrs, + r, + crStart, + clockwise, + ); + const ct1 = computeCornerTangents( + xre, + yre, + xire, + yire, + r, + crEnd, + clockwise, + ); + + sectorPathCommands.push(['M', x + ct0.cx + ct0.x0, y + ct0.cy + ct0.y0]); + + // Have the corners merged? + if (limitedOutBorderRadiusMax < outBorderRadiusMax && crStart === crEnd) { + const outStartBorderRadiusStartAngle = mathATan2(ct0.y0, ct0.x0); + const outStartBorderRadiusEndAngle = mathATan2(ct1.y0, ct1.x0); + sectorPathCommands.push([ + 'A', + limitedOutBorderRadiusMax, + limitedOutBorderRadiusMax, + 0, + computeArcSweep( + outStartBorderRadiusStartAngle, + outStartBorderRadiusEndAngle, + ), + 1, + x + ct1.cx + ct1.x0, + y + ct1.cy + ct1.y0, + ]); + } else { + // draw the two corners and the ring + if (crStart > 0) { + const outStartBorderRadiusStartAngle = mathATan2(ct0.y0, ct0.x0); + const outStartBorderRadiusEndAngle = mathATan2(ct0.y1, ct0.x1); + const outStartBorderRadiusEndPoint = polarToCartesian( + x, + y, + r, + outStartBorderRadiusEndAngle, + ); + sectorPathCommands.push([ + 'A', + crStart, + crStart, + 0, + computeArcSweep( + outStartBorderRadiusStartAngle, + outStartBorderRadiusEndAngle, + ), + 1, + outStartBorderRadiusEndPoint.x, + outStartBorderRadiusEndPoint.y, + ]); + } + + const outRadiusStartAngle = mathATan2(ct0.cy + ct0.y1, ct0.cx + ct0.x1); + const outRadiusEndAngle = mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1); + const outRadiusEndPoint = polarToCartesian(x, y, r, outRadiusEndAngle); + sectorPathCommands.push([ + 'A', + r, + r, + 0, + computeArcSweep(outRadiusStartAngle, outRadiusEndAngle), + 1, + outRadiusEndPoint.x, + outRadiusEndPoint.y, + ]); + if (crEnd > 0) { + const outEndBorderRadiusStartAngle = mathATan2(ct1.y1, ct1.x1); + const outEndBorderRadiusEndAngle = mathATan2(ct1.y0, ct1.x0); + sectorPathCommands.push([ + 'A', + crEnd, + crEnd, + 0, + computeArcSweep( + outEndBorderRadiusStartAngle, + outEndBorderRadiusEndAngle, + ), + 1, + x + ct1.cx + ct1.x0, + y + ct1.cy + ct1.y0, + ]); + } + } + } else { + sectorPathCommands.push(['M', start.x, start.y]); + sectorPathCommands.push(['A', r, r, 0, arcSweep, 1, end.x, end.y]); + } + + // no inner ring, is a circular sector + if (r0 < e) { + sectorPathCommands.push(['L', innerEnd.x, innerEnd.y]); + } + // the inner ring has corners + else if (limitedInnerBorderRadiusMax > e) { + const crStart = mathMin(innerStartRadius, limitedInnerBorderRadiusMax); + const crEnd = mathMin(innerEndRadius, limitedInnerBorderRadiusMax); + const ct0 = computeCornerTangents( + xire, + yire, + 0, + 0, + r0 - r, + crEnd, + clockwise, + ); + const ct1 = computeCornerTangents( + 0, + 0, + xirs, + yirs, + r0 - r, + crStart, + clockwise, + ); + + sectorPathCommands.push(['L', x + ct0.cx + ct0.x0, y + ct0.cy + ct0.y0]); + + // Have the corners merged? + if ( + limitedInnerBorderRadiusMax < innerBorderRadiusMax && + crStart === crEnd + ) { + const innerStartBorderRadiusStartAngle = mathATan2(ct0.y0, ct0.x0); + const innerStartBorderRadiusEndAngle = mathATan2(ct1.y0, ct1.x0); + const innerStartBorderRadiusEndPoint = polarToCartesian( + x, + y, + r0, + innerStartBorderRadiusEndAngle, + ); + sectorPathCommands.push([ + 'A', + limitedOutBorderRadiusMax, + limitedOutBorderRadiusMax, + 0, + computeArcSweep( + innerStartBorderRadiusStartAngle, + innerStartBorderRadiusEndAngle, + ), + 1, + innerStartBorderRadiusEndPoint.x, + innerStartBorderRadiusEndPoint.y, + ]); + } + // draw the two corners and the ring + else { + if (crEnd > 0) { + const innerStartBorderRadiusStartAngle = mathATan2(ct0.y0, ct0.x0); + const innerStartBorderRadiusEndAngle = mathATan2(ct0.y1, ct0.x1); + const innerStartBorderRadiusEndPoint = polarToCartesian( + x, + y, + r0 - r, + innerStartBorderRadiusEndAngle, + ); + sectorPathCommands.push([ + 'A', + crEnd, + crEnd, + 0, + computeArcSweep( + innerStartBorderRadiusStartAngle, + innerStartBorderRadiusEndAngle, + ), + 1, + innerStartBorderRadiusEndPoint.x, + innerStartBorderRadiusEndPoint.y, + ]); + } + const innerRadiusStartAngle = mathATan2( + ct0.cy + ct0.y1, + ct0.cx + ct0.x1, + ); + const innerRadiusEndAngle = mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1); + const innerRadiusEndPoint = polarToCartesian( + x, + y, + r0, + innerRadiusEndAngle, + ); + sectorPathCommands.push([ + 'A', + r0, + r0, + 0, + computeArcSweep(innerRadiusEndAngle, innerRadiusStartAngle), + 0, + innerRadiusEndPoint.x, + innerRadiusEndPoint.y, + ]); + sectorPathCommands.push([ + 'L', + innerRadiusEndPoint.x, + innerRadiusEndPoint.y, + ]); + if (crStart > 0) { + const innerEndBorderRadiusStartAngle = mathATan2(ct1.y1, ct1.x1); + const innerEndBorderRadiusEndAngle = mathATan2(ct1.y0, ct1.x0); + sectorPathCommands.push([ + 'A', + crStart, + crStart, + 0, + computeArcSweep( + innerEndBorderRadiusStartAngle, + innerEndBorderRadiusEndAngle, + ), + 1, + x + ct1.cx + ct1.x0, + y + ct1.cy + ct1.y0, + ]); + } + } + } + // the inner ring is just a circular arc + else { + sectorPathCommands.push(['L', innerEnd.x, innerEnd.y]); + sectorPathCommands.push([ + 'A', + r0, + r0, + 0, + arcSweep, + 0, + innerStart.x, + innerStart.y, + ]); + } + sectorPathCommands.push(['Z']); + + return sectorPathCommands as PathArray; + } +} diff --git a/packages/g-components/src/index.ts b/packages/g-components/src/index.ts index b471f2698..21b4f5aee 100644 --- a/packages/g-components/src/index.ts +++ b/packages/g-components/src/index.ts @@ -1,2 +1,4 @@ export { Arrow } from './Arrow'; +// export { Sector } from './Sector'; +export { Sector } from './Sector2'; // export { Spreadsheet } from './sheet'; diff --git a/packages/g-css-layout-api/package.json b/packages/g-css-layout-api/package.json index 3d0a66ee8..ffe479088 100644 --- a/packages/g-css-layout-api/package.json +++ b/packages/g-css-layout-api/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-css-layout-api", - "version": "1.0.21", + "version": "1.0.22", "description": "A simple implementation of CSS Layout API.", "keywords": [ "antv", diff --git a/packages/g-css-typed-om-api/package.json b/packages/g-css-typed-om-api/package.json index 50fe8c82e..f993d836d 100644 --- a/packages/g-css-typed-om-api/package.json +++ b/packages/g-css-typed-om-api/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-css-typed-om-api", - "version": "1.0.21", + "version": "1.0.22", "description": "A simple implementation of CSS Typed OM API.", "keywords": [ "antv", diff --git a/packages/g-devtool/package.json b/packages/g-devtool/package.json index 56c726710..6c05b281f 100644 --- a/packages/g-devtool/package.json +++ b/packages/g-devtool/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-devtool", - "version": "0.10.32", + "version": "0.10.33", "private": true, "description": "devtool for g in browser", "license": "MIT", diff --git a/packages/g-dom-mutation-observer-api/package.json b/packages/g-dom-mutation-observer-api/package.json index 92e45cf34..918f73efc 100644 --- a/packages/g-dom-mutation-observer-api/package.json +++ b/packages/g-dom-mutation-observer-api/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-dom-mutation-observer-api", - "version": "1.0.21", + "version": "1.0.22", "description": "A simple implementation of DOM MutationObserver API.", "keywords": [ "antv", diff --git a/packages/g-gesture/package.json b/packages/g-gesture/package.json index 09852c9f8..d9feeee9b 100644 --- a/packages/g-gesture/package.json +++ b/packages/g-gesture/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-gesture", - "version": "0.0.55", + "version": "0.0.56", "description": "G Gesture", "keywords": [ "antv", @@ -34,8 +34,8 @@ "eventemitter3": "^4.0.0" }, "devDependencies": { - "@antv/g-mobile-canvas": "^0.8.29", - "@antv/g-mobile-canvas-element": "^0.6.32" + "@antv/g-mobile-canvas": "^0.8.30", + "@antv/g-mobile-canvas-element": "^0.6.33" }, "publishConfig": { "access": "public" diff --git a/packages/g-image-exporter/package.json b/packages/g-image-exporter/package.json index b156ee888..a35a721e9 100644 --- a/packages/g-image-exporter/package.json +++ b/packages/g-image-exporter/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-image-exporter", - "version": "0.5.32", + "version": "0.5.33", "description": "A image exporter for G using DOM API", "keywords": [ "antv", diff --git a/packages/g-layout-blocklike/package.json b/packages/g-layout-blocklike/package.json index 4e773679e..666d5c03d 100644 --- a/packages/g-layout-blocklike/package.json +++ b/packages/g-layout-blocklike/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-layout-blocklike", - "version": "1.7.32", + "version": "1.7.33", "description": "A blocklike layout", "keywords": [ "antv", diff --git a/packages/g-lite/package.json b/packages/g-lite/package.json index 7dff852db..2e63f29eb 100644 --- a/packages/g-lite/package.json +++ b/packages/g-lite/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-lite", - "version": "1.0.21", + "version": "1.0.22", "description": "A core module for rendering engine implements DOM API.", "keywords": [ "antv", @@ -32,7 +32,7 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-math": "^1.7.32", + "@antv/g-math": "^1.7.33", "@antv/util": "^3.3.1", "@types/offscreencanvas": "^2019.6.4", "d3-color": "^1.4.0", diff --git a/packages/g-lite/src/css/properties/CSSPropertyClipPath.ts b/packages/g-lite/src/css/properties/CSSPropertyClipPath.ts index b583a6e3b..dcf5fb1dc 100644 --- a/packages/g-lite/src/css/properties/CSSPropertyClipPath.ts +++ b/packages/g-lite/src/css/properties/CSSPropertyClipPath.ts @@ -6,14 +6,26 @@ import type { CSSProperty } from '../CSSProperty'; /** * clipPath / textPath / offsetPath */ -export class CSSPropertyClipPath implements Partial> { - calculator(name: string, oldPath: DisplayObject, newPath: DisplayObject, object: DisplayObject) { +export class CSSPropertyClipPath + implements Partial> +{ + calculator( + name: string, + oldPath: DisplayObject, + newPath: DisplayObject, + object: DisplayObject, + ) { // unset if (newPath instanceof CSSKeywordValue) { newPath = null; } - runtime.sceneGraphService.updateDisplayObjectDependency(name, oldPath, newPath, object); + runtime.sceneGraphService.updateDisplayObjectDependency( + name, + oldPath, + newPath, + object, + ); if (name === 'clipPath') { // should affect children diff --git a/packages/g-lite/src/display-objects/DisplayObject.ts b/packages/g-lite/src/display-objects/DisplayObject.ts index a1cb5371f..dbf8c13ac 100644 --- a/packages/g-lite/src/display-objects/DisplayObject.ts +++ b/packages/g-lite/src/display-objects/DisplayObject.ts @@ -221,7 +221,7 @@ export class DisplayObject< destroy() { super.destroy(); - // remove from into pool + // remove from pool runtime.displayObjectPool.remove(this.entity); // stop all active animations diff --git a/packages/g-lite/src/plugins/PrepareRendererPlugin.ts b/packages/g-lite/src/plugins/PrepareRendererPlugin.ts index 06272cac7..0d0f3d0d8 100644 --- a/packages/g-lite/src/plugins/PrepareRendererPlugin.ts +++ b/packages/g-lite/src/plugins/PrepareRendererPlugin.ts @@ -73,18 +73,33 @@ export class PrepareRendererPlugin implements RenderingPlugin { renderingService.dirtify(); }; - renderingService.hooks.init.tapPromise(PrepareRendererPlugin.tag, async () => { - canvas.addEventListener(ElementEvent.MOUNTED, handleMounted); - canvas.addEventListener(ElementEvent.UNMOUNTED, handleUnmounted); - canvas.addEventListener(ElementEvent.ATTR_MODIFIED, handleAttributeChanged); - canvas.addEventListener(ElementEvent.BOUNDS_CHANGED, handleBoundsChanged); - }); + renderingService.hooks.init.tapPromise( + PrepareRendererPlugin.tag, + async () => { + canvas.addEventListener(ElementEvent.MOUNTED, handleMounted); + canvas.addEventListener(ElementEvent.UNMOUNTED, handleUnmounted); + canvas.addEventListener( + ElementEvent.ATTR_MODIFIED, + handleAttributeChanged, + ); + canvas.addEventListener( + ElementEvent.BOUNDS_CHANGED, + handleBoundsChanged, + ); + }, + ); renderingService.hooks.destroy.tap(PrepareRendererPlugin.tag, () => { canvas.removeEventListener(ElementEvent.MOUNTED, handleMounted); canvas.removeEventListener(ElementEvent.UNMOUNTED, handleUnmounted); - canvas.removeEventListener(ElementEvent.ATTR_MODIFIED, handleAttributeChanged); - canvas.removeEventListener(ElementEvent.BOUNDS_CHANGED, handleBoundsChanged); + canvas.removeEventListener( + ElementEvent.ATTR_MODIFIED, + handleAttributeChanged, + ); + canvas.removeEventListener( + ElementEvent.BOUNDS_CHANGED, + handleBoundsChanged, + ); }); renderingService.hooks.endFrame.tap(PrepareRendererPlugin.tag, () => { diff --git a/packages/g-lite/src/services/SceneGraphService.ts b/packages/g-lite/src/services/SceneGraphService.ts index f8f771eed..975dcadc7 100644 --- a/packages/g-lite/src/services/SceneGraphService.ts +++ b/packages/g-lite/src/services/SceneGraphService.ts @@ -16,6 +16,14 @@ import { findClosestClipPathTarget } from '../utils'; import type { SceneGraphService } from './interfaces'; import type { GlobalRuntime } from '../global-runtime'; +function markRenderableDirty(e: Element) { + const renderable = e.renderable; + if (renderable) { + renderable.renderBoundsDirty = true; + renderable.boundsDirty = true; + } +} + /** * update transform in scene graph * @@ -517,14 +525,16 @@ export class DefaultSceneGraphService implements SceneGraphService { } while (p) { - const renderable = (p as Element).renderable; - if (renderable) { - renderable.renderBoundsDirty = true; - renderable.boundsDirty = true; - } + markRenderableDirty(p as Element); p = p.parentNode; } + if (affectChildren) { + element.forEach((e: Element) => { + markRenderableDirty(e); + }); + } + // inform dependencies this.informDependentDisplayObjects(element as DisplayObject); @@ -569,7 +579,7 @@ export class DefaultSceneGraphService implements SceneGraphService { if (dependencyMap) { Object.keys(dependencyMap).forEach((name) => { dependencyMap[name].forEach((target) => { - this.dirtifyToRoot(target); + this.dirtifyToRoot(target, true); target.dispatchEvent( new MutationEvent( diff --git a/packages/g-lite/src/utils/dom.ts b/packages/g-lite/src/utils/dom.ts index 5fbc1f058..2f957f6fa 100644 --- a/packages/g-lite/src/utils/dom.ts +++ b/packages/g-lite/src/utils/dom.ts @@ -17,7 +17,9 @@ export function sortByZIndex(o1: IElement, o2: IElement) { return zIndex1 - zIndex2; } -export function findClosestClipPathTarget(object: DisplayObject): DisplayObject { +export function findClosestClipPathTarget( + object: DisplayObject, +): DisplayObject { let el = object; do { const clipPath = el.style?.clipPath; @@ -37,7 +39,9 @@ export function setDOMSize($el: CanvasLike, width: number, height: number) { export function getStyle($el: HTMLElement | CanvasLike, property: string) { if (isBrowser) { - return document.defaultView.getComputedStyle($el as Element, null).getPropertyValue(property); + return document.defaultView + .getComputedStyle($el as Element, null) + .getPropertyValue(property); } } diff --git a/packages/g-lottie-player/package.json b/packages/g-lottie-player/package.json index 770f9467f..82627a061 100644 --- a/packages/g-lottie-player/package.json +++ b/packages/g-lottie-player/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-lottie-player", - "version": "0.0.18", + "version": "0.0.19", "description": "A lottie player for G", "keywords": [ "antv", diff --git a/packages/g-math/package.json b/packages/g-math/package.json index fe10314ff..132747f36 100644 --- a/packages/g-math/package.json +++ b/packages/g-math/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-math", - "version": "1.7.32", + "version": "1.7.33", "description": "Geometry util", "keywords": [ "antv", diff --git a/packages/g-mobile-canvas-element/package.json b/packages/g-mobile-canvas-element/package.json index 6b0cbcd5a..bcd14abc7 100644 --- a/packages/g-mobile-canvas-element/package.json +++ b/packages/g-mobile-canvas-element/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-mobile-canvas-element", - "version": "0.6.32", + "version": "0.6.33", "description": "Create a CanvasLike element from existed context in mobile environment", "keywords": [ "antv", diff --git a/packages/g-mobile-canvas/package.json b/packages/g-mobile-canvas/package.json index b9de2fd51..ea37d7ba6 100644 --- a/packages/g-mobile-canvas/package.json +++ b/packages/g-mobile-canvas/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-mobile-canvas", - "version": "0.8.29", + "version": "0.8.30", "description": "A renderer implemented with Canvas2D API in mobile environment", "keywords": [ "antv", @@ -30,11 +30,11 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-plugin-canvas-path-generator": "^1.1.32", - "@antv/g-plugin-canvas-picker": "^1.8.29", - "@antv/g-plugin-canvas-renderer": "^1.7.35", - "@antv/g-plugin-image-loader": "^1.1.33", - "@antv/g-plugin-mobile-interaction": "^0.7.32", + "@antv/g-plugin-canvas-path-generator": "^1.1.33", + "@antv/g-plugin-canvas-picker": "^1.8.30", + "@antv/g-plugin-canvas-renderer": "^1.7.36", + "@antv/g-plugin-image-loader": "^1.1.34", + "@antv/g-plugin-mobile-interaction": "^0.7.33", "@antv/util": "^3.3.1", "tslib": "^2.3.1" }, diff --git a/packages/g-mobile-svg/package.json b/packages/g-mobile-svg/package.json index 779c1a151..3d18a4122 100644 --- a/packages/g-mobile-svg/package.json +++ b/packages/g-mobile-svg/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-mobile-svg", - "version": "0.8.29", + "version": "0.8.30", "description": "A renderer implemented by SVG in mobile environment", "keywords": [ "antv", @@ -30,9 +30,9 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-plugin-mobile-interaction": "^0.7.32", - "@antv/g-plugin-svg-picker": "^1.7.32", - "@antv/g-plugin-svg-renderer": "^1.8.29", + "@antv/g-plugin-mobile-interaction": "^0.7.33", + "@antv/g-plugin-svg-picker": "^1.7.33", + "@antv/g-plugin-svg-renderer": "^1.8.30", "@antv/util": "^3.3.1", "tslib": "^2.3.1" }, diff --git a/packages/g-mobile-webgl/package.json b/packages/g-mobile-webgl/package.json index 6035a5af3..3450f5b0e 100644 --- a/packages/g-mobile-webgl/package.json +++ b/packages/g-mobile-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-mobile-webgl", - "version": "0.7.35", + "version": "0.7.36", "description": "A renderer implemented by WebGL1/2 in mobile environment", "keywords": [ "antv", @@ -30,12 +30,12 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-plugin-device-renderer": "^1.7.35", - "@antv/g-plugin-dragndrop": "^1.6.32", - "@antv/g-plugin-html-renderer": "^1.7.32", - "@antv/g-plugin-image-loader": "^1.1.33", - "@antv/g-plugin-mobile-interaction": "^0.7.32", - "@antv/g-plugin-webgl-device": "^1.7.32", + "@antv/g-plugin-device-renderer": "^1.7.36", + "@antv/g-plugin-dragndrop": "^1.6.33", + "@antv/g-plugin-html-renderer": "^1.7.33", + "@antv/g-plugin-image-loader": "^1.1.34", + "@antv/g-plugin-mobile-interaction": "^0.7.33", + "@antv/g-plugin-webgl-device": "^1.7.33", "@antv/util": "^3.3.1" }, "devDependencies": { diff --git a/packages/g-pattern/package.json b/packages/g-pattern/package.json index 39f73174a..d01b4c329 100644 --- a/packages/g-pattern/package.json +++ b/packages/g-pattern/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-pattern", - "version": "1.0.2", + "version": "1.0.3", "description": "A pattern libs for G", "keywords": [ "antv", diff --git a/packages/g-plugin-3d/package.json b/packages/g-plugin-3d/package.json index 1467c0906..86dd6fcb6 100644 --- a/packages/g-plugin-3d/package.json +++ b/packages/g-plugin-3d/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-3d", - "version": "1.7.32", + "version": "1.7.33", "description": "Provide 3D extension for G", "keywords": [ "antv", @@ -30,7 +30,7 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-shader-components": "^1.7.32", + "@antv/g-shader-components": "^1.7.33", "gl-matrix": "^3.1.0", "tslib": "^2.3.1" }, diff --git a/packages/g-plugin-a11y/package.json b/packages/g-plugin-a11y/package.json index 511d93507..7a05d2204 100644 --- a/packages/g-plugin-a11y/package.json +++ b/packages/g-plugin-a11y/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-a11y", - "version": "0.4.32", + "version": "0.4.33", "description": "A G plugin for accessibility", "keywords": [ "antv", diff --git a/packages/g-plugin-annotation/package.json b/packages/g-plugin-annotation/package.json index c0c408276..0bd82802a 100644 --- a/packages/g-plugin-annotation/package.json +++ b/packages/g-plugin-annotation/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-annotation", - "version": "0.2.30", + "version": "0.2.31", "description": "A G plugin for annotation", "keywords": [ "antv", diff --git a/packages/g-plugin-annotation/src/SelectablePlugin.ts b/packages/g-plugin-annotation/src/SelectablePlugin.ts index 9a2b44954..5f6313796 100644 --- a/packages/g-plugin-annotation/src/SelectablePlugin.ts +++ b/packages/g-plugin-annotation/src/SelectablePlugin.ts @@ -228,10 +228,13 @@ export class SelectablePlugin implements RenderingPlugin { this.brush.on(DrawerEvent.CANCEL, onCancel); const handleClick = (e: FederatedPointerEvent) => { - if ( - !this.annotationPluginOptions.enableAutoSwitchDrawingMode && - this.annotationPluginOptions.isDrawingMode - ) { + const { + enableAutoSwitchDrawingMode, + enableContinuousBrush, + isDrawingMode, + } = this.annotationPluginOptions; + + if (!enableAutoSwitchDrawingMode && isDrawingMode) { return; } @@ -239,7 +242,7 @@ export class SelectablePlugin implements RenderingPlugin { // @ts-ignore if (object === document) { // allow continuous selection @see https://github.com/antvis/G/issues/1240 - if (!e.shiftKey) { + if (!e.shiftKey || (e.shiftKey && !enableContinuousBrush)) { this.deselectAllDisplayObjects(); this.selected = []; } diff --git a/packages/g-plugin-annotation/src/index.ts b/packages/g-plugin-annotation/src/index.ts index ca2aa4e20..0bdc4096e 100644 --- a/packages/g-plugin-annotation/src/index.ts +++ b/packages/g-plugin-annotation/src/index.ts @@ -21,6 +21,7 @@ export class Plugin extends AbstractRendererPlugin { arrowKeyStepLength: 4, enableAutoSwitchDrawingMode: false, enableDeleteTargetWithShortcuts: false, + enableContinuousBrush: true, ...this.options, }; diff --git a/packages/g-plugin-annotation/src/tokens.ts b/packages/g-plugin-annotation/src/tokens.ts index e61b324ec..5129c25ee 100644 --- a/packages/g-plugin-annotation/src/tokens.ts +++ b/packages/g-plugin-annotation/src/tokens.ts @@ -30,6 +30,11 @@ export interface AnnotationPluginOptions { * Delete target with shortcuts, e.g. Delete, Esc */ enableDeleteTargetWithShortcuts: boolean; + + /** + * Enable to do brush selections continuously. + */ + enableContinuousBrush: boolean; } // @see http://fabricjs.com/fabric-intro-part-4#customization diff --git a/packages/g-plugin-box2d/package.json b/packages/g-plugin-box2d/package.json index af1c0fa40..eb4a7b42e 100644 --- a/packages/g-plugin-box2d/package.json +++ b/packages/g-plugin-box2d/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-box2d", - "version": "1.7.32", + "version": "1.7.33", "description": "A G plugin for Box2D", "keywords": [ "antv", diff --git a/packages/g-plugin-canvas-path-generator/package.json b/packages/g-plugin-canvas-path-generator/package.json index 3a8cd4e6d..e078af4cb 100644 --- a/packages/g-plugin-canvas-path-generator/package.json +++ b/packages/g-plugin-canvas-path-generator/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-canvas-path-generator", - "version": "1.1.32", + "version": "1.1.33", "description": "A G plugin of path generator with Canvas2D API", "keywords": [ "antv", @@ -30,7 +30,7 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-math": "^1.7.32", + "@antv/g-math": "^1.7.33", "@antv/util": "^3.3.1", "tslib": "^2.3.1" }, diff --git a/packages/g-plugin-canvas-picker/package.json b/packages/g-plugin-canvas-picker/package.json index c36014c51..1ea99b2e8 100644 --- a/packages/g-plugin-canvas-picker/package.json +++ b/packages/g-plugin-canvas-picker/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-canvas-picker", - "version": "1.8.29", + "version": "1.8.30", "description": "A G plugin for picking in canvas", "keywords": [ "antv", @@ -30,7 +30,7 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-plugin-canvas-path-generator": "^1.1.32", + "@antv/g-plugin-canvas-path-generator": "^1.1.33", "@antv/util": "^3.3.1", "gl-matrix": "^3.1.0", "tslib": "^2.3.1" diff --git a/packages/g-plugin-canvas-renderer/package.json b/packages/g-plugin-canvas-renderer/package.json index e1d2d75a0..7e534be67 100644 --- a/packages/g-plugin-canvas-renderer/package.json +++ b/packages/g-plugin-canvas-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-canvas-renderer", - "version": "1.7.35", + "version": "1.7.36", "description": "A G plugin of renderer implementation with Canvas2D API", "keywords": [ "antv", @@ -30,9 +30,9 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-math": "^1.7.32", - "@antv/g-plugin-canvas-path-generator": "^1.1.32", - "@antv/g-plugin-image-loader": "^1.1.33", + "@antv/g-math": "^1.7.33", + "@antv/g-plugin-canvas-path-generator": "^1.1.33", + "@antv/g-plugin-image-loader": "^1.1.34", "@antv/util": "^3.3.1", "gl-matrix": "^3.1.0", "tslib": "^2.3.1" diff --git a/packages/g-plugin-canvaskit-renderer/package.json b/packages/g-plugin-canvaskit-renderer/package.json index ddad1343e..fb52db5c5 100644 --- a/packages/g-plugin-canvaskit-renderer/package.json +++ b/packages/g-plugin-canvaskit-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-canvaskit-renderer", - "version": "1.1.33", + "version": "1.1.34", "description": "A G plugin of renderer implementation with CanvasKit", "keywords": [ "antv", @@ -30,8 +30,8 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-math": "^1.7.32", - "@antv/g-plugin-image-loader": "^1.1.33", + "@antv/g-math": "^1.7.33", + "@antv/g-plugin-image-loader": "^1.1.34", "@antv/util": "^3.3.1", "canvaskit-wasm": "^0.34.0", "gl-matrix": "^3.1.0", diff --git a/packages/g-plugin-control/package.json b/packages/g-plugin-control/package.json index 1d24239b9..288951133 100644 --- a/packages/g-plugin-control/package.json +++ b/packages/g-plugin-control/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-control", - "version": "1.7.32", + "version": "1.7.33", "description": "A G plugin for orbit control", "keywords": [ "antv", diff --git a/packages/g-plugin-css-select/package.json b/packages/g-plugin-css-select/package.json index 48b8d73b4..575ee6f47 100644 --- a/packages/g-plugin-css-select/package.json +++ b/packages/g-plugin-css-select/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-css-select", - "version": "1.7.32", + "version": "1.7.33", "description": "A G plugin for using CSS select syntax in query selector", "keywords": [ "antv", diff --git a/packages/g-plugin-device-renderer/package.json b/packages/g-plugin-device-renderer/package.json index b19ea2d9d..0523c48be 100644 --- a/packages/g-plugin-device-renderer/package.json +++ b/packages/g-plugin-device-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-device-renderer", - "version": "1.7.35", + "version": "1.7.36", "description": "A G plugin of renderer implementation with GPUDevice", "keywords": [ "antv", @@ -34,8 +34,8 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-plugin-image-loader": "^1.1.33", - "@antv/g-shader-components": "^1.7.32", + "@antv/g-plugin-image-loader": "^1.1.34", + "@antv/g-shader-components": "^1.7.33", "@antv/util": "^3.3.1", "@mapbox/tiny-sdf": "^2.0.4", "@types/offscreencanvas": "^2019.6.4", diff --git a/packages/g-plugin-dom-interaction/package.json b/packages/g-plugin-dom-interaction/package.json index 2c4e40064..436ad3e30 100644 --- a/packages/g-plugin-dom-interaction/package.json +++ b/packages/g-plugin-dom-interaction/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-dom-interaction", - "version": "1.7.32", + "version": "1.7.33", "description": "A G plugin", "keywords": [ "antv", diff --git a/packages/g-plugin-dragndrop/package.json b/packages/g-plugin-dragndrop/package.json index 352c64045..2413e689f 100644 --- a/packages/g-plugin-dragndrop/package.json +++ b/packages/g-plugin-dragndrop/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-dragndrop", - "version": "1.6.32", + "version": "1.6.33", "description": "A G plugin for Drag n Drop implemented with PointerEvents", "keywords": [ "antv", diff --git a/packages/g-plugin-gpgpu/package.json b/packages/g-plugin-gpgpu/package.json index 41952f2f9..e881bcc3f 100644 --- a/packages/g-plugin-gpgpu/package.json +++ b/packages/g-plugin-gpgpu/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-gpgpu", - "version": "1.7.32", + "version": "1.7.33", "description": "A G plugin for GPGPU based on WebGPU", "keywords": [ "webgpu", diff --git a/packages/g-plugin-html-renderer/package.json b/packages/g-plugin-html-renderer/package.json index 74c0d19fe..eb17cba85 100644 --- a/packages/g-plugin-html-renderer/package.json +++ b/packages/g-plugin-html-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-html-renderer", - "version": "1.7.32", + "version": "1.7.33", "description": "A G plugin for rendering HTML", "keywords": [ "antv", diff --git a/packages/g-plugin-image-loader/package.json b/packages/g-plugin-image-loader/package.json index 399eadc0c..8684409d1 100644 --- a/packages/g-plugin-image-loader/package.json +++ b/packages/g-plugin-image-loader/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-image-loader", - "version": "1.1.33", + "version": "1.1.34", "description": "A G plugin for loading image", "keywords": [ "antv", diff --git a/packages/g-plugin-matterjs/package.json b/packages/g-plugin-matterjs/package.json index 3694ff6ab..99b102fe2 100644 --- a/packages/g-plugin-matterjs/package.json +++ b/packages/g-plugin-matterjs/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-matterjs", - "version": "1.7.32", + "version": "1.7.33", "description": "A G plugin for matter.js physics engine", "keywords": [ "antv", diff --git a/packages/g-plugin-mobile-interaction/package.json b/packages/g-plugin-mobile-interaction/package.json index 06c9aedbf..94897780f 100644 --- a/packages/g-plugin-mobile-interaction/package.json +++ b/packages/g-plugin-mobile-interaction/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-mobile-interaction", - "version": "0.7.32", + "version": "0.7.33", "description": "A G plugin listening events in mobile environment", "keywords": [ "antv", diff --git a/packages/g-plugin-physx/package.json b/packages/g-plugin-physx/package.json index 438ef84e4..563ce3cd0 100644 --- a/packages/g-plugin-physx/package.json +++ b/packages/g-plugin-physx/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-physx", - "version": "1.7.32", + "version": "1.7.33", "description": "A G plugin for PhysX", "keywords": [ "antv", diff --git a/packages/g-plugin-rough-canvas-renderer/package.json b/packages/g-plugin-rough-canvas-renderer/package.json index fcb3385a6..b66271bea 100644 --- a/packages/g-plugin-rough-canvas-renderer/package.json +++ b/packages/g-plugin-rough-canvas-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-rough-canvas-renderer", - "version": "1.7.33", + "version": "1.7.34", "description": "A G plugin of renderer implementation with rough.js", "keywords": [ "antv", diff --git a/packages/g-plugin-rough-svg-renderer/package.json b/packages/g-plugin-rough-svg-renderer/package.json index 294c9edfa..8b9f1e2f0 100644 --- a/packages/g-plugin-rough-svg-renderer/package.json +++ b/packages/g-plugin-rough-svg-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-rough-svg-renderer", - "version": "1.7.33", + "version": "1.7.34", "description": "A G plugin of renderer implementation with rough.js", "keywords": [ "antv", diff --git a/packages/g-plugin-svg-picker/package.json b/packages/g-plugin-svg-picker/package.json index 1e6697c5a..3e043c2d5 100644 --- a/packages/g-plugin-svg-picker/package.json +++ b/packages/g-plugin-svg-picker/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-svg-picker", - "version": "1.7.32", + "version": "1.7.33", "description": "A G plugin for picking in SVG", "keywords": [ "antv", diff --git a/packages/g-plugin-svg-renderer/package.json b/packages/g-plugin-svg-renderer/package.json index 20946619f..bd841858f 100644 --- a/packages/g-plugin-svg-renderer/package.json +++ b/packages/g-plugin-svg-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-svg-renderer", - "version": "1.8.29", + "version": "1.8.30", "description": "A G plugin of renderer implementation with SVG", "keywords": [ "antv", diff --git a/packages/g-plugin-svg-renderer/src/SVGRendererPlugin.ts b/packages/g-plugin-svg-renderer/src/SVGRendererPlugin.ts index 106ad51b5..d182001c1 100644 --- a/packages/g-plugin-svg-renderer/src/SVGRendererPlugin.ts +++ b/packages/g-plugin-svg-renderer/src/SVGRendererPlugin.ts @@ -163,6 +163,17 @@ export class SVGRendererPlugin implements RenderingPlugin { const handleMounted = (e: FederatedEvent) => { const object = e.target as DisplayObject; + + // should remove clipPath already existed in + const $useRefs = this.clipPathUseMap.get(object); + if ($useRefs) { + const $def = this.defElementManager.getDefElement(); + const existed = $def.querySelector(`#${this.getId(object)}`); + if (existed) { + existed.remove(); + } + } + // create SVG DOM Node this.createSVGDom(document, object, this.$camera); }; @@ -607,8 +618,9 @@ export class SVGRendererPlugin implements RenderingPlugin { this.createOrUpdateHitArea(object, $el, $groupEl); const $parentGroupEl = + root || // @ts-ignore - (object.parentNode && object.parentNode.elementSVG?.$groupEl) || root; + (object.parentNode && object.parentNode.elementSVG?.$groupEl); if ($parentGroupEl) { $parentGroupEl.appendChild($groupEl); diff --git a/packages/g-plugin-webgl-device/package.json b/packages/g-plugin-webgl-device/package.json index ac50ca0c7..6551438f3 100644 --- a/packages/g-plugin-webgl-device/package.json +++ b/packages/g-plugin-webgl-device/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-webgl-device", - "version": "1.7.32", + "version": "1.7.33", "description": "A G plugin implements GPUDevice interface with WebGL API", "keywords": [ "antv", diff --git a/packages/g-plugin-webgpu-device/package.json b/packages/g-plugin-webgpu-device/package.json index 62257294b..6be3218d9 100644 --- a/packages/g-plugin-webgpu-device/package.json +++ b/packages/g-plugin-webgpu-device/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-webgpu-device", - "version": "1.7.32", + "version": "1.7.33", "description": "A G plugin implements GPUDevice interface with WebGPU API", "keywords": [ "antv", diff --git a/packages/g-plugin-yoga/package.json b/packages/g-plugin-yoga/package.json index 657574a82..ae0f7c81c 100644 --- a/packages/g-plugin-yoga/package.json +++ b/packages/g-plugin-yoga/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-yoga", - "version": "1.7.32", + "version": "1.7.33", "description": "A G plugin for Yoga layout engine", "keywords": [ "antv", diff --git a/packages/g-shader-components/package.json b/packages/g-shader-components/package.json index 07eda47e7..784cb3316 100644 --- a/packages/g-shader-components/package.json +++ b/packages/g-shader-components/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-shader-components", - "version": "1.7.32", + "version": "1.7.33", "description": "Shader components based on glslify", "keywords": [ "antv", diff --git a/packages/g-svg/package.json b/packages/g-svg/package.json index fdcb872bd..e426b4088 100644 --- a/packages/g-svg/package.json +++ b/packages/g-svg/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-svg", - "version": "1.8.29", + "version": "1.8.30", "description": "A renderer implemented by SVG", "keywords": [ "antv", @@ -30,9 +30,9 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-plugin-dom-interaction": "^1.7.32", - "@antv/g-plugin-svg-picker": "^1.7.32", - "@antv/g-plugin-svg-renderer": "^1.8.29", + "@antv/g-plugin-dom-interaction": "^1.7.33", + "@antv/g-plugin-svg-picker": "^1.7.33", + "@antv/g-plugin-svg-renderer": "^1.8.30", "@antv/util": "^3.3.1", "tslib": "^2.3.1" }, diff --git a/packages/g-web-animations-api/package.json b/packages/g-web-animations-api/package.json index f3f17152f..3c2d017bf 100644 --- a/packages/g-web-animations-api/package.json +++ b/packages/g-web-animations-api/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-web-animations-api", - "version": "1.0.21", + "version": "1.0.22", "description": "A simple implementation of Web Animations API.", "keywords": [ "antv", diff --git a/packages/g-web-components/package.json b/packages/g-web-components/package.json index 4f1b93e71..b3261b9a0 100644 --- a/packages/g-web-components/package.json +++ b/packages/g-web-components/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-web-components", - "version": "1.7.32", + "version": "1.7.33", "description": "A declarative usage for G implemented with WebComponents", "keywords": [ "antv", diff --git a/packages/g-webgl/package.json b/packages/g-webgl/package.json index b3148dfd1..00e02cc7f 100644 --- a/packages/g-webgl/package.json +++ b/packages/g-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-webgl", - "version": "1.7.35", + "version": "1.7.36", "description": "A renderer implemented by WebGL1/2", "keywords": [ "antv", @@ -30,11 +30,11 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-plugin-device-renderer": "^1.7.35", - "@antv/g-plugin-dom-interaction": "^1.7.32", - "@antv/g-plugin-html-renderer": "^1.7.32", - "@antv/g-plugin-image-loader": "^1.1.33", - "@antv/g-plugin-webgl-device": "^1.7.32", + "@antv/g-plugin-device-renderer": "^1.7.36", + "@antv/g-plugin-dom-interaction": "^1.7.33", + "@antv/g-plugin-html-renderer": "^1.7.33", + "@antv/g-plugin-image-loader": "^1.1.34", + "@antv/g-plugin-webgl-device": "^1.7.33", "@antv/util": "^3.3.1" }, "devDependencies": { diff --git a/packages/g-webgpu/package.json b/packages/g-webgpu/package.json index 421322699..61270a023 100644 --- a/packages/g-webgpu/package.json +++ b/packages/g-webgpu/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-webgpu", - "version": "1.7.35", + "version": "1.7.36", "description": "A renderer implemented by WebGPU", "keywords": [ "antv", @@ -30,11 +30,11 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-plugin-device-renderer": "^1.7.35", - "@antv/g-plugin-dom-interaction": "^1.7.32", - "@antv/g-plugin-html-renderer": "^1.7.32", - "@antv/g-plugin-image-loader": "^1.1.33", - "@antv/g-plugin-webgpu-device": "^1.7.32", + "@antv/g-plugin-device-renderer": "^1.7.36", + "@antv/g-plugin-dom-interaction": "^1.7.33", + "@antv/g-plugin-html-renderer": "^1.7.33", + "@antv/g-plugin-image-loader": "^1.1.34", + "@antv/g-plugin-webgpu-device": "^1.7.33", "@antv/util": "^3.3.1", "@webgpu/types": "^0.1.6" }, diff --git a/packages/g/package.json b/packages/g/package.json index 62bf1cee6..05bba5dc9 100644 --- a/packages/g/package.json +++ b/packages/g/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g", - "version": "5.15.1", + "version": "5.15.2", "description": "A core module for rendering engine implements DOM API.", "keywords": [ "antv", @@ -32,12 +32,12 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g-camera-api": "^1.0.21", - "@antv/g-css-layout-api": "^1.0.21", - "@antv/g-css-typed-om-api": "^1.0.21", - "@antv/g-dom-mutation-observer-api": "^1.0.21", - "@antv/g-lite": "^1.0.21", - "@antv/g-web-animations-api": "^1.0.21" + "@antv/g-camera-api": "^1.0.22", + "@antv/g-css-layout-api": "^1.0.22", + "@antv/g-css-typed-om-api": "^1.0.22", + "@antv/g-dom-mutation-observer-api": "^1.0.22", + "@antv/g-lite": "^1.0.22", + "@antv/g-web-animations-api": "^1.0.22" }, "publishConfig": { "access": "public" diff --git a/packages/react-g/package.json b/packages/react-g/package.json index a87dc831d..15c990c4d 100644 --- a/packages/react-g/package.json +++ b/packages/react-g/package.json @@ -1,6 +1,6 @@ { "name": "@antv/react-g", - "version": "1.8.29", + "version": "1.8.30", "description": "react render for @antv/g", "keywords": [ "react", @@ -31,7 +31,7 @@ "sync": "tnpm sync" }, "dependencies": { - "@antv/g": "^5.15.1", + "@antv/g": "^5.15.2", "@antv/util": "^3.3.1", "react-reconciler": "^0.26.2", "scheduler": "^0.20.2", diff --git a/site/docs/plugins/annotation.en.md b/site/docs/plugins/annotation.en.md index 8ef348110..24b35404f 100644 --- a/site/docs/plugins/annotation.en.md +++ b/site/docs/plugins/annotation.en.md @@ -172,6 +172,12 @@ The default value is `false` to delete the selected interactive graphics using k When enabled, you can use the `Delete` / `Esc` / `Backspace` keys to delete the selected interactive graphics. +### enableContinuousBrush + +Whether to support continuous pressing of `shift` for frame selection, the default value is `true`. + +After closing, each frame selection will clear the previous result and re-select. + ### arrowKeyStepLength In edit mode, use the keyboard up, down, left and right arrow keys to move the graph in steps, the default value is `4`. diff --git a/site/docs/plugins/annotation.zh.md b/site/docs/plugins/annotation.zh.md index 4879b97ca..8d2bb5fc5 100644 --- a/site/docs/plugins/annotation.zh.md +++ b/site/docs/plugins/annotation.zh.md @@ -172,6 +172,12 @@ circle.style.selectable = true; 开启后,可使用 `Delete` / `Esc` / `Backspace` 按键删除已选中的可交互图形。 +### enableContinuousBrush + +是否支持连续按住 `shift` 进行框选,默认值为 `true`。 + +关闭后,每次框选都会清除上一次的结果,重新选择。 + ### arrowKeyStepLength 编辑模式下,使用键盘上下左右方向键移动图形的步长,默认值为 `4`。 diff --git a/site/examples/camera/camera-action/demo/meta.json b/site/examples/camera/camera-action/demo/meta.json index 450a57d35..db1c489c5 100644 --- a/site/examples/camera/camera-action/demo/meta.json +++ b/site/examples/camera/camera-action/demo/meta.json @@ -13,7 +13,8 @@ "title": { "zh": "View Offset", "en": "View Offset" - } + }, + "screenshot": "https://mdn.alipayobjects.com/antforest/afts/img/A*4C_tQLZJ_24AAAAAAAAAAAAADrd2AQ/Dec-13-2022%2014-05-16.gif" }, { "filename": "zoom-by-point.js", diff --git a/site/examples/ecosystem/lottie/demo/arrow.js b/site/examples/ecosystem/lottie/demo/arrow.js new file mode 100644 index 000000000..b3a736569 --- /dev/null +++ b/site/examples/ecosystem/lottie/demo/arrow.js @@ -0,0 +1,90 @@ +import { Canvas, CanvasEvent } from '@antv/g'; +import { Renderer as CanvasRenderer } from '@antv/g-canvas'; +import { Renderer as CanvaskitRenderer } from '@antv/g-canvaskit'; +import { loadAnimation } from '@antv/g-lottie-player'; +import { Renderer as SVGRenderer } from '@antv/g-svg'; +import { Renderer as WebGLRenderer } from '@antv/g-webgl'; +import { Renderer as WebGPURenderer } from '@antv/g-webgpu'; +import * as lil from 'lil-gui'; +import Stats from 'stats.js'; +import * as d3 from 'd3'; + +/** + * @see https://lottiefiles.github.io/lottie-docs/concepts/#transform + */ + +// create a renderer +const canvasRenderer = new CanvasRenderer(); +const svgRenderer = new SVGRenderer(); +const webglRenderer = new WebGLRenderer(); +const webgpuRenderer = new WebGPURenderer(); +const canvaskitRenderer = new CanvaskitRenderer({ + wasmDir: '/', + fonts: [ + { + name: 'sans-serif', + url: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/file/A*064aSK2LUPEAAAAAAAAAAAAADmJ7AQ/NotoSansCJKsc-VF.ttf', + }, + ], +}); + +// create a canvas +const canvas = new Canvas({ + container: 'container', + width: 600, + height: 500, + renderer: canvasRenderer, +}); + +canvas.addEventListener(CanvasEvent.READY, async () => { + const data = await d3.json('/lottie/arrow.json'); + const animation = loadAnimation(data, { loop: true }); + const wrapper = animation.render(canvas); +}); + +// stats +const stats = new Stats(); +stats.showPanel(0); +const $stats = stats.dom; +$stats.style.position = 'absolute'; +$stats.style.left = '0px'; +$stats.style.top = '0px'; +const $wrapper = document.getElementById('container'); +$wrapper.appendChild($stats); +canvas.addEventListener(CanvasEvent.AFTER_RENDER, () => { + if (stats) { + stats.update(); + } +}); + +// GUI +const gui = new lil.GUI({ autoPlace: false }); +$wrapper.appendChild(gui.domElement); +const rendererFolder = gui.addFolder('renderer'); +const rendererConfig = { + renderer: 'canvas', +}; +rendererFolder + .add(rendererConfig, 'renderer', [ + 'canvas', + 'svg', + 'webgl', + 'webgpu', + 'canvaskit', + ]) + .onChange((rendererName) => { + let renderer; + if (rendererName === 'canvas') { + renderer = canvasRenderer; + } else if (rendererName === 'svg') { + renderer = svgRenderer; + } else if (rendererName === 'webgl') { + renderer = webglRenderer; + } else if (rendererName === 'webgpu') { + renderer = webgpuRenderer; + } else if (rendererName === 'canvaskit') { + renderer = canvaskitRenderer; + } + canvas.setRenderer(renderer); + }); +rendererFolder.open(); diff --git a/site/examples/ecosystem/lottie/demo/meta.json b/site/examples/ecosystem/lottie/demo/meta.json index a161357ed..299df294c 100644 --- a/site/examples/ecosystem/lottie/demo/meta.json +++ b/site/examples/ecosystem/lottie/demo/meta.json @@ -48,6 +48,13 @@ "zh": "弹簧", "en": "Spring" } + }, + { + "filename": "arrow.js", + "title": { + "zh": "箭头", + "en": "Arrow" + } } ] } diff --git a/site/examples/event/dragndrop/demo/meta.json b/site/examples/event/dragndrop/demo/meta.json index 7f004e609..2960ab869 100644 --- a/site/examples/event/dragndrop/demo/meta.json +++ b/site/examples/event/dragndrop/demo/meta.json @@ -17,7 +17,8 @@ "title": { "zh": "使用 PointerEvents 实现拖拽", "en": "Drag with PointerEvents" - } + }, + "screenshot": "https://mdn.alipayobjects.com/antforest/afts/img/A*Z_xHTIB2l2sAAAAAAAAAAAAADrd2AQ/Dec-13-2022%2014-03-24.gif" } ] } diff --git a/site/examples/event/gesture/demo/meta.json b/site/examples/event/gesture/demo/meta.json index 7a7cd444f..674491846 100644 --- a/site/examples/event/gesture/demo/meta.json +++ b/site/examples/event/gesture/demo/meta.json @@ -9,7 +9,8 @@ "title": { "zh": "使用 PointerEvents 实现 Pinch 手势", "en": "Pinch zoom gestures with PointerEvents" - } + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*0cgWSKwc53EAAAAAAAAAAAAADmJ7AQ/original" }, { "filename": "hammer.js", @@ -24,7 +25,8 @@ "title": { "zh": "使用 Hammer.js 手势库实现图片缩放", "en": "Gesture with Hammer.js" - } + }, + "screenshot": "https://mdn.alipayobjects.com/antforest/afts/img/A*sXIXRbjkgVAAAAAAAAAAAAAADrd2AQ/Dec-13-2022%2014-00-07.gif" } ] } diff --git a/site/examples/plugins/others/demo/annotation.js b/site/examples/plugins/annotation/demo/annotation.js similarity index 100% rename from site/examples/plugins/others/demo/annotation.js rename to site/examples/plugins/annotation/demo/annotation.js diff --git a/site/examples/plugins/annotation/demo/meta.json b/site/examples/plugins/annotation/demo/meta.json new file mode 100644 index 000000000..1d2f4cfe1 --- /dev/null +++ b/site/examples/plugins/annotation/demo/meta.json @@ -0,0 +1,12 @@ +{ + "demos": [ + { + "filename": "annotation.js", + "title": { + "zh": "使用标注", + "en": "Use annotation" + }, + "screenshot": "https://mdn.alipayobjects.com/antforest/afts/img/A*joHKRpe9U4YAAAAAAAAAAAAADrd2AQ/Dec-13-2022%2015-08-49.gif" + } + ] +} diff --git a/site/examples/plugins/others/index.en.md b/site/examples/plugins/annotation/index.en.md similarity index 50% rename from site/examples/plugins/others/index.en.md rename to site/examples/plugins/annotation/index.en.md index 6eb27b6c2..7193cee89 100644 --- a/site/examples/plugins/others/index.en.md +++ b/site/examples/plugins/annotation/index.en.md @@ -1,4 +1,4 @@ --- -title: Others +title: Annotation order: 20 --- diff --git a/site/examples/plugins/others/index.zh.md b/site/examples/plugins/annotation/index.zh.md similarity index 56% rename from site/examples/plugins/others/index.zh.md rename to site/examples/plugins/annotation/index.zh.md index 7be3b47c5..c29745241 100644 --- a/site/examples/plugins/others/index.zh.md +++ b/site/examples/plugins/annotation/index.zh.md @@ -1,4 +1,4 @@ --- -title: 其它 +title: 标注 order: 20 --- diff --git a/site/examples/plugins/control/demo/meta.json b/site/examples/plugins/control/demo/meta.json new file mode 100644 index 000000000..44f97f53c --- /dev/null +++ b/site/examples/plugins/control/demo/meta.json @@ -0,0 +1,12 @@ +{ + "demos": [ + { + "filename": "orbit-control.js", + "title": { + "zh": "使用 Orbit Control", + "en": "Use orbit control" + }, + "screenshot": "https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*1u8eRKMbVX8AAAAAAAAAAAAAARQnAQ" + } + ] +} diff --git a/site/examples/plugins/others/demo/orbit-control.js b/site/examples/plugins/control/demo/orbit-control.js similarity index 100% rename from site/examples/plugins/others/demo/orbit-control.js rename to site/examples/plugins/control/demo/orbit-control.js diff --git a/site/examples/plugins/control/index.en.md b/site/examples/plugins/control/index.en.md new file mode 100644 index 000000000..1bf1202ba --- /dev/null +++ b/site/examples/plugins/control/index.en.md @@ -0,0 +1,4 @@ +--- +title: Camera Control +order: 20 +--- diff --git a/site/examples/plugins/control/index.zh.md b/site/examples/plugins/control/index.zh.md new file mode 100644 index 000000000..b1d99d943 --- /dev/null +++ b/site/examples/plugins/control/index.zh.md @@ -0,0 +1,4 @@ +--- +title: 相机控制 +order: 20 +--- diff --git a/site/examples/plugins/others/demo/css-select.js b/site/examples/plugins/css-select/demo/css-select.js similarity index 100% rename from site/examples/plugins/others/demo/css-select.js rename to site/examples/plugins/css-select/demo/css-select.js diff --git a/site/examples/plugins/css-select/demo/meta.json b/site/examples/plugins/css-select/demo/meta.json new file mode 100644 index 000000000..e2cd2315a --- /dev/null +++ b/site/examples/plugins/css-select/demo/meta.json @@ -0,0 +1,12 @@ +{ + "demos": [ + { + "filename": "css-select.js", + "title": { + "zh": "CSS 选择器插件", + "en": "CSS Selector Plugin" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*enWBR60fAnEAAAAAAAAAAAAADmJ7AQ/original" + } + ] +} diff --git a/site/examples/plugins/css-select/index.en.md b/site/examples/plugins/css-select/index.en.md new file mode 100644 index 000000000..d0ebb0844 --- /dev/null +++ b/site/examples/plugins/css-select/index.en.md @@ -0,0 +1,4 @@ +--- +title: CSS Select +order: 20 +--- diff --git a/site/examples/plugins/css-select/index.zh.md b/site/examples/plugins/css-select/index.zh.md new file mode 100644 index 000000000..46df49c04 --- /dev/null +++ b/site/examples/plugins/css-select/index.zh.md @@ -0,0 +1,4 @@ +--- +title: CSS 选择器 +order: 20 +--- diff --git a/site/examples/plugins/dragndrop/demo/meta.json b/site/examples/plugins/dragndrop/demo/meta.json index deb39b4e4..68e4d5879 100644 --- a/site/examples/plugins/dragndrop/demo/meta.json +++ b/site/examples/plugins/dragndrop/demo/meta.json @@ -17,14 +17,16 @@ "title": { "zh": "在 Group 上使用拖放", "en": "Use Drag'n'Drop on Group" - } + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*TBlQQYoxQfQAAAAAAAAAAAAADmJ7AQ/original" }, { "filename": "dragndrop-perf.js", "title": { "zh": "拖放性能测试", "en": "Drag'n'Drop Perf" - } + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*68gxTJFGvO4AAAAAAAAAAAAADmJ7AQ/original" } ] } diff --git a/site/examples/plugins/others/demo/meta.json b/site/examples/plugins/others/demo/meta.json deleted file mode 100644 index 7af78b019..000000000 --- a/site/examples/plugins/others/demo/meta.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "demos": [ - { - "filename": "css-select.js", - "title": { - "zh": "CSS 选择器插件", - "en": "CSS Selector Plugin" - } - }, - { - "filename": "orbit-control.js", - "title": { - "zh": "使用 Orbit Control", - "en": "Use orbit control" - }, - "screenshot": "https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*1u8eRKMbVX8AAAAAAAAAAAAAARQnAQ" - }, - { - "filename": "annotation.js", - "title": { - "zh": "使用标注", - "en": "Use annotation" - } - } - ] -} diff --git a/site/examples/style/clip-path/demo/animated.ts b/site/examples/style/clip-path/demo/animated.ts new file mode 100644 index 000000000..884288afa --- /dev/null +++ b/site/examples/style/clip-path/demo/animated.ts @@ -0,0 +1,135 @@ +import { Canvas, CanvasEvent, Circle, Group } from '@antv/g'; +import { Sector } from '@antv/g-components'; +import { Renderer as CanvasRenderer } from '@antv/g-canvas'; +import { Renderer as CanvaskitRenderer } from '@antv/g-canvaskit'; +import { Renderer as SVGRenderer } from '@antv/g-svg'; +import { Renderer as WebGLRenderer } from '@antv/g-webgl'; +import { Renderer as WebGPURenderer } from '@antv/g-webgpu'; +import * as lil from 'lil-gui'; +import Stats from 'stats.js'; + +// create a renderer +const canvasRenderer = new CanvasRenderer(); +const webglRenderer = new WebGLRenderer(); +const svgRenderer = new SVGRenderer(); +const canvaskitRenderer = new CanvaskitRenderer({ + wasmDir: '/', + fonts: [ + { + name: 'sans-serif', + url: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/file/A*064aSK2LUPEAAAAAAAAAAAAADmJ7AQ/NotoSansCJKsc-VF.ttf', + }, + ], +}); +const webgpuRenderer = new WebGPURenderer(); + +// create a canvas +const canvas = new Canvas({ + container: 'container', + width: 600, + height: 500, + renderer: canvasRenderer, +}); + +const sector = new Sector({ + style: { + x: 150, + y: 100, + lineWidth: 1, + sr: 100, + startAngle: -90, + fill: 'yellow', + opacity: 0.5, + }, +}); + +canvas.addEventListener(CanvasEvent.READY, () => { + const group = new Group({ + style: { + clipPath: sector, + }, + }); + const circle1 = new Circle({ + style: { + fill: 'red', + cx: 100, + cy: 100, + r: 20, + }, + }); + const circle2 = new Circle({ + style: { + fill: 'red', + cx: 150, + cy: 100, + r: 20, + }, + }); + canvas.appendChild(group); + group.appendChild(circle1); + group.appendChild(circle2); + canvas.appendChild(sector); + + sector.animate( + [ + { + endAngle: -90, + }, + { + endAngle: 270, + }, + ], + { + duration: 1000, + iterations: Infinity, + fill: 'both', + }, + ); +}); + +// stats +const stats = new Stats(); +stats.showPanel(0); +const $stats = stats.dom; +$stats.style.position = 'absolute'; +$stats.style.left = '0px'; +$stats.style.top = '0px'; +const $wrapper = document.getElementById('container'); +$wrapper.appendChild($stats); +canvas.addEventListener(CanvasEvent.AFTER_RENDER, () => { + if (stats) { + stats.update(); + } +}); + +// GUI +const gui = new lil.GUI({ autoPlace: false }); +$wrapper.appendChild(gui.domElement); +const rendererFolder = gui.addFolder('renderer'); +const rendererConfig = { + renderer: 'canvas', +}; +rendererFolder + .add(rendererConfig, 'renderer', [ + 'canvas', + 'svg', + 'webgl', + 'webgpu', + 'canvaskit', + ]) + .onChange((rendererName) => { + let renderer; + if (rendererName === 'canvas') { + renderer = canvasRenderer; + } else if (rendererName === 'svg') { + renderer = svgRenderer; + } else if (rendererName === 'webgl') { + renderer = webglRenderer; + } else if (rendererName === 'webgpu') { + renderer = webgpuRenderer; + } else if (rendererName === 'canvaskit') { + renderer = canvaskitRenderer; + } + canvas.setRenderer(renderer); + }); +rendererFolder.open(); diff --git a/site/examples/style/clip-path/demo/meta.json b/site/examples/style/clip-path/demo/meta.json index 603fb7a46..246858460 100644 --- a/site/examples/style/clip-path/demo/meta.json +++ b/site/examples/style/clip-path/demo/meta.json @@ -7,6 +7,14 @@ "en": "Clip Path" }, "screenshot": "https://gw.alipayobjects.com/zos/raptor/1669181270740/Nov-23-2022%25252013-25-56.gif" + }, + { + "filename": "animated.ts", + "title": { + "zh": "对裁剪区域应用动画", + "en": "Animated ClipPath" + }, + "screenshot": "https://mdn.alipayobjects.com/antforest/afts/img/A*2OssQK89ur0AAAAAAAAAAAAADrd2AQ/Dec-13-2022%2011-55-46.gif" } ] } diff --git a/site/static/lottie/arrow.json b/site/static/lottie/arrow.json new file mode 100644 index 000000000..28b2bce2d --- /dev/null +++ b/site/static/lottie/arrow.json @@ -0,0 +1,442 @@ +{ + "v": "5.9.4", + "fr": 30, + "ip": 0, + "op": 240, + "w": 750, + "h": 700, + "nm": "配置顺序", + "ddd": 0, + "assets": [ + { + "id": "0", + "w": 107, + "h": 32, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGsAAAAgBAMAAADnDpuQAAAAJHpUWHRDcmVhdG9yAAAImXNMyU9KVXBMK0ktUnBNS0tNLikGAEF6Bs5qehXFAAAACXBIWXMAAAABAAAAAQBPJcTWAAAAFVBMVEVHcEwDH24HJG8FIW4EIW0XMngLJXGTC7URAAAAB3RSTlMASCMxPQsWQwqyEAAAAfRJREFUOMvtlMt2pCAQhhEva0mrawR1rWL32lt6rX2i67YTff9HCEphzJk5M32yDhssqa+g/qJA6Hf8OYafYZWXJ91zro/jbkVGRMPmJ7A+4cVJG7zvRl6R/+1oP0RFvsLzZlqnSVl4mYdvidvDEm+f2fdkPEIaOUXKmmRI4rV0/X7rUJ0RQq7binQYHgXRe/uXvJCzAAz1nRW/bZixpGJZXsAxROsZtWW75YXLuda7ZSxMNObKYNpx6pYOWSlYzmv5Km5JB6vD8giFaO+AcSy8qlQy3lEUNzo1nFO/nggJNstsBMsSUMWK3chqGHc3y6DIyXw0KFnMFmVBaINc9sJYVbTkpDA/MtPRUZhFZQ28itwhpFSl2HV1GGshIDJTfzLTyPGVY1IQckpCtWZ4grlix/ALF0XlAxasmK2xfDZTLZ3BeFXWX1ggE4Njmem1x2VoQ9pSRFxiF+6ZNFK5kMPBaqljpdZwWfe3ckIHzHUolKPJ38/+Xh7zKjPDO2bc3PCAQZrrneEFSfz9h6xA20KlcJnL0kUQURYAwXlVlxozEVEJ2HlY/QETxkybEelyO+/+sSXQjbcgutUUh924RZ0gpHBbUe/RvzfV+HGGNDQ2pY7qTPyPXoy2tsnqGEQwmdfJS/zMkzQujF82jCI8099H+qnxCTRIVCwPkdqtAAAAAElFTkSuQmCC", + "e": 1 + }, + { + "id": "1", + "w": 713, + "h": 501, + "u": "", + "p": "data:image/png;base64,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", + "e": 1 + } + ], + "layers": [ + { + "ddd": 0, + "ind": 1, + "ty": 2, + "nm": "文字配置顺序.png", + "cl": "png", + "refId": "0", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [375, 605, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [53.5, 16, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "hasMask": true, + "masksProperties": [ + { + "inv": false, + "mode": "a", + "pt": { + "a": 1, + "k": [ + { + "i": { "x": 0.833, "y": 1 }, + "o": { "x": 0.167, "y": 0 }, + "t": 97.817, + "s": [ + { + "i": [ + [0, 0], + [-1135.627, 0], + [-21.44, -233.444], + [-2.451, 0], + [-2.748, 2.025] + ], + "o": [ + [0, 0], + [921.687, -263.672], + [2.576, 28.049], + [154.397, -34.584], + [52.909, -38.967] + ], + "v": [ + [-258.072, -463.35], + [-395.373, -190.287], + [77.459, -4.767], + [-111.817, -344.649], + [474.247, -459.64] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.716 }, + "o": { "x": 0.172, "y": 0 }, + "t": 98.098, + "s": [ + { + "i": [ + [0, 0], + [-1135.627, 0], + [-21.44, -233.444], + [-2.451, 0], + [-2.748, 2.025] + ], + "o": [ + [0, 0], + [921.687, -263.672], + [2.576, 28.049], + [154.397, -34.584], + [52.909, -38.967] + ], + "v": [ + [-258.072, -463.35], + [-395.373, -46.287], + [77.459, -4.767], + [-111.817, -344.649], + [474.247, -459.64] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.604, "y": 0.324 }, + "o": { "x": 0.376, "y": 0.642 }, + "t": 108.993, + "s": [ + { + "i": [ + [0, 0], + [-757.938, 67.854], + [-269.207, -184.514], + [-2.451, 0], + [-2.748, 2.025] + ], + "o": [ + [0, 0], + [577.6, -396.43], + [27.943, 19.152], + [154.397, -34.584], + [52.909, -38.967] + ], + "v": [ + [-258.072, -463.35], + [18.883, 301.25], + [56.487, -64.83], + [-111.819, -344.649], + [474.247, -459.64] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 1 }, + "o": { "x": 0.586, "y": 1 }, + "t": 117.192, + "s": [ + { + "i": [ + [0, 0], + [-757.938, 67.854], + [-2.224, -347.141], + [-2.451, 0], + [-2.748, 2.025] + ], + "o": [ + [0, 0], + [425.619, -455.068], + [0.181, 28.166], + [154.398, -34.584], + [52.909, -38.967] + ], + "v": [ + [-258.072, -463.35], + [389.98, 406.383], + [47.224, -91.359], + [-111.819, -344.649], + [474.247, -459.64] + ], + "c": true + } + ] + }, + { + "t": 120, + "s": [ + { + "i": [ + [0, 0], + [-757.938, 67.854], + [-86.224, -487.141], + [-2.451, 0], + [-2.748, 2.025] + ], + "o": [ + [0, 0], + [425.619, -455.068], + [4.909, 27.736], + [154.398, -34.584], + [52.909, -38.967] + ], + "v": [ + [-258.072, -463.35], + [389.98, 406.383], + [47.224, -91.359], + [-111.819, -344.649], + [474.247, -459.64] + ], + "c": true + } + ] + } + ], + "ix": 1 + }, + "o": { "a": 0, "k": 100, "ix": 3 }, + "x": { "a": 0, "k": 0, "ix": 4 }, + "nm": "蒙版 1" + } + ], + "ip": 15.5, + "op": 6015.5, + "st": 15.5, + "bm": 0 + }, + { + "ddd": 0, + "ind": 2, + "ty": 2, + "nm": "最外面的无字环.png", + "cl": "png", + "refId": "1", + "sr": 1, + "ks": { + "o": { + "a": 1, + "k": [ + { + "i": { "x": [0.833], "y": [1] }, + "o": { "x": [0.333], "y": [0] }, + "t": 90, + "s": [100] + }, + { + "i": { "x": [0.842], "y": [1] }, + "o": { "x": [0.191], "y": [0] }, + "t": 97, + "s": [0] + }, + { "t": 111.5, "s": [100] } + ], + "ix": 11 + }, + "r": { + "a": 1, + "k": [ + { + "i": { "x": [0], "y": [1] }, + "o": { "x": [0.179], "y": [0] }, + "t": 90, + "s": [0] + }, + { "t": 126, "s": [-360] } + ], + "ix": 10 + }, + "p": { "a": 0, "k": [368, 361, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [350.5, 144.5, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "hasMask": true, + "masksProperties": [ + { + "inv": false, + "mode": "a", + "pt": { + "a": 1, + "k": [ + { + "i": { "x": 0.833, "y": 1 }, + "o": { "x": 0.167, "y": 0 }, + "t": 68, + "s": [ + { + "i": [ + [0, 0], + [-1135.627, 0], + [-21.44, -233.444], + [-2.451, 0], + [-2.748, 2.025] + ], + "o": [ + [0, 0], + [921.687, -263.672], + [2.576, 28.049], + [154.397, -34.584], + [52.909, -38.967] + ], + "v": [ + [44.928, -228.85], + [-92.373, 44.213], + [380.459, 229.733], + [191.183, -110.149], + [777.247, -225.14] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.716 }, + "o": { "x": 0.172, "y": 0 }, + "t": 68.281, + "s": [ + { + "i": [ + [0, 0], + [-1135.627, 0], + [-21.44, -233.444], + [-2.451, 0], + [-2.748, 2.025] + ], + "o": [ + [0, 0], + [921.687, -263.672], + [2.576, 28.049], + [154.397, -34.584], + [52.909, -38.967] + ], + "v": [ + [44.928, -228.85], + [-92.373, 188.213], + [380.459, 229.733], + [191.183, -110.149], + [777.247, -225.14] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.604, "y": 0.324 }, + "o": { "x": 0.376, "y": 0.642 }, + "t": 79.176, + "s": [ + { + "i": [ + [0, 0], + [-757.938, 67.854], + [-269.207, -184.514], + [-2.451, 0], + [-2.748, 2.025] + ], + "o": [ + [0, 0], + [577.6, -396.43], + [27.943, 19.152], + [154.397, -34.584], + [52.909, -38.967] + ], + "v": [ + [44.928, -228.85], + [321.883, 535.75], + [359.487, 169.67], + [191.181, -110.149], + [777.247, -225.14] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 1 }, + "o": { "x": 0.586, "y": 1 }, + "t": 87.375, + "s": [ + { + "i": [ + [0, 0], + [-757.938, 67.854], + [-2.224, -347.141], + [-2.451, 0], + [-2.748, 2.025] + ], + "o": [ + [0, 0], + [425.619, -455.068], + [0.181, 28.166], + [154.398, -34.584], + [52.909, -38.967] + ], + "v": [ + [44.928, -228.85], + [692.98, 640.883], + [350.224, 143.141], + [191.181, -110.149], + [777.247, -225.14] + ], + "c": true + } + ] + }, + { + "t": 90.183, + "s": [ + { + "i": [ + [0, 0], + [-757.938, 67.854], + [-86.224, -487.141], + [-2.451, 0], + [-2.748, 2.025] + ], + "o": [ + [0, 0], + [425.619, -455.068], + [4.909, 27.736], + [154.398, -34.584], + [52.909, -38.967] + ], + "v": [ + [44.928, -228.85], + [692.98, 640.883], + [350.224, 143.141], + [191.181, -110.149], + [777.247, -225.14] + ], + "c": true + } + ] + } + ], + "ix": 1 + }, + "o": { "a": 0, "k": 100, "ix": 3 }, + "x": { "a": 0, "k": 0, "ix": 4 }, + "nm": "蒙版 1" + } + ], + "ip": -60, + "op": 5940, + "st": -60, + "bm": 0 + } + ], + "markers": [], + "tiny": 0.55 +} diff --git a/site/static/lottie/radar3.json b/site/static/lottie/radar3.json new file mode 100644 index 000000000..07d116ecd --- /dev/null +++ b/site/static/lottie/radar3.json @@ -0,0 +1,1395 @@ +{ + "v": "5.9.4", + "fr": 30, + "ip": 0, + "op": 25, + "w": 235, + "h": 235, + "nm": "帮你配 赛道", + "ddd": 0, + "assets": [ + { + "id": "0", + "w": 35, + "h": 125, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAB9BAMAAADac8ftAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAwUExURUdwTPn8//j8//n8//n8//z///n8//j7//n8//j7//n7//n8//////n8//j8//j7/49ZQY8AAAAPdFJOUwDI5LCZEiZhcoU7UQfzSpxMZe4AAAGsSURBVEjHnZW7TgJBFIYXAa+Ia3gAiS8AhT2UWkljrY228gRCbwFvgJWFMdHeAnobYm2CT8CGi8AiuMZw1pn4DZMNW22+QOb8lznrvL50uw/3V2eOeuLzt8P9o5PbR4XSweLxFUrlFmjeUuxUfvas0JOgvEJrgj4V2hI0VmhbUE+bTI4MLhRqCKrySNd6ZELQhCq1I1MdYSXFCoLKClWo8lzQu0IxQd8UPqTwvia8Q+EFCq9ximtOEXoxpRdavBv0Yl1Q0GIiHxyszsFcDjZTaJeDxRlS6NiAuWmOJQM6lmNu0WYNC9VmuiP6Oub4vnX8HY7/Z3WJHbhT6IAdCK9g0VoLT1CWgWhXZI+BxCKJTLDVm+xT2qJbVSxlSdJgRZlW1Lktitar6y2va5YVaNOwGVsxooeGnn/RwzE9nPCa+qyTYaUY0IB3Rl9/hiVsWE85IsljHgkFDq+kwyANX5qSFTWIamyTAVX4x5VRMxLyqNGjE01a2KT3y1FvVaTVJNQ4JPLtqIZGh0jrfRjalGjETszYnDaRy8rliYpsdPV/7/sZbeck+5njm8vftx95FsPDwox41gAAAABJRU5ErkJggg==", + "e": 1 + }, + { + "id": "1", + "w": 36, + "h": 120, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAB4BAMAAABoYk0nAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAwUExURUdwTPn8//j8//v///n8//j8//n9//n8//n7//n7//j7//n9//////n7//f///j7/78zKTEAAAAPdFJOUwD1wBBS5YtsodI+KAayHT1/GREAAAGpSURBVEjHrZY7TgJRFIaRQUVRQuIChh2IK5DeRImVHcSYWMoOMG5AK2OnHY0BduCQ2FlIZYsLsHDQ4SkeH3PxXuZjzJg41eQr5p7/cW4mFps8qe1Y8EldHDwFUFp2D2vTyBLxHracKSYi7vk0sz+Z7NWcIJJxw0DFb+SWgMRElz46JmoZaN1HWaIzokIklImEniOhF07/L6hIZEdCAmQJpk8TpQROLIcjw9VbQRyLRAuCHCfISDsp6EScaElQpnmFyhrdK5TX6IaortCVRjsKPWpUUcjo/ZFPPMP6to8GTLbDzPoMqKvRnUI9jRIKDengiA6+0cEC7TLS2KTPdZpaoYPKCGlgN1wHqgfsYJ8Su5T4qtGqQu/Uk6GeLPWUqMeQeEo9ahldDt/56/Bx7meT21JnGDOcb4dO6nGvx1zPHj01mjTH2kQbS6UvuR+ywvR/cWvIXAvc4UjWuHoGy4YPCfqQZLea4UUqcwtyyKLD23PGgWsU3eKBedTUc+BylwpHTNpo20bonhv+Ta6yPuXMuH6y/Loxe7p6Ygfuzq+EqvvFHn5frGv9/gE0ZmiMC2DrdgAAAABJRU5ErkJggg==", + "e": 1 + }, + { + "id": "2", + "w": 62, + "h": 106, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABqBAMAAAAW8P+WAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAwUExURUdwTPj7//j8//j7//n8//////n8//f+//////j7//n8//n7//n7//r6//r8//j7/0pG2PUAAAAPdFJOUwB75vVODpccBaq/ONMqYK8Uj/gAAAHbSURBVEjHnZa9TgJREIXRAKICobKFQhMTC0t/osGYmNgB+gBS2C/RxNa/1hB7CyjslzcgFiZ0yxtoYywNuwSjEEeEe7finDHQfmHumTNn7t1IBPxiEf4rVTjff7ii3Nl+p9wLnhoEp0T8U3JCWkS2DjFfGPLgsQj5yZDLzgHkH39clmGB2ogHbwAn8iMua4BHx1j6gM8bvgn4reH3gBcMf6XyRSpc/kCR31Hko/aODc9R90XKgLuG703GcwYHIEAzhn+B8rOGdwFvKtNx+HRieS4/bbAP5CcN7yny+oq8nCIvw91D4bHyvpVs/ijZXOXDReGIW97m2UPysoo8j8uzq4HcSyruFZRsuny4KVu+zjcT3QwvSvYc7k44nBVlOMCdS7u5RX58T+l+Q+m+zLtHw6n98/jP6Y5vKse7/Pio0v0NNz9hb11/svmxdX7rX9vyrcn8XPi1V+OLuSg8+XfCb12710Flqu7iSrKbSnce765q/76rmJfh5oHZhdHoKtGo870D5oWz6SizmVw+Ec6mzfdKK9/io5fGVOqPlPIOVx9Vyp8p3tut9yv8Oe4qwSzz3A+K8EOaBTOrPCgXef6eRUpjAc/wU7zqYW/HBrv4U22cnxpaG/tsLSHyC5GMLznhxMCGAAAAAElFTkSuQmCC", + "e": 1 + }, + { + "id": "3", + "w": 81, + "h": 86, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFEAAABWBAMAAABFpGe9AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAnUExURUdwTPr///n8//n7//n8//j8//j8//n8//n9//j8//n7//n8//j7/7qhZ/cAAAAMdFJOUwAOJvFhRbneeJGkyRXSt90AAAGdSURBVEjHjZchT8NwEMXbhhEKpoolYJogEDgSCAJRfEXJSDCIzc+wIBATfICJBY0gYGdA1xXa0d2Hou3af6t6v9Mv73Lvvbv+a1l62RatOw8CncsIIg+SD4hcyDNr74hkrP1QRL4R8q1A5qT9oABKcgOQJyUStZ9WyCtfBe5VQMluVeTDFimvajjmNfJJm363Bsqf7mRd50TMql6QmEVttOYxbe6a5oGCDBtgjud5BMncVkTnWSvAfUM5pv5kHp3nl/qjOWnyJqlCeYzFXDXAxKeW/1DLZUklSrFEyjzONZ1nSP2xYxp2s+Xqmk9p3tpgbjz9CiOJWiM1iUzW5QLdVrCSIU3RjtCtCKnqHcolpcwx5ZhSpphyQu1JPWrPhIZIoXQx5YpSHlItOwupaHnaUr73n405dXxEQ9TxcU19VA5MewyU7bHb+5JEVKH+b/7AHFbJfDrOVy/wSGA0nJiKPqIKdVaiX6GOlDLrpbwXeqsX+BC1qmsfXeNkoj7vm5HA89plj9bmwCUBQZZDzdh/zRn7sSiH+gwsWOSf7h81MVY6vg3XsAAAAABJRU5ErkJggg==", + "e": 1 + }, + { + "id": "4", + "w": 88, + "h": 69, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFgAAABFBAMAAAA88zxCAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAtUExURUdwTPn8//////j7//n9//n8//j8//f///j7//r8//j8//n8//v7//j7//j7/4uwcWMAAAAOdFJOUwDjB/MmhLoU0VVsnDVC5tQhQAAAAX9JREFUSMeVlr9Kw1AUxi+hJdTaXaGELF3q7KBCUAdncXHr5KihS30CwUVC1BeodndwcRPdHAX3wCVYYoXzDJpgzclyz3fO/CN8f869ucaA4xnFTMY421pLcfgjf4TZDlEfhkdEO6joDSKy+xjrx78wHWPwXsmContRBS8g0Q8VS/Nd0F059gZ1Bzp8XbJ0JncX/cPrSHfL+ZLY85qlqcCuBjW7BUZcJfcCRlzOhXQ8kpqdS2Xfsg8fKkQsFCJEd1zEpULEdyjUkSi6mzG2r9gJKeJegEfsscUUF+iNsYVwTtuMpSO8OlHETJHEAeFJrER4Ha2Y78QYF5ynCsEnbnbA2W1hJRK8Ov9ZUd01Z68U5j5D3FzhPs6dABfcaE642PyRIuE7zgo/MX6OyKZ4aPTkftIQ3sYgws0NA9xcs4zi3cnyraTcfV/GiiBMxtlT4UbpMlb8k3u1v81Q/O1n6CXBdUBPoD8d7oCbOgrwEduVt7Khw04NOpm9xx/SbZT9AfSRiwkFfEplAAAAAElFTkSuQmCC", + "e": 1 + }, + { + "id": "5", + "w": 93, + "h": 51, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAAAzBAMAAAAHoRnaAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAtUExURUdwTP////j8//n7//n7//n8//j8//j7//n8//b///j7//r8//n8//j8//j7/+1jD5IAAAAOdFJOUwAI4cnyU39CoRtnL5GxhBG0zQAAAWFJREFUSMeVlj9LA0EQxe8EiWcQrk5h5wkqAQsbC0tJoWJMk0qC2IggERsLS8VOUlnYRb+AlaQSFJuQxkYs7LLb3vsM/uEgdzPe7M7UP4Y3b2dmJwj8I+wFmggfOip+z75o8BbwpcDPAKzpcCQ6HA0dDtNT4TC7KhzjjqeRWdh3D/wek1h1N0Eex7ILjw7zOBZiB/5WwJHIfPWmiGNRxKc3CL4ppq/VVfjtDjTiB4TGkoSHLRUeHVBcdL5CfZQnq0Z9lAd3QI2xQ3HL0OTjI6kFLilu+gJ+x6SnXQE/pzS2hBGvMtfFV+I24lPwpQ2NMRXmC0yzHL+o80ofNYVivbzSJ57cjsqVv/Lkabn0Nk+ORHikf7RcS93LRiPti0tmX6HlN+aLTzpybdS5PN7oOhf2bK7Qq9j9HUST5E2v3ynrYvsRe+HByR++7Zf8J559lWcxBaycKg6JGXOsOmsi1dX0DXsjWu0QPbYRAAAAAElFTkSuQmCC", + "e": 1 + }, + { + "id": "6", + "w": 94, + "h": 31, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF4AAAAfBAMAAACc+GeUAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAwUExURUdwTPj///j7//n8//n8//n8//n7//////n7//n8//n8//n7//j8//j7//r8//j7/3k2glMAAAAPdFJOUwAhZVX01IELM63AneREkj2lQYQAAAEMSURBVDjLY2AgBQiJk6R6zxdz4lULb/3//4s60WbP+Q8EX9KJU9005T8YfHlIhGL2a0v+Q8GXiQRVM2rH/0cAQuprM/3/I4OF+J299T8aCMTjELsl/zHAQZyh/cr//39i1XPoLfmPHThiCT5MV+NWz96cef4/HvAR1dGZ8f/xAyT1wtkhBBT//7pJAOZmgib//++ZWwBWLGE2y5+g4i9xhhCjJQm6AuyQBpiz7QmrjtYoQHiTkHqvR+0oYYhX/Z9lhujRiVv9l2hdAczox6U+MlkAa9qyx664HVfC1cdwBh7FGOr/rNMVwJ9DkdSf2mZRQDD/Q9X/WY3XFSjq/6xMukh0sXg76WIBCWUuAOVRXzP4mF3cAAAAAElFTkSuQmCC", + "e": 1 + }, + { + "id": "7", + "w": 95, + "h": 17, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF8AAAARBAMAAABJMG3aAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAwUExURUdwTPn8//f7//r6//j+//n7//r///n7//n8//n8//j8//n8//j8//n8//j7//j7/8ac3/wAAAAPdFJOUwBQQDAiyhNh8bPfkH+hb0xnXv8AAAC3SURBVCjPY2AgAaQovkkgVmXd6ZtR/f///3fAp4zNxUgQqDB0xX8EAGpgKhdUUjaGACUlQUHxujen996cGrqq4z8m+AHUwPqfBADS4E+Khl9ADfWkaphPioavQA39JGpgIkX9/84EBh6SNPxNIC1U/3cnMOSTpKEngUGeJA3tCQz3iVXbFTp3T6EaA0P13pnYkw04JXQtDZ15e8+7QmU39JSZluJspKSkKAhMfOVAApQeXdywJX4A4qlNoF/7I20AAAAASUVORK5CYII=", + "e": 1 + }, + { + "id": "8", + "w": 93, + "h": 36, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAAAkBAMAAAAZciv5AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAwUExURUdwTPn7//j8//j7//j///j7//j7//n8//j7//j8//f8//n8//j7//n9//n5//j7/+nK1AIAAAAPdFJOUwA/2cAQhquW92QdUu5yJ75wYRYAAAETSURBVDjLY2BgYBBkIAlw9R+bRYp65v///6sKEK9+P1D9/x+ZD4hUznL+Pxh8qnYgSj37fxj4HEiMevn/CECMx/X/IwP1LQSUs/5HBT9s8QfVi//o4E/mAjzq7f9jAnxB5V2DRQPeoBLVx6aj+R5ODXyXsWnAF7ieOVh14AlccayO+m8qQqKj8ESHN3ZH/cGdcrGH1P9POCOQa1o/dh04I5Ax6D92HdG4dLy1wK7jc6ADaWH7vzmQRG/8b19Amjc+4063K7HFxnF8OUkUM2vo4i9ptqN73JBA5ua7hurxLIKlB2MwclIqIKJ88i5CRPIFokpAeIx/JrZUFrXAH12YQQVO6pok1BKgwE0krR6adoWBAQD6RSkXqZtSrAAAAABJRU5ErkJggg==", + "e": 1 + }, + { + "id": "9", + "w": 85, + "h": 58, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFUAAAA6BAMAAAAzeQjmAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAtUExURUdwTPj8//j7//n8//n8//j7//r6//////j///j7//n9//r7//j7//////j7/xorFqUAAAAOdFJOUwDka45O8ykNGL3LOKcIcwLOhgAAAUVJREFUSMfNlrFqAlEQRRcJKsg2ahcQm3yDlbIW/oCmDqbcVII/INimDoJgJTbC4nbiD1gIQZIqpYiFEuYbfLKrM92dKQSn2OqwvLl35r7nea7CqqetQuW00LItov+BDs2Qq85WxTYuLJU16B8l9YXRfJSyVIPs+xWlHVQuvLGElWsyvEfK5RoMt9GPsxOG59CMCsNQjCEZxFgxfOwC1n8RYvSQe6I/OBlPoj84GX1mD3UEfwgxAgSL/uCa5L8NZsv+Zgj+JYPZj9ff3OAf7m91p/58uX+vcP/eGB4h+FPMZ9WQLye4fyJf9iiZCxHDz+gUP6K/tSE/H2TkRpbIgJbElkg0RX5kSAFhCVY5NNxobEmpB9mbJVPF3Z5acqgp2HRLjoGGTbakqHuM5C5H3igfRO7Iu0DJuinqdLWsF4+3atZfus8Z6/cASe6qbLIAAAAASUVORK5CYII=", + "e": 1 + }, + { + "id": "a", + "w": 71, + "h": 77, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEcAAABNBAMAAAAGBWRKAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAnUExURUdwTPn7//j8//j7//j7//////f///r9//j7//j8//n6//n9//j7/5OUP8gAAAAMdFJOUwCD4vW5Dh5ipEkxzrqPMa4AAAFKSURBVEjHvZYxbsJAEEUdKdg4FelpScUBCFBwAApEQ0Fjkgu4SZeCOqJAipSKwpLPEBASTexIYHkPxYLH7Z9vCbyFq6ev75k/u+M49rjPjnqeVmapMf7YmJPCzLrGHiy1uDLmH0KfpjgjBHkC1SbVFgr+4INAp7qkVkK1ENQU6A9KjRmpuUBHBDUOQoWImgqUIcgtAmPSNaLeRKoPcz4soCRC1LdIvcBxECiZMOH7Zdp8g/DV3eZ79CZA1EakOjVNc7WChkxBubDDhMZVEppTCaUuohtWAWah0WWyEDPD5VfKAnWHZkwVcAOnTIzdIWN9wzTQY4a5fEmw9Ucme2WMsfWYqbpPWW8z1ptMYMqXC1t/r2L9lbGOHxKxnoSE9V6kW0+/lG3vAg0CZd+z1tOttjjawAwiDbITv5+oe2qcf+jLrLcLdMj5uXzO4xy1b/LyCzEAAAAASUVORK5CYII=", + "e": 1 + }, + { + "id": "b", + "w": 52, + "h": 93, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAABdBAMAAAAYrVhKAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAtUExURUdwTPj7//j8//n7//////n8//////j7//n7//j7//r8//r6//f///n8//j7/+44TfEAAAAOdFJOUwD0aIIIzhPko0C7MRxSXKb3qAAAAXdJREFUSMfNlr1KA0EUhYf8bkzsgpUsPsFgZSmxShuCdUhIKYhFSGGxpNVCrCyD+ABiwFpSpLGRgL0whhCjMs+ge2fLc2bZYOG0Hzv3zLl3zqxS8Xp+UGidvF5GdheRiY3XB0KBIHsNUC0UdIw+OxT0jlBTkJkCtO2KjdBnHUFrhJ4ELT3y97j8AZe/QKjH5ee4/EIk6AvtqAV9IlTk7idetbhX0P2xoFUDoC3uVcVyr+65V64xpsuL7QNUdWjnPxcbb1Ss4inW4cXeeM+KvGc5T88iPiCaX6Yjt+McoDyfxlLIR/+KB49rp51u5HA9463Q3OFy6qFv//rQJmOnPVGQ5M6ahxzUccrND1LNP8sY35rr6HE/gtS08kSjJ4cX3I+VR8ec6xjxG1jP+Ha+8KciuRRdngTIqkLIrXJz+s3jD1pV5vmR51NV5RKTlrW4VUNq1fKAvaqmjZwSq84f4e9T7XcA4HbxS2EuGgTpuxkhqn/DiCrJdj/sGwyAGof/DAAAAABJRU5ErkJggg==", + "e": 1 + }, + { + "id": "c", + "w": 30, + "h": 108, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAABsCAMAAABKBPJaAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAA2UExURUdwTPn7//n5//r8//n7//n8//////f///j7//n7//n8//j8//j8//j8//n8//n6//j7//j7/+s30goAAAARdFJOUwCeKMZgtAYX9I3cRet9UTRy7gF4GAAAAUBJREFUSMfFltuOwjAMRJv7PW3//2dXgISy63LaCMT69RThGY+TLMvfSlYvUPu+R/P6m7g/6vZNeI1vlRirf8Tpy3hH7EfcBA4TeGNsBdaM1xF3gcuIi8B9xKvAdsSasczaNmIvYz7QKCeiBpwZG4ndgJ3EhpOYr2epcVgsj7vwPDUPLPBEZOPtW54emFZxCTy7otmVwkkbXansimFXHLuSOEqWZa8sO6DsA13bdV2KdTXW1VmXZl0eQ555XieNb9x44cYDbueB45YdTxwVh1H5tUArHivRY1QMWzrfWcZhBz7nP9dZ55M6YAwzT1Px/rxlykGQOp85iSNu3klKv57hNrtdJ39tWbVi1fXyUVo9npVudgE8x6xfv3VP7k1+LkR+Y7nZy+nk9rlvZrxXPXoO1JqzcSo1W+SPfXiWl23/AO6oVMpyFWFnAAAAAElFTkSuQmCC", + "e": 1 + }, + { + "id": "d", + "w": 56, + "h": 110, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAABuBAMAAACAf83HAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAqUExURUdwTPn8//////j7//j8//n8//j7//n9//v///n8//j8//j7//n8//j7/7DVUvQAAAANdFJOUwAkBvCpxz54E96OaFIL7jEqAAABvklEQVRIx62Xv2rCUBTGY6qt1QxO3QLWLu3QRZdSEHyBQNYOgb5AIC8QENq1IE51EFw6Ftw6Fbp16tB/UVPvu1Rzb7ZzfyB4R3/g+b5zvnNsHUd8Q8f+KtdAPQW0oVRupTW1oS0LvFRA4y1UaxmmBIMCLmXYL+BI7kHB1ECETQ3nIqxqKFs5KNh3W4R+AX/J5oJsZiJztc0vER5qsaFtmts3s05z825F+KChbPOVbAZg0zjJyEmXnMjTPKZp6pkoMdRuSk6iAuaUrozS1aW2D0jsGwTIMpMInBixfyI80vCTxIYkNiGx8hJNQayJwYJiIIs9I7EfJDYAsXUFYpvUWdO8JVxESwwCiEG9DxfI6MlJT0Z6RqQnAT3yghk9P7S2a9Iz3lmPCbusp0F67qg/KfTHncIB8hTMq0bziinsEeTHrJB82quUZ59GEkALyq7PoaTcAp/2/RkuaVkyoZLDnUsal1f7LRlTyQiy7lFjLzRbte2/0vIsy6UNYUnk+Pi0QQEktgzlbGcjKRipkBEzEfmux7B65UKP99ueCKJlLqV88+9vJj3rtzqn70+TXu/R+jf9+clLy/7vQKcjfvwP5cdtjxnUxgAAAAAASUVORK5CYII=", + "e": 1 + }, + { + "id": "e", + "w": 85, + "h": 102, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFUAAABmBAMAAABINcBqAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAtUExURUdwTPn8//////j7//j7//n8//n7//n8//n7//r8//j7//n8//n8//n7//j7/0PvGn8AAAAOdFJOUwDfC/L9qylSyxk9kWd7UFH1twAAAgJJREFUWMOVmEFLAlEUhQdBTSuIIKEWYpuK1lK0EaQwsxikVSsR/ANCLVpGuzYiBOVSqHXYH5A2bcX+gCDzKsm6vyHH995s55u7PlzOO/fcc0cdh1Sn7eCqbWBowvWaFBsXmVLsi4g6h9iWiIzrCJpUM6zaR9gF8etoSLCDOVatAGgsO8fKG8Aua+iYUGho7DcasMbeAGhaQ6WLFZNPrph8AWiqoLE95jG/vDbzmF9/EYa2SoamNJbsxb2GliMMrURsLlwxQ8HLcQpnxDeKe2xTQxXZ4b7GkiBJu3xohgIaWp/b3FI4iaDCkFOYRFjgUgQVetwLReCbpPHCD7cjotAy8QgomCSVCmj7zCnYXCAqxCNQMOmoAIWESccJoLBj2pb4fMmdWhK+EeZMyQEXVzW5uCQXRgZ7y/fXq/OX/YKXGedKlb+MWMy+bA/spMvn2+DzTWW5uMaNSFzrxmN+f2WI94y8zFqBnJMGf1kgWIULBmYWOGzKHabAzMzhIZm7aNuCVR/ZPevisCFfuldcsGAfTiO0rfK2wGGXgncnaAtSP2C7ztuO27xtJnxkQdvwfRi4uK296XJYx74Fbe06ALaxmou17di2xTbOBLkLbftkoeVQJyQLlm34L+vrPM+Px4s8Dlxn+9UHK5Djs9r1wSAT5rX14aqMA+vhfS3nYDD6c+Efbcq5dvTBhKoAAAAASUVORK5CYII=", + "e": 1 + }, + { + "id": "f", + "w": 26, + "h": 105, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAABpBAMAAADW0i6SAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAwUExURUdwTPj7//n8//j8//n7//v+//n8//j8//n7//n7//r6//j7//j7//////j7//j7/2yr6gkAAAAPdFJOUwBdQ35tGZXUquYxwvQKuaGYIt0AAAFeSURBVDjLpZRLTsJQFIYLVnwhOnaCAx3jDjRuAHaAJDouK7AmLgCGJgx0B3UHugHDEnQHSouRinq1p/fUfsmNIfHOvuY2/+Oc1tvb90qnZUanvw/q5ueMbiytZmROLFWEhpaWhd71xTCjRCnIaK7UlKsdS12hbUsrQheWapCoQiIXTCD4BcEPCu5C8MDSmtAtEj5YWhKKIa+CmwaCIQRF3mhtbaEjSxFKfBTqI/0n0qu8D/nczAxdpCp/jYKfkT6AmSbMRDCTW3tBT1p+Q2gCowmMzmD0DUaNGh3DaAijAxgNsBdtDK2FLYlgOw/xihAx2p5i9AkizRBpjsVPEVAjrZtypHxJikUYI2CIgHfYygHmwvCHQk+ooo95DlHMvbOYCMV0QVuYdd1RGkn3YAPUcNTrppqj+gTfoJv8hanyL5r+QZOFKS5Telaiq+NO4Tq93FHw/PNe6d9cLW6Vzjd2303ziaAgagAAAABJRU5ErkJggg==", + "e": 1 + }, + { + "id": "g", + "w": 113, + "h": 85, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABVBAMAAACMbRbDAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAnUExURUdwTPn8//n8//r///////n8//n8//j7//n8//j9//n8//n8//j7/48ozloAAAAMdFJOUwAq4hcJ0kvynmuAuh1GvVsAAAG6SURBVFjDnZixS8NgFMQTGopxCgWx6CQFpwwiCOoUF7E4FVeHLsXFxaWDdBDs6NChIIKDYN26Kbh0CoTE5v4ogzTf93Xz7u0/7uXd5b2mnsdX88sTa7sQQX+Evka2gDsJbMRAlijkIap6ECWBH1USeV+UBDqiJFCqkvx0WysQV2x8asn0QJXs8IldSUYkeVNL7rHvpSx5q0qGUCXnquSGKhksVC+PajAj49O4VhPbUiVNCMBu6dcaLBPREYxVRwrVEbyJm4Bes89GktyymwYcquNho74FMXc2PWwI5moILg24VK1kHbFW7nPghQEzzhHfLAJ8itcARSL2iona61CdKzmeY9srt7WasZiewOaV/NVk3y30tFvJWukvVCutIeSZ3bVgSR2gcCT26qSO69VxkpzrwIL5RIwrlwF3OstEjEDK5DV4cnodi9nh1qQzVhRMeNoOSL2UzqoDHgmwOxIfMoyhpa7pxBxZXwTzmQgy12cdJKZzvgbe/386XXeqTHZOXR9RRiLI+LHjPmQ6ZT4KPjQjqzoxovk7+SUyEEFjJw96wd+tTGceX2fflR1TT6l2XIr/FfkvEQ/9AvNzjAUC6jIpAAAAAElFTkSuQmCC", + "e": 1 + }, + { + "id": "h", + "w": 132, + "h": 60, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIQAAAA8BAMAAABV8w+MAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAqUExURUdwTPn7//j8//r9//n8//n8//j7//j7//n8//r7//////n7//n7//j7/xgCzlEAAAANdFJOUwDOnRtVs2z15S8MPoE64GgkAAABr0lEQVRIx8XXv0tCURQH8AfPRV0ipJYcosiCghBpqaFwiaYGySKCkgJrU3DzQQg1+UCEmiOoxYZ+0NYiErVqynP5/i89Lat73xPuuWfo7PfDeeeec7waxn/H3QhXCNhtphCMoskTzAUA9xwh9OYK2OQQ2Z6AD4aw3hfQ0hcevgQ4V7rCMwaxrylc/Ag41RPivwLabAEdtuDo1CJu/SWmuDlgR0OoCkKEd5tunLM6qhdFjc5cE4TWIn26s4LQqdCFd1GgLxszJghNuhDeE4VVsnAb5QortiB06cIjmELoAMyvCMa4glRIDaFqgdcPplQGek8G0pKQp85F1ZaEInE2zboEoEzcD0tRWYgw6wjsclNwGrR+9KbQPCEJL7ZHyJPaITHrAVCmXGa47gWQohThyPIC3QYFsH1SKKhPZu3VJwNgTLkMl5N+59GdUzy/nBn3BZBX+4hEZhtDIqU2VjfWMKCj2pABe4iwpVxHM+0LFDa03wzfFzFNWi7X3mJMEDek9JMNlJLMl8fZMfMZWNIB3GsdLDlnNGnohdn/j4XcTMXQDvcxmZtPGpyoHT5xjn8CSC7umaa1m9IAAAAASUVORK5CYII=", + "e": 1 + }, + { + "id": "i", + "w": 142, + "h": 28, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAI4AAAAcCAMAAACAjXdyAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAA2UExURUdwTPj8//n7//n7//n7//j8//n7//f///f7//n7//j7//j7//////j8//n8//j8//n7//j7/ww+fegAAAARdFJOUwC6jqle484XgTj0bglMKZh3OkoYbQAAATNJREFUSMfNl117gyAMRhsCBAjh4///2dFp127rVrUonju88TwviYmXyzkgnfEkKonR1EYcH4o4CHXGjzSJnrOtj/Cw69HZhvqTPCKTpyaf2GPrxDPa+g/huEgUmPqStH8iy0Qm9H6BJOG8XGRCncRjBnrWh7BCu83jXsskPr6ThdfsMvzVuyt16JJa7xkL2WnxiZYYUPJydWhRdJGYVaBchwTh96fGWkBEpZT7oh0yIoDtKnDHIN96nFwdilX68U6iHmZisPyq2+iHmICT54VK5iwmkw6Ew+oEi7xq3qjCEZEovez7FsXsLkJrpu4+OsHiSpGZzsWz2WNGmW4a/I7HbZF2sF2oTRXMRUuKvfe2tiDAkqk0zTXlWhTpgF81Iu9FtNbMZZqhhbkdRXwb+rTnqz8AKGN3GBhdF4AAAAAASUVORK5CYII=", + "e": 1 + }, + { + "id": "j", + "w": 141, + "h": 38, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAI0AAAAmBAMAAAALqwW7AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAwUExURUdwTPn8//j8//////j8//n9//j8//n7//n8//r8//f///j8//j7//n6//n8//j7/7O7hcYAAAAPdFJOUwBYyg7zcEDdtSwdkH6mmsllwBYAAAFsSURBVEjHY+AKNWCgBuDq90ughjmc+v8/RVHDHP////83Uu43tv8g4CtMqTmGYHP+f7lIoZNM/0OBB2WhtOY/HOhQEnHzEOYAPbeAbHPm/kcG3zeSG0wz/qOCT2SaNOk/Ovj+kBzf8f7HBF9ak0k2h1n/PzZQG0aq9zifYDXo//erJDqKWeg/DlBxcAJJJi3Vx2XSF90wUgKdc/v//7iNOjiZeJPm6P/HAyqeZhHtpKD/eMF3vYNEmmV45T8B4N5HnFk5+v8Jgi8aW8UIhhezXP1/YoC77p6wLLwJlYtIk0AuK+rdE5i5GKdJ0vr/SQFfijRu7xHA6ruclv8kAgUcjpq4yZ8q5gDTkzQpjmrAF+YLTxAd5hcIpIPEHcQZ9YBwqZJKjFEbiMoxE+PUCZhzgNhsbCm6o4Qa5kDMeqGCw5wAkptdidFNWBwmQFadZ5kY/ULdn3JzIGBlYsy+JnUXsDlUaBoar0wTDF0AAB3/knPrDNhIAAAAAElFTkSuQmCC", + "e": 1 + }, + { + "id": "k", + "w": 133, + "h": 73, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIUAAABJBAMAAADh3vjAAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAqUExURUdwTPn8//f8//n7//////n8//n8//n8//j8//n8//n8//r7//f7//j7/3vgFsQAAAANdFJOUwD2HqAOhtHla1W3Lz9z0UemAAABz0lEQVRYw62YMUvDUBSFQ8hgSQehdAy4iNDJzrUgiKCbStFBHBwEi3QUBAkoSDsJFUShk6tIoSA6FwQHt1CaQvD8F1Nr25cXl5z78gM+3j33nMu9sSzLseRf6UrOaA3WpQjnGJdSxrYP7Ejl8ICwJyvlDvFXFDHc6piBM5Ec3i8DNQHjdYJA2OYZj38MREs042jKEOh6O2OgzjJW5gy8sP6ozhkB25ycr0DYCJeUakZtaXvHNulzDFuRBFFPLgkGpNc2FAYKJORdhRRJyLUBSEJXFpJvGNBkwTcA2fQgb7Fq+hjCme0zAYn64uTQI7aVhFCjwNlNQEY1A5BgT25YoGICUjcBuWBWHFeDUAnUX0K5zS4nIeENA0m2GEFF7hPgmYEcaJBzQlmnpUEKjLIPMKDslwYJ1phlzdMop4Rnl30Domw1DIiS7xoQxdXdxjglZRRE99mf0oGBelLtYepJtccj6nHLBupxmjoEJ9nr+dCNz/gtJUo8mTLnJ58ShcjPP6KMDuXTAFjNfkPqGQSxYNj6sKYWt2STQ/ImVusZkhePvT9nfNPn6NssyYv8bZ2b+u1J8sOiM5FWcOOP89OlW6tI26Rbqw7JxlDMsOw4cj93jxlMshBUbAAAAABJRU5ErkJggg==", + "e": 1 + }, + { + "id": "l", + "w": 116, + "h": 101, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAABlBAMAAABuPtoqAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAnUExURUdwTPj8//j///n7//n8//j7//n8//n8//j7//n8//n8//n7//j7/7QVfMEAAAAMdFJOUwAhD9Dm9olRt59wOSWCqnsAAAHjSURBVFjD1ZitTwNBFMTvTvDRMxAIAkVAABIsmCpCqCIkJKQCUVnRBOoLuoI0yIoKcIgmYEhw/W7eH0UPertr51cMm1ROZvp2Zt7momh21iN64kqXQj9LRUr6bP0dBt0qmR0jZFIxszGCbs9IzRqE9CVD2gRA939IzW516N0v0oY69GsOBbQF47RVTru6AG2T065w2uQ0xz7J2L0cOlmAtsFpx3JuY0er53Yjh/bWOG2R/9t+l9Nec1qr8budyrQHhu2YNLkvXIDsSJbcdhck+2LJ+AW5lhp0cDmCvqg7bEuFpmWeoE3DCfIpGNR4CnQrN7mVvS96spXf+KSWy3xSH9xT/oLskfeF7ikXXDvjCbIOT9BEvdy0xHvKW1lfJG0eg2BSLT4p+XLjEq9W7yn9KeYnJS+hgkufXfD0ydvAb2vdj6vG/fhquGyCGAx5DOwBr1w9Qr5adcnvhvvRv4l0yUFyp9yPsuRgG8iS/d7Up1znxgglq14+/BvJavxSL/nqn0gOpjxYQLJccoHkkwUkd7iXx+r2uzf8tAkaQ95+wQaTF3ZQcjeq5DZvm6CXR/iDAPiG4VaJ/Gp12w98YspzcAmg8xx0CDTOTNWL0MlMNWLQzFQNCE2q1oXQKD2P8Nmd/b4ByijZ4gZcubIAAAAASUVORK5CYII=", + "e": 1 + }, + { + "id": "m", + "w": 90, + "h": 120, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAB4BAMAAACA4vgMAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAnUExURUdwTPn7//n8//////v///n7//n8//j8//n8//n8//n7//n8//j7/yYG2d8AAAAMdFJOUwDw2wcTp4IkwEw6Zix2ATQAAAHpSURBVFjDzZehb8JQGMSblRbY7JKZuiErFrJshBnAzkBmKyonEPAfsGARM3MI1FQFEoGBZAy290dtrO+h70dSsieqLs29++7uaz3v9/j3A08/t4trHVxeRN8yuPQcmVVLBb/FxphUBL+//ILNp4Z+7O3B5kNDN0x+XiV01aJFDSc5eqOhsxy90sYZWCpdTcIoR+80Kv0cvb6R0GeWSoo0FMeZ5Oithh7al88ldGjRl9rLY0OclSFnBYiKG6dIZYmoVCy6pnUEo2KdZWbIWVrezs1RVDRV6kiVJqOSICod5JXqcVTmSJUrRGVbBJUO6hVHRay4BFWcU+UL2XbdQrbtIiraHi8btIMclTHqlQ3qFbEpliieAcqEa1vRiFOUCbeDtpIR/RgZ0a1Dbe0/uOlrRrRfN2Ykodto+i6e4vT7aPp1NP0ym/4SZT9ANVSKUfYzlP2QZX+CVnMbSe4aUZS8jwJXYZJHSPJpgZL7TPIhkrx6nOSayxtow0HJM1QsISuWCfrU6qAuP7g8RcWyQ8UiWiv+N9byT2KtUQHWujDoKz5BrVVHrVU+RWuJEUoKjNDhnmkB97xzEZLueWjnGrtnAT/Zvr3nkwfmqQnu5jkWwX/3FH9s7D1rnnymZj3Q0aEYNXt6M4Ju7h8/2gHMmeCkIwYAAAAASUVORK5CYII=", + "e": 1 + }, + { + "id": "n", + "w": 59, + "h": 129, + "u": "", + "p": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADsAAACBBAMAAACMWt+TAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAtUExURUdwTP////j7//n8//n9//n8//n8//n8//n8//r8//n8//j7//r///f+//j7/0LsbNsAAAAOdFJOUwAI4csplbM/8VdxhRQeIGpf3gAAAb9JREFUSMfFlz9LQlEYxs/NP6EZSJOjTTVJn+DSEESLKO0XoV38Al1waQoJ2qOlVfoE4thQ4idw0LTUOp+h8q3x/Z2LB+kuDj/Ex+d93ueca4wxwcvJpdGe4Pn04eJKxWfnHWvfiwq9Pfym1rYUHNvVU1NwSXBZwVnBbwrOCV4quCB4ov2xpvBjBXcF3yt4JPhIwSnBHwreEbxQcNohvSK8r+AeS6+y9C3BnxuVPlRwxNLjRNJfWfqSpY8d0lvs+iO7XubAaFnPC54qeFewuqah8BvOekPBAw5zlhOR40QEHd7DJtsas60ltjXDtm47bK2wrT22dcS2ptjWPNtaSGZrjW1t86LNedFmvGhqf4VcAl0ugQGPPPufI69yt6a4oHJcUH8jb3G3Nnjk1zzydeNoWZsjjneJ4rjgOE64PNddFYe2Eq9KhrWlHdpCbsdfbfte2lxrPPTS5tfcM8dMh+udKsm0edbfZrTteWnz9C3mvDmOjTxrcx1pUSJtbe7e+WZuMRF3SJW71++G5bq4Om5/T6wtk+h9QL1Uh6xNwj7tU6DG2pclUHX11fbnUDow+hPZaRFwrP/wKlB1oiaQjy91/SSh/OvPpwAAAABJRU5ErkJggg==", + "e": 1 + }, + { + "id": "o", + "w": 202, + "h": 202, + "u": "", + "p": "data:image/png;base64,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", + "e": 1 + } + ], + "layers": [ + { + "ddd": 0, + "ind": 1, + "ty": 2, + "nm": "24.png", + "cl": "png", + "refId": "0", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [133.5, 65.5, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [17.5, 62.5, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 24, + "op": 25, + "st": 24, + "bm": 0 + }, + { + "ddd": 0, + "ind": 2, + "ty": 2, + "nm": "23.png", + "cl": "png", + "refId": "1", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [151, 69, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [18, 60, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 23, + "op": 24, + "st": 23, + "bm": 0 + }, + { + "ddd": 0, + "ind": 3, + "ty": 2, + "nm": "22.png", + "cl": "png", + "refId": "2", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [165, 77, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [31, 53, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 22, + "op": 23, + "st": 22, + "bm": 0 + }, + { + "ddd": 0, + "ind": 4, + "ty": 2, + "nm": "21.png", + "cl": "png", + "refId": "3", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [175.5, 89, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [40.5, 43, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 21, + "op": 22, + "st": 21, + "bm": 0 + }, + { + "ddd": 0, + "ind": 5, + "ty": 2, + "nm": "20.png", + "cl": "png", + "refId": "4", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [180, 98.5, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [44, 34.5, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 20, + "op": 21, + "st": 20, + "bm": 0 + }, + { + "ddd": 0, + "ind": 6, + "ty": 2, + "nm": "19.png", + "cl": "png", + "refId": "5", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [183.5, 108.5, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [46.5, 25.5, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 19, + "op": 20, + "st": 19, + "bm": 0 + }, + { + "ddd": 0, + "ind": 7, + "ty": 2, + "nm": "18.png", + "cl": "png", + "refId": "6", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [184, 117.5, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [47, 15.5, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 18, + "op": 19, + "st": 18, + "bm": 0 + }, + { + "ddd": 0, + "ind": 8, + "ty": 2, + "nm": "17.png", + "cl": "png", + "refId": "7", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [183.5, 124.5, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [47.5, 8.5, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 17, + "op": 18, + "st": 17, + "bm": 0 + }, + { + "ddd": 0, + "ind": 9, + "ty": 2, + "nm": "16.png", + "cl": "png", + "refId": "8", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [181.5, 137, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [46.5, 18, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 16, + "op": 17, + "st": 16, + "bm": 0 + }, + { + "ddd": 0, + "ind": 10, + "ty": 2, + "nm": "15.png", + "cl": "png", + "refId": "9", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [176.5, 149, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [42.5, 29, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 15, + "op": 16, + "st": 15, + "bm": 0 + }, + { + "ddd": 0, + "ind": 11, + "ty": 2, + "nm": "14.png", + "cl": "png", + "refId": "a", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [169.5, 159.5, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [35.5, 38.5, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 14, + "op": 15, + "st": 14, + "bm": 0 + }, + { + "ddd": 0, + "ind": 12, + "ty": 2, + "nm": "13.png", + "cl": "png", + "refId": "b", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [160, 168.5, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [26, 46.5, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 13, + "op": 14, + "st": 13, + "bm": 0 + }, + { + "ddd": 0, + "ind": 13, + "ty": 2, + "nm": "12.png", + "cl": "png", + "refId": "c", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [133, 177, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [15, 54, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 11, + "op": 12, + "st": 11, + "bm": 0 + }, + { + "ddd": 0, + "ind": 14, + "ty": 2, + "nm": "11.png", + "cl": "png", + "refId": "d", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [120, 176, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [28, 55, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 10, + "op": 11, + "st": 10, + "bm": 0 + }, + { + "ddd": 0, + "ind": 15, + "ty": 2, + "nm": "10.png", + "cl": "png", + "refId": "e", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [105.5, 172, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [42.5, 51, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 9, + "op": 10, + "st": 9, + "bm": 0 + }, + { + "ddd": 0, + "ind": 16, + "ty": 2, + "nm": "9.png", + "cl": "png", + "refId": "f", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [148, 174.5, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [13, 52.5, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 12, + "op": 13, + "st": 12, + "bm": 0 + }, + { + "ddd": 0, + "ind": 17, + "ty": 2, + "nm": "8.png", + "cl": "png", + "refId": "g", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [92.5, 163.5, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [56.5, 42.5, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 8, + "op": 9, + "st": 8, + "bm": 0 + }, + { + "ddd": 0, + "ind": 18, + "ty": 2, + "nm": "7.png", + "cl": "png", + "refId": "h", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [81, 150, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [66, 30, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 7, + "op": 8, + "st": 7, + "bm": 0 + }, + { + "ddd": 0, + "ind": 19, + "ty": 2, + "nm": "6.png", + "cl": "png", + "refId": "i", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [75, 135, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [71, 14, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 6, + "op": 7, + "st": 6, + "bm": 0 + }, + { + "ddd": 0, + "ind": 20, + "ty": 2, + "nm": "5.png", + "cl": "png", + "refId": "j", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [73.5, 116, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [70.5, 19, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 5, + "op": 6, + "st": 5, + "bm": 0 + }, + { + "ddd": 0, + "ind": 21, + "ty": 2, + "nm": "4.png", + "cl": "png", + "refId": "k", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [78.5, 98.5, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [66.5, 36.5, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 4, + "op": 5, + "st": 4, + "bm": 0 + }, + { + "ddd": 0, + "ind": 22, + "ty": 2, + "nm": "3.png", + "cl": "png", + "refId": "l", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [88, 84.5, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [58, 50.5, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 3, + "op": 4, + "st": 3, + "bm": 0 + }, + { + "ddd": 0, + "ind": 23, + "ty": 2, + "nm": "2.png", + "cl": "png", + "refId": "m", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [101, 74, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [45, 60, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 2, + "op": 3, + "st": 2, + "bm": 0 + }, + { + "ddd": 0, + "ind": 24, + "ty": 2, + "nm": "1.png", + "cl": "png", + "refId": "n", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [117.5, 68.5, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [29.5, 64.5, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "ip": 1, + "op": 2, + "st": 1, + "bm": 0 + }, + { + "ddd": 0, + "ind": 28, + "ty": 2, + "nm": "橙1.png", + "cl": "png", + "refId": "o", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [116.912, 116.88, 0], "ix": 2, "l": 2 }, + "a": { "a": 0, "k": [101, 101, 0], "ix": 1, "l": 2 }, + "s": { "a": 0, "k": [112.074, 112.074, 100], "ix": 6, "l": 2 } + }, + "ao": 0, + "hasMask": true, + "masksProperties": [ + { + "inv": false, + "mode": "a", + "pt": { + "a": 1, + "k": [ + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 0, + "s": [ + { + "i": [ + [4.958, -13.557], + [-58.315, 24.553], + [-10.632, 5.311], + [-0.232, 0.117], + [0, 0], + [-0.001, -0.001], + [0, 0], + [49.089, 72.305] + ], + "o": [ + [-21.1, 57.695], + [22.072, -9.293], + [3.548, -1.772], + [0.074, -0.037], + [0, 0], + [49.02, 71.98], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.28, -37.613], + [12.31, -27.816], + [64.5, -51.887], + [72.833, -56.101], + [72.998, -56.183], + [79.719, -42.367], + [118.275, 107.156], + [79.873, -42.356] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 1, + "s": [ + { + "i": [ + [4.958, -13.557], + [-47.477, 19.135], + [-8.741, 4.366], + [-0.194, 0.098], + [0, 0], + [-0.001, -0.001], + [0, 0], + [49.519, 71.883] + ], + "o": [ + [-21.1, 57.695], + [17.97, -7.242], + [2.917, -1.457], + [0.062, -0.031], + [0, 0], + [28.681, 62.834], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.262, -37.6], + [-13.459, -14.91], + [29.224, -34.228], + [36.099, -37.712], + [36.236, -37.781], + [55.891, -45.154], + [118.292, 107.169], + [78.997, -42.269] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 3, + "s": [ + { + "i": [ + [4.958, -13.557], + [-25.802, 8.297], + [-4.96, 2.475], + [-0.118, 0.06], + [0, 0], + [-0.001, 0], + [0, 0], + [49.71, 72.154] + ], + "o": [ + [-21.1, 57.695], + [9.766, -3.14], + [1.655, -0.826], + [0.038, -0.02], + [0, 0], + [24.138, 9.296], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.231, -37.574], + [-64.997, 10.902], + [-41.326, 1.089], + [-37.371, -0.935], + [-37.287, -0.977], + [-30.132, -13.923], + [118.436, 107.195], + [79.364, -42.54] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 4, + "s": [ + { + "i": [ + [4.958, -13.557], + [-22.192, -3.916], + [-5.979, -8.573], + [-0.103, 0.016], + [0, 0], + [-0.001, 0], + [0, 0], + [48.896, 71.456] + ], + "o": [ + [-21.1, 57.695], + [7.93, 0.594], + [1.241, -0.023], + [0.033, -0.004], + [0, 0], + [125.108, 57.866], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-94.32, -35.798], + [-71.323, 37.188], + [-53.665, 35.113], + [-46.871, 33.144], + [-49.176, 35.065], + [-42.543, 33.426], + [118.32, 106.963], + [79.285, -42.289] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 5, + "s": [ + { + "i": [ + [4.958, -13.557], + [-18.582, -16.128], + [-6.998, -19.621], + [-0.088, -0.028], + [0, 0], + [-0.001, 0], + [0, 0], + [49.533, 72.097] + ], + "o": [ + [-21.1, 57.695], + [6.095, 4.328], + [0.828, 0.781], + [0.028, 0.009], + [0, 0], + [128.819, 32.377], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.24, -37.592], + [-91.478, 59.904], + [-79.834, 65.567], + [-70.2, 63.653], + [-74.895, 67.538], + [-63.431, 76.314], + [118.204, 107.289], + [78.983, -42.149] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 6, + "s": [ + { + "i": [ + [4.958, -13.557], + [-14.971, -28.341], + [-8.017, -30.669], + [-0.072, -0.072], + [0, 0], + [-0.001, 0], + [0, 0], + [49.054, 71.957] + ], + "o": [ + [-21.1, 57.695], + [4.259, 8.062], + [0.414, 1.584], + [0.023, 0.023], + [0, 0], + [120.262, 18.934], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.244, -37.6], + [-104.718, 84.406], + [-99.088, 97.807], + [-86.615, 95.947], + [-93.7, 101.796], + [-76.735, 110.726], + [118.2, 107.392], + [79.351, -42.232] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 8, + "s": [ + { + "i": [ + [4.958, -13.557], + [-24.143, -51.088], + [-4.67, -7.886], + [-0.113, -0.148], + [0, 0], + [-0.001, 0], + [0, 0], + [48.512, 72.547] + ], + "o": [ + [-21.1, 57.695], + [9.138, 19.337], + [1.559, 2.632], + [0.036, 0.047], + [0, 0], + [136.647, -28.464], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.26, -37.632], + [-68.974, 152.137], + [-46.757, 194.414], + [-43.026, 200.388], + [-42.945, 200.491], + [-40.922, 202.737], + [118.295, 107.025], + [79.669, -42.933] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 10, + "s": [ + { + "i": [ + [4.958, -13.557], + [-46.371, -73.317], + [-8.548, -11.764], + [-0.19, -0.226], + [0, 0], + [-0.001, 0], + [0, 0], + [50.179, 71.743] + ], + "o": [ + [-21.1, 57.695], + [17.552, 27.75], + [2.853, 3.926], + [0.06, 0.072], + [0, 0], + [62.762, -93.22], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.254, -37.61], + [-16.08, 205.046], + [25.633, 266.82], + [32.358, 275.789], + [32.493, 275.945], + [44.117, 273.293], + [118.19, 106.825], + [78.895, -42.464] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 12, + "s": [ + { + "i": [ + [4.958, -13.557], + [-42.898, -71.382], + [-46.761, -4.47], + [-1.155, -0.02], + [-0.148, 0.008], + [0, 0.001], + [0, 0], + [49.807, 71.372] + ], + "o": [ + [-19.02, 52.006], + [21.21, 35.525], + [15.604, 1.492], + [0.367, 0.006], + [0.08, -0.004], + [25.965, -117.977], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.254, -37.61], + [-63.588, 212.66], + [77.725, 265.313], + [117.149, 267.699], + [117.958, 267.711], + [122.85, 265.928], + [118.078, 107.048], + [79.044, -41.869] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 16, + "s": [ + { + "i": [ + [4.958, -13.557], + [-41.162, -70.414], + [-80.954, 1.113], + [-3.56, 8.732], + [-0.479, 1.208], + [-0.002, 0.001], + [0, 0], + [49.733, 71.945] + ], + "o": [ + [-17.98, 49.162], + [20.924, 35.794], + [35.989, -0.555], + [1.132, -2.776], + [0.26, -0.655], + [-0.984, 7.844], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.254, -37.588], + [-87.342, 216.489], + [124.946, 267.092], + [238.632, 154.696], + [241.122, 148.506], + [241.973, 143.474], + [117.744, 107.07], + [78.672, -41.996] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 17, + "s": [ + { + "i": [ + [4.958, -13.557], + [-41.162, -70.414], + [-82.63, 1.328], + [0.698, 13.729], + [0.152, 1.912], + [-0.002, 0.001], + [0, 0], + [49.661, 71.934] + ], + "o": [ + [-17.98, 49.162], + [20.689, 35.392], + [36.73, -0.63], + [-0.222, -4.364], + [-0.082, -1.036], + [-0.669, 9.641], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.257, -37.577], + [-87.345, 216.499], + [127.296, 267.381], + [243.441, 123.752], + [242.81, 113.989], + [243.347, 107.694], + [117.908, 107.229], + [78.818, -42.209] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 19, + "s": [ + { + "i": [ + [4.958, -13.557], + [-41.162, -70.414], + [-85.983, 1.758], + [9.212, 23.722], + [1.415, 3.32], + [-0.002, 0.001], + [0, 0], + [49.517, 71.914] + ], + "o": [ + [-17.98, 49.162], + [20.219, 34.588], + [38.212, -0.781], + [-2.928, -7.541], + [-0.767, -1.799], + [-0.041, 13.237], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.262, -37.557], + [-87.35, 216.52], + [131.997, 267.96], + [253.058, 61.864], + [246.185, 44.955], + [246.097, 46.842], + [118.238, 107.547], + [79.11, -42.634] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 21, + "s": [ + { + "i": [ + [4.958, -13.557], + [-41.162, -70.414], + [-85.983, 1.758], + [20.947, 34.315], + [3.148, 4.819], + [-0.002, 0.001], + [0, 0], + [49.421, 71.629] + ], + "o": [ + [-17.98, 49.162], + [20.219, 34.588], + [36.07, -0.737], + [-6.659, -10.909], + [-1.706, -2.611], + [-28.368, 71.546], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.277, -37.606], + [-87.365, 216.47], + [131.982, 267.91], + [242.606, 12.345], + [227.147, -12.156], + [224.474, -16.218], + [117.386, 107.497], + [79.318, -42.126] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 22, + "s": [ + { + "i": [ + [4.958, -13.557], + [-41.162, -70.414], + [-85.983, 1.758], + [33.859, 38.48], + [12.191, -1.596], + [-0.002, 0], + [0, 0], + [49.915, 72.127] + ], + "o": [ + [-17.98, 49.162], + [20.219, 34.588], + [36.07, -0.737], + [-11.542, -12.843], + [-9.467, 2.229], + [-0.676, 72.044], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.269, -37.603], + [-87.357, 216.473], + [131.989, 267.913], + [232.028, -23.026], + [186.694, -46.196], + [176.706, -31.884], + [117.505, 107.5], + [79.159, -42.067] + ], + "c": true + } + ] + }, + { + "i": { "x": 0.833, "y": 0.833 }, + "o": { "x": 0.167, "y": 0.167 }, + "t": 23, + "s": [ + { + "i": [ + [4.958, -13.557], + [-41.162, -70.414], + [-85.983, 1.758], + [46.771, 42.645], + [21.234, -8.012], + [-0.004, -0.002], + [0, 0], + [50.075, 71.622] + ], + "o": [ + [-17.98, 49.162], + [20.219, 34.588], + [36.07, -0.737], + [-16.424, -14.777], + [-17.228, 7.068], + [27.016, 72.542], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.262, -37.6], + [-87.35, 216.476], + [131.997, 267.916], + [221.45, -58.398], + [146.241, -80.236], + [128.938, -47.551], + [117.513, 107.392], + [78.999, -42.008] + ], + "c": true + } + ] + }, + { + "t": 24, + "s": [ + { + "i": [ + [4.958, -13.557], + [-41.162, -70.414], + [-85.983, 1.758], + [59.683, 46.81], + [30.278, -14.428], + [-0.004, -0.002], + [0, 0], + [48.952, 72.4] + ], + "o": [ + [-17.98, 49.162], + [20.219, 34.588], + [36.07, -0.737], + [-21.306, -16.71], + [-24.99, 11.908], + [38.597, 21.873], + [0, 0], + [-24.825, -30.697] + ], + "v": [ + [-101.254, -37.597], + [-87.342, 216.479], + [132.004, 267.919], + [210.872, -93.769], + [105.788, -114.277], + [81.17, -63.218], + [117.521, 107.507], + [79.341, -41.782] + ], + "c": true + } + ] + } + ], + "ix": 1 + }, + "o": { "a": 0, "k": 100, "ix": 3 }, + "x": { "a": 0, "k": 0, "ix": 4 }, + "nm": "蒙版 1" + } + ], + "ip": -30, + "op": 210, + "st": -30, + "bm": 0 + } + ], + "markers": [], + "tiny": 0.55 +}