From c0f3d84d8f9bf8e4bd7d5287a843d98425a84828 Mon Sep 17 00:00:00 2001 From: xiaoiver Date: Fri, 21 Jul 2023 15:53:09 +0800 Subject: [PATCH] Release (#1428) * fix: enhance perf of Text when fontSize changed in webgl (#1424) * fix: enhance perf of Text when fontSize changed in webgl #1422 * chore: commit changeset * fix: draw 1px sub-pixel line correctly in webgl #1425 * chore: commit changeset * chore: add testcase for sub-pixel line #1425 * fix: convertToPath should account for Rect with undefined x/y * chore: commit changeset * fix: make FillMesh instanced to enhance perf #1359 * chore: commit changeset * fix: make textBaseline in SVG the same with Canvas #1313 * chore: commit changeset * fix: add a fixed offset for Text in webgl #1380 * chore: commit changeset * fix: convertToPath should be compatible with empty coords * chore: commit changeset * chore(release): bump version (#1427) Co-authored-by: github-actions[bot] --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] --- .../__node__tests__/canvas/line.spec.js | 8 +- .../__node__tests__/canvas/snapshots/line.png | Bin 604 -> 897 bytes .../__node__tests__/webgl/line.spec.js | 8 +- .../__node__tests__/webgl/path.spec.js | 14 + .../webgl/snapshots/circle.png | Bin 4733 -> 4708 bytes .../webgl/snapshots/d3-barchart.png | Bin 14593 -> 14598 bytes .../webgl/snapshots/d3-scatterchart.png | Bin 55861 -> 55899 bytes .../webgl/snapshots/ellipse.png | Bin 6799 -> 6777 bytes .../__node__tests__/webgl/snapshots/line.png | Bin 378 -> 419 bytes .../webgl/snapshots/marker.png | Bin 3244 -> 3265 bytes .../__node__tests__/webgl/snapshots/path.png | Bin 8272 -> 8472 bytes .../__node__tests__/webgl/snapshots/text.png | Bin 11775 -> 11924 bytes packages/g-camera-api/CHANGELOG.md | 11 + packages/g-camera-api/package.json | 2 +- packages/g-canvas/CHANGELOG.md | 17 + packages/g-canvas/package.json | 2 +- packages/g-canvaskit/CHANGELOG.md | 17 + packages/g-canvaskit/package.json | 2 +- packages/g-components/CHANGELOG.md | 11 + packages/g-components/package.json | 2 +- .../g-dom-mutation-observer-api/CHANGELOG.md | 11 + .../g-dom-mutation-observer-api/package.json | 2 +- packages/g-gesture/CHANGELOG.md | 11 + packages/g-gesture/package.json | 2 +- packages/g-image-exporter/CHANGELOG.md | 11 + packages/g-image-exporter/package.json | 2 +- packages/g-lite/CHANGELOG.md | 10 + packages/g-lite/package.json | 2 +- packages/g-lite/src/utils/path.ts | 19 +- packages/g-lottie-player/CHANGELOG.md | 11 + packages/g-lottie-player/package.json | 2 +- packages/g-mobile-canvas-element/CHANGELOG.md | 11 + packages/g-mobile-canvas-element/package.json | 2 +- packages/g-mobile-canvas/CHANGELOG.md | 17 + packages/g-mobile-canvas/package.json | 2 +- packages/g-mobile-svg/CHANGELOG.md | 15 + packages/g-mobile-svg/package.json | 2 +- packages/g-mobile-webgl/CHANGELOG.md | 19 + packages/g-mobile-webgl/package.json | 2 +- packages/g-pattern/CHANGELOG.md | 11 + packages/g-pattern/package.json | 2 +- packages/g-plugin-3d/CHANGELOG.md | 15 + packages/g-plugin-3d/package.json | 2 +- packages/g-plugin-a11y/CHANGELOG.md | 11 + packages/g-plugin-a11y/package.json | 2 +- packages/g-plugin-annotation/CHANGELOG.md | 11 + packages/g-plugin-annotation/package.json | 2 +- packages/g-plugin-box2d/CHANGELOG.md | 11 + packages/g-plugin-box2d/package.json | 2 +- .../CHANGELOG.md | 11 + .../package.json | 2 +- packages/g-plugin-canvas-picker/CHANGELOG.md | 13 + packages/g-plugin-canvas-picker/package.json | 2 +- .../g-plugin-canvas-renderer/CHANGELOG.md | 13 + .../g-plugin-canvas-renderer/package.json | 2 +- .../g-plugin-canvaskit-renderer/CHANGELOG.md | 12 + .../g-plugin-canvaskit-renderer/package.json | 2 +- packages/g-plugin-control/CHANGELOG.md | 11 + packages/g-plugin-control/package.json | 2 +- packages/g-plugin-css-select/CHANGELOG.md | 11 + packages/g-plugin-css-select/package.json | 2 +- .../g-plugin-device-renderer/CHANGELOG.md | 20 + .../g-plugin-device-renderer/package.json | 2 +- .../src/meshes/Fill.ts | 210 ----- .../src/meshes/Image.ts | 16 +- .../src/meshes/Instanced.ts | 8 +- .../src/meshes/InstancedFill.ts | 134 +++ .../src/meshes/InstancedPath.ts | 495 ++++++++++- .../src/meshes/Line.ts | 818 ------------------ .../src/meshes/SDF.ts | 47 +- .../src/meshes/Text.ts | 66 +- .../src/meshes/index.ts | 3 +- .../src/renderer/BatchManager.ts | 81 +- .../src/renderer/Circle.ts | 6 +- .../src/renderer/Path.ts | 37 +- .../src/renderer/Rect.ts | 4 +- .../src/shader/instanced-line.frag | 7 +- .../src/shader/instanced-line.vert | 9 +- .../src/shader/mesh.frag | 21 +- .../src/shader/mesh.vert | 8 +- .../src/shader/text.vert | 5 +- .../g-plugin-dom-interaction/CHANGELOG.md | 11 + .../g-plugin-dom-interaction/package.json | 2 +- packages/g-plugin-dragndrop/CHANGELOG.md | 11 + packages/g-plugin-dragndrop/package.json | 2 +- packages/g-plugin-gpgpu/CHANGELOG.md | 12 + packages/g-plugin-gpgpu/package.json | 2 +- packages/g-plugin-html-renderer/CHANGELOG.md | 11 + packages/g-plugin-html-renderer/package.json | 2 +- packages/g-plugin-image-loader/CHANGELOG.md | 11 + packages/g-plugin-image-loader/package.json | 2 +- packages/g-plugin-matterjs/CHANGELOG.md | 11 + packages/g-plugin-matterjs/package.json | 2 +- .../g-plugin-mobile-interaction/CHANGELOG.md | 11 + .../g-plugin-mobile-interaction/package.json | 2 +- packages/g-plugin-physx/CHANGELOG.md | 11 + packages/g-plugin-physx/package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../g-plugin-rough-svg-renderer/CHANGELOG.md | 12 + .../g-plugin-rough-svg-renderer/package.json | 2 +- packages/g-plugin-svg-picker/CHANGELOG.md | 12 + packages/g-plugin-svg-picker/package.json | 2 +- packages/g-plugin-svg-renderer/CHANGELOG.md | 14 + packages/g-plugin-svg-renderer/package.json | 2 +- .../src/shapes/paths/Text.ts | 7 +- packages/g-plugin-webgl-device/CHANGELOG.md | 14 + packages/g-plugin-webgl-device/package.json | 2 +- packages/g-plugin-webgpu-device/CHANGELOG.md | 14 + packages/g-plugin-webgpu-device/package.json | 2 +- packages/g-plugin-yoga/CHANGELOG.md | 11 + packages/g-plugin-yoga/package.json | 2 +- .../CHANGELOG.md | 12 + .../package.json | 2 +- .../g-plugin-zdog-svg-renderer/CHANGELOG.md | 13 + .../g-plugin-zdog-svg-renderer/package.json | 2 +- packages/g-shader-components/CHANGELOG.md | 9 + packages/g-shader-components/mesh.both.glsl | 9 - packages/g-shader-components/package.json | 2 +- packages/g-svg/CHANGELOG.md | 14 + packages/g-svg/package.json | 2 +- packages/g-web-animations-api/CHANGELOG.md | 11 + packages/g-web-animations-api/package.json | 2 +- packages/g-web-components/CHANGELOG.md | 13 + packages/g-web-components/package.json | 2 +- packages/g-webgl/CHANGELOG.md | 18 + packages/g-webgl/package.json | 2 +- packages/g-webgpu/CHANGELOG.md | 18 + packages/g-webgpu/package.json | 2 +- packages/g/CHANGELOG.md | 14 + packages/g/package.json | 2 +- packages/react-g/CHANGELOG.md | 6 + packages/react-g/package.json | 2 +- site/examples/perf/animation/demo/meta.json | 14 + .../perf/animation/demo/webgl-opacity.js | 58 ++ .../perf/animation/demo/webgl-text.js | 139 +-- .../perf/webgl/demo/circle-linedash.js | 99 +++ site/examples/perf/webgl/demo/meta.json | 24 + site/examples/perf/webgl/demo/polygons.js | 118 +++ site/examples/perf/webgl/demo/polylines.js | 117 +++ .../examples/perf/webgl/demo/rounded-rects.js | 4 +- site/examples/shape/line/demo/meta.json | 8 + site/examples/shape/line/demo/thin-line.js | 124 +++ site/examples/shape/text/demo/meta.json | 7 + .../examples/shape/text/demo/text-baseline.js | 26 +- .../shape/text/demo/text-billboard.js | 241 ++++++ 146 files changed, 2337 insertions(+), 1410 deletions(-) delete mode 100644 packages/g-plugin-device-renderer/src/meshes/Fill.ts create mode 100644 packages/g-plugin-device-renderer/src/meshes/InstancedFill.ts delete mode 100644 packages/g-plugin-device-renderer/src/meshes/Line.ts delete mode 100644 packages/g-shader-components/mesh.both.glsl create mode 100644 site/examples/perf/animation/demo/webgl-opacity.js create mode 100644 site/examples/perf/webgl/demo/circle-linedash.js create mode 100644 site/examples/perf/webgl/demo/polygons.js create mode 100644 site/examples/perf/webgl/demo/polylines.js create mode 100644 site/examples/shape/line/demo/thin-line.js create mode 100644 site/examples/shape/text/demo/text-billboard.js diff --git a/__tests__/integration/__node__tests__/canvas/line.spec.js b/__tests__/integration/__node__tests__/canvas/line.spec.js index 0bb9f968c..0b325ff4b 100644 --- a/__tests__/integration/__node__tests__/canvas/line.spec.js +++ b/__tests__/integration/__node__tests__/canvas/line.spec.js @@ -76,9 +76,15 @@ describe('Render with g-canvas', () => { const line7 = line.cloneNode(); line7.style.stroke = 'linear-gradient(90deg, blue, green 40%, red)'; - line7.setPosition(150, 0); + line7.setPosition(180, 0); canvas.appendChild(line7); + // lineWidth less than 1px + const line8 = line.cloneNode(); + line8.style.lineWidth = 0.5; + line8.setPosition(10, 80); + canvas.appendChild(line8); + await sleep(300); await new Promise((resolve) => { diff --git a/__tests__/integration/__node__tests__/canvas/snapshots/line.png b/__tests__/integration/__node__tests__/canvas/snapshots/line.png index 188294c86443d1b57ca58c126bdcc7dc8feb320a..bba1f17626398a969e070ada997b5f01e01223da 100644 GIT binary patch delta 753 zcmcb^(#Sr+w4T|_)5S5QV$Rz;XY-^(CDQw&sDsM+flx1)vCO> z`roH#|M~H{S>aOfBt&8`oizQ+#J%yR=#S7trY&o747Bmc+AogTTnDbhG+6c zcE+7|(j3ej9B#~Tzno&_bF8_Zsc2)y!ViVT-4=|A$#Sx4?u&PI-(g9qyXurE+YfUf0}zL?$VpL7kRDi zR`jzku3B7II(LuYgzBfiRs8KL{+oPl|MIeI+2&}uzR8b0Whb3fsNC++_W9XsIo@+& zef#eo*va}NIewj_@Pz0YJd<9o;5(uI_{sY2GP9TJ*^@3*IBdK6Yx|BTKi*7BE;&)Z ztHI{}ft{rSX3y>_&5Tt`|6EmE_jzBY`sQcn?w)LTbL-iZTld9JChWA#FP>btt8?oW zskuBHyI$)4w7EWf|slVO!`&s$tU&Whq>jQU`d+U^4Uj4c1{KapJ z)vB*MmUP|ylC^DayXafT8=U+1-#z#EUG?@Oo7ivG`|78!t~a>4Wp8xS#@TV_CWYGX z%#E7Ns2Ml$`&+Ml?f!fp# z)qTsDUNcR;$f)A>KYpssx=F`x&tu=RcK=&Whv}RgA{-8S%6b8`GfFdL)0#bN9#3Ljf9W69@04l_* z(DMwTOO;TN2+<4$i$o-Q*up<=XYOzr?;iI{`1AO>rUv&(haa7r&s;;>sh-Pm4GlF0fCC4fPbu*fH0oZZ%cPDIssuk zCJ0mr$hMW_B+2_EZw{qTN#1tJuZh>~eLUJF>v}vYAe;9g$@xFuFY@O{da+D9>+3bOX?`CbwAbsI!Oc1DOa)LO6&=i zCIzi9L7<` with g-webgl', () => { const line7 = line.cloneNode(); line7.style.stroke = 'linear-gradient(90deg, blue, green 40%, red)'; - line7.setPosition(150, 0); + line7.setPosition(180, 0); canvas.appendChild(line7); + // lineWidth less than 1px + const line8 = line.cloneNode(); + line8.style.lineWidth = 0.5; + line8.setPosition(10, 80); + canvas.appendChild(line8); + await sleep(200); const pixels = new Uint8Array(width * height * 4); diff --git a/__tests__/integration/__node__tests__/webgl/path.spec.js b/__tests__/integration/__node__tests__/webgl/path.spec.js index 8beec7c45..b7f3bc743 100644 --- a/__tests__/integration/__node__tests__/webgl/path.spec.js +++ b/__tests__/integration/__node__tests__/webgl/path.spec.js @@ -131,6 +131,20 @@ describe('Render with g-webgl', () => { }); canvas.appendChild(path3); + const path4 = new Path({ + style: { + path: [['M', -6, -6], ['L', 6, -6], ['L', 6, 6], ['L', -6, 6], ['Z']], + lineWidth: 0, + fill: '#5AD8A6', + fillOpacity: 1, + stroke: '', + visibility: 'visible', + }, + }); + path4.translate(100, 100); + path4.scale(2); + canvas.appendChild(path4); + await sleep(200); const pixels = new Uint8Array(width * height * 4); diff --git a/__tests__/integration/__node__tests__/webgl/snapshots/circle.png b/__tests__/integration/__node__tests__/webgl/snapshots/circle.png index 2f09f6a75b2e8c66f3b85890dd9bc4308499fa98..a0f6ae4e3a3bf0e1af7d259f830cae93cd64723f 100644 GIT binary patch literal 4708 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 J;SKLU`xm*#=*<8C literal 4733 zcmds5XH-*No7GoAr7B33BGSPG5CH=MN|gWsDWN4GU3y14pHd>yTSAA>Bqa3SksuIy z?;uDo5drBhGI{-Ge$T8~^J{+GbMCqO+-L1|&fWX$btAMPs?-#$6xXg@qgH#Rq(ka^ z{<&_GliCu)(kxQS->B$K3c`-92rU3zH@%ugq@_D95_iO}DGV z1((xr(vH9UBjJ0}Z3bI3!u=DzMu9zhLw9B+_Dw0N-_kFl)*haVIo{LKvc!cL_HMJl z>JbAp*7a3zYmB4sEW@s)y~NsFv&+C6WU}_Rsat6h=M8p}zF)pjy{pAOP6lWp$d62` z`xzZPnTzL*3VRK56suI^r3Uy!PU{tTfd}RBLY{^$6-SKN+IeRQX)0}8=Y8u!VR1Nu zT1a*a>{ZMzpmnb@V1SY$Iit$-vMgIiJ6(O>xzfZ=&F7cKItml)i#-F#G+X6fZL1j+ z>k?mtfnlrW-1@&VU5=T$>-Ro5LC$yTKu-Ke4dYaAv?R4?Dwnf?k~#>lAfg+Sy2JjR zb8S};D%Rp-h)-k*rQxtb%L)t`n~EQD-eApir951BF9{KR7cmorUf7y5`YGJy$hq!vCJv&8meP@}T?|NFzV10d?h?(|UoH0G5bucCk z4bibI=B(%A~?utDIY*%rzU8SRpxy`XC~HzDSn;@sfoob^^K+E z&?74=6F#$b>(Kmk!8OK+Z08>`n|)EH^~ko+=ARl+(N(#ZexF=IPYfx25Xi34Jb22O{K7nRxtr84^Adg=0M24PqQ%B}xHXTn1A_yCtDukF-P;&5k@l7WAsxQf_UYkg zI7a`L646f&BZd4)PV$F$K4WeI1#tOrz}h{yC&x-~dkElZieropQ$}lMSS-kK zY;k>Gd^%o4)i^SqPuS}{X<^KfcoJ7dxJ5a7wz}B0D#=l+u~*W8t(4J!!mn=wW?t_> zr8j!wdwBKh))e*ZO8HtoK}hU4o-)(2-Xltni}wP(k>NQDL;&i-#2t?OafFa9`BSuw zKj{;f5ce7p_;i(-YvY_MPHroD?<9CgxnJ>+v>Pv! zzk15Fp*~kEJn6S+HT7T_7Wk`b(W37%v2?beS38l)JN!$pe6~xMl)*MO5>m33ir$u@ zmTXTC5^n;J42TfMlna`s=f0_31))=Ct6{G#=UX~u zFf4r)uCmUIp1x^aNYXA%PWTBDF;KdQw56vn=< zW@l`vWy_^^dYC+^Y5Zwjo6L)@LOp*oXuSJEKJ8hII3XfwldmBpYN|9KJu2Dd(AESO zj{!`cz6xPYoh?ymYPPu~m+GCqa}k$N0(T3EO8#NdBManoZDVOv3x>F6Y;jwyw!Cyt zs|1;6M_JYQnhnZrg(`)!dQ2Zn$Pdh}0ZvQ=Jk=@_?H8=}fMxb|Hsw(zEW1PDLMRNn zH;~7yLW5cx2me+gdE$bsxPC#HE$|CABdiCoU|C)?mNk3E1U0JB?|}w+{EJ33kK0!4 zh{)ug=}Nj_ZzSf47ZM|Sb4ubbKxSeTS3op`Pgn%8OIA3#<$I zVdUMZH@6CKNOS=Xy2n1ix^q!!{}E^+5qjSGcCyGQFM#Zv`7`#MncwU^^ukj>9A4O~ zF~wzab!NS7{Wd7oPcRVR;ZQug^Q1aBQfi*4r@nB&XkxtysLdU4;~Q}%XX+iM0*<3c zGiTv)>L|Ee-z}j9%xI=`z}LUvM+}snhRfaqX-TQ2<7AD+<7A}TIJK%mro)yhuYUpO z5{4pgI8ERPcj;}eTEvk_+m*ZpFz-aM-(8vBK9<)ht=?XzWJAyqkIT;(*SB&_QtA)` z(l}9rs;(O4{?zsIfz+44EH*9EYrRe?^WE;n^9_%x8_Vb(Pw-jfq%Kw~s_sHys4jXwJ}>SkjQ37K(Ux z`8vIpaT`^s!vwIlraX#K6yz*k#ZUlQzurZd3u4>4P;8q{>YA?bwO47n8vZ7q`%}Bv z8RUM(5w@Ksm;XUBD})@A@+Li`SM)qCnWT39K(#LmbT!2Lc~$}@z_j)i2DYn0o*`c3 z(qGAwgH~9ZCQ_Dv1L!sVNe;SW0CqR=1jB)O&cg>+V1}Iyr81v(@??lu$(EBABT>rg zms|*GMz4RvW0%9(5PoCaSGhK~XxbKhIybXy+;tkfi6gwTO&U_bwq*Xp!MxKqYU)m% z=$=CWp?hM^5#iO90tY2@4=v3{Q_T=_pw!FFSf2w=PM?l~;^!;eN0M{qnPN5%upQbc z!yR8c6Lt;G71%atBNcU!i@w z`k(R8GFH2TMSAMFpS89sNBYLib6h3Ase@0fq??!Tn3VXfgTJM` zD@2m)On6}}4w>Y>=vYGwshpyd^8I?lnCS7ZiRO9m7lBV+9Xe3pcQf|xN;V~u>3-j` zi}JdwZX_E*c~U-u{;xFB^dV5Aq%a`;q=covl5YFr{KbE!k!LB(gWkynm1|qWIg63V z8H;Ed#blX2y)z2Wx09P2g)^&UoCZam${dn9VKh5{+C_^Ane_OWid@n2+sahbvYn+SOTGDuktnmPBMxdBSY&0W<6;o#XDmmcaCZEXjD zfwbpq(q+EmXbnl#OzH!wV>0>C(kr31fkkt?fAESQd)A@+)9FWM6%6a!%{aN$lZ~6i zG@r6C^6EQ#eeO>gn4LpCsCA0*K>fx2X1{b#<@d`f&!!$0Nbl;bu@7PE2+KVQ%zM~g z4FjvF0L78Qm(j$<@zgOwigMXk}W2d4Bl4z@a34y;i@8L7n^l9x9CyhRzB}B9q z_ArykL0rEWYhyLNp6CzDeB^e!B;UpQH++7wQw1&cYE88KfGhF7wWThPycRXWEG5zW8)pyk?4>b3ZT-I;Z)=LhT?E)Pd;0(c^ z`x)ULROyS<*)i>@+-zvxcb+b}UOei_*LzPQD);~X%-cNN+2n^#3h@bfr{bEBm(K}8 zxe{CEdD-0ff6l1-o>FSKh9>JgM^-Ub1aQh6JrU#-M`Xi0?yDNzBm0x$mOm1f^EvlL zNHt&UfZe!0{~cp%VmBJeLnHd}V6LG{%w1-RDi`)l=e+;>4vAylt{*Vt>(q#XE^Z^9u+<%N3c}DM(o==o*#a|~B^>rrH3}-T zuck(F5STo4bTtRi?oA{|@q2(m;pl|pBwnwI#ZDGBs*%Z2oGQ(wyXA!&!{aR3NB!z= zZb3)=QlO)+C|R%;n!@ z+Yg`T^NhS4AGD3o!YAkqf57o5n|fMbK)l zTF7=P0T~-ugM<}FL#Ig^4U6D<}Wo{7h>5|zW}{sSH<7b$J7Vz!a67|LD(b<)nRd5^9Kie zU${t;yQ`D@(gn)Z=^j~3PK_fg!8VRDCXH_q-g%$^NmWYyM^3F-SJ1v4KTML=q_@bs zf3y6H#Iis`Io)-fXt}ZH;|+-3aD&RbdxjXZmRbLZO&#l0X)#1Xn3c{Xp`TxQhCoL{ zSehaw6tsqInG>Ctx?IG>QEc#X)TO-nvg~|IDrzJb)%U;inZ_J>{%@U5-&VH&*ifMG z;okRJ(k8aN6hgdLPD1L)rH$}X3Gn1P>3EEIW^3YASnd7?_WS=~if7vut&QaSUl=!DQPTgUYii06rBa1A GAN~W}{VO5> diff --git a/__tests__/integration/__node__tests__/webgl/snapshots/d3-barchart.png b/__tests__/integration/__node__tests__/webgl/snapshots/d3-barchart.png index ced8c8df422ff0f11f77545e9b42f4e028f7309d..01d881c009418c8d67d3d98a1d8e7b4221c3075d 100644 GIT binary patch literal 14598 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 z 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 A*8l(j diff --git a/__tests__/integration/__node__tests__/webgl/snapshots/ellipse.png b/__tests__/integration/__node__tests__/webgl/snapshots/ellipse.png index 36131919eef040308a625b2de56e75605ead350e..5298bc4232c078409d5a6a76128d9366c1046ea4 100644 GIT binary patch literal 6777 zcmd6M_dnZT^uG>W-lcYpqQnlZS-Vsav-SvLj}X$@tJ>-ygq9M7*b#)Fgj(qvrM3p4 zc3ae@wMXeE-rvtJ-^ceK_&y$a=DzMZ_nvd^eVuz==e%A>Qxm=G*SN3I(a~Mk2ZPLM zZPyvDT%!F~*b;MS&3S#0mSxzvHSXvkIy!FIv)+2^)ojb%=K|k0TZqNVa82n3kiVAB z4dI�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 I1Lv6k0nITjYybcN literal 6799 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 I&MBb@0H1ezI{*Lx literal 378 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yF?qT;hEy=Vk*d4Iz`$q>;=Mg+ zSR`X8z_3y7+Q0v&OP*z{JX5a2?Eq8^1pild?k{^A=i~eT!n(WND?8UmF}iC%c=3{b zcbWb&wI8fu2QFT21uOXA2oiS+7LG|^m9dS@xc=_w6&Cp|Onvk8OiT}wuaG_Xvbc|L mL8EBF7AA@}4+-oKaXCqZK`y*C_1dWzE7<=M4#u6-S>6v^SiEH*Z2GTet*AZZl}7c ztLUmIC@82?+_rcFZ$9`@LIKZsFMs!mJ3JPk8;B53(^}&9n62n(H zR}dN-2FseAsv`YNiZmWEt{fYomGe><=|5a}tDvH1>+6Rz9^>njsj3(^G$&;}MNc8h zR%a!QD*mXf&OOWUA7pv`-Y{xf{ZKNcjA3e$m6m)ot<8*M=Y|Z#`j&7z8Mq2`{Rz(5 zN|K>+n9IS+GebjV)l3WQwQj+OXq3r>#+!8nl_dA!??}iEv|V10cX*o@p&7P!vv^!~ z;;nn=l9~%9Bc|td?y23&um&fM#NaEzjUlg@;KHh{#o_3xUA8B|1%w^OyIc3~?BtgP zI|~a<^Vj!V5|G46lyaD}kdd_p6SHQKk+GH_i-%b0Oy1{ccEibK>?msv+eJ0R#%*z# z&!gdU^X%4OC4-;rXomDzylc>aL4uX$@%cBY;=>L$*|cN=GhkStS8H)BG-cKKc# zhZ`x%Zv8e-JoEDSC(g6oNGmO}O(>2TdEZS*Se~cJbHZYn=`LiYW!X$k4P9l-DhnXM zWP++CU_GaLba&hS0`1@E1no~-hw0#t)>>>jfpBk3UxczbMLK6?#wMeWzZR1$WaJj9 zMu3y};P#-q@g42xVi>8kBG`m=Z`aQ6_Y@PK5ckv&4Y3iqxjVntIA@~eO~USxt!J&7bDVs>(mLQOwb%oo>{>|V37g{n1FMYg!8Mndrw7^ZC>%3FYG#i_AHj_ ze!3V27*nLJg)ICE0d3xj%t#J|0y6jf{W1?83+>;0Q3a!Zi&LE?j5yl|`!EKNHDGY{;?K zJI5V6{cJorb~e2HuksueTz{98&cTtz*-FB#EVy`ApfFG}$TLa7h}YHu$m&x; zk7`KgeHmbZX3TuJyZ%Lc!XU^dhqvM?R%RgAW-)shek%C<#rzTU60?l_u&`AR1d+2N zYPA)B8LIK!Y>K&;Dq2DH~CXW8SDn2Ea>nk7v(u%OWMD4ck2#g=>bv3i(P`c zbm@WDBoTrAf4U-#p*0=|q{ZdRiai@h3Nq6|fNr$lw$cJ4tw_y)K`)h0+TVasZeMsd zWMuM@+|p130==MtV|>2D%Jo=Avj!0&D#iGOiaowCUN%%NkA>rRk zYxwBv@r$EbV@D2%`g|5UvEy|2^r5@)?Y9HGysHwTH#!^y^eHB|4_}R#x2EtuT24(3 z*oL*=RV~d9IBswaEJ$6dt~A$7a6UKQ`V*7Ze=VvC?Z&T!@$SwFmemc!S+Q(QP}*7c-+dey#jefpu>r zz2&2&wYB}`Ng*;PCwV65m6o9Q`e&M*WbBgxPzei^Xs=2m>gt6vC8c`$2Ga{55P!OM zZS(aTmfLlB=*Quqy88Nc*Rhnkn{Vd1_V{fH2|w5T-NeUdb5bG^h$w!tXvCo?Sp@po z;t^W1h=|)EKX!{m%`aB}FOF4jhTCbLo~U86SpDgun@m{8#JsMl#3N%cbFBxgEYz1T zfBqs5=NCXv^W^5AZEU>!Bt8!M9kST7RDD}Z3opQ$phVZ2bt|4 z+?gV?MIw^m?#zspOWy!0js%pO_Lyc zDP0}g`er55Y2pBlBI5M;oOY^(=5eyPbml|mc+=b2ank%NX(NZ)yU^nVP{8~L4O&zP zYqgYw1X!w)He_m24I$6`R);IM8KDnO-XtZYL)C~ZZiiXQdsVQLkvbY#oMqPd0M?*7 zw7@2qWFuIc6JP=rB(m7u<)ySI9a9Yky&*$X=r^-==A{nh=1LyJFEJe`x$D&_eX3Hm z1D9kqI(hnd+m%<04JDt1Tvu60s291w^q6`UR+ccy&al2+)^ccnqtln;ARje3NtTC2 X4D4`qLvH~7lPFM}sar0Q1AqN50{PRt literal 3244 zcmai1Ygkh07S@;$6U$2-4|FlYTf;ayps9I{V+!SHX^)*Wt!WhUsgxuOHANGfaMaYy z2{LrbGM`dU=_#+N95T8ni8h*|LJj z+AGj2)YR0p$s|{A;9Us55OCmH`0pYf@V1QXx@`|b{Vh6Htfqzx26yl3?)+@@bIiuB z;;4Uot#iwjT-QWPM@G?tx0bcQu59M&3gg9t&zalyb~SCYPBqapSQpUoodw#FQF0=e z(bKpE_v2T-mYkPK)&02@=|g^6TVfKXCmz@gy^AW8eA2|Qbcl#0FA^Nv%LvmTd{=7a zctxE|B81zUfA2+g(Gw?kcY6 z4I&TDQB?6hJ1jkGO(OM%$Gzm%+eo2M%P4P6BJArVRttNP6^BH^t38Ny`G< zFep!go-!Jqpg1bb`GfpJG$udW=ewH6!N0@@mf$yHEz;6_SFgNjrsqxFgef#zw`;di zo|8AxZ?|pkRTAk6n^k(1=CVCK4V|_(a3l7VtJ`cUfWO=Dxn$Y;uozZy2S}HVa|9f3 zQ*&JLE&LFeInLs_*!Jr6<0gJ+_fjh-?=MiNq-l!e7(jj(mr;>VH;JmqXjeCm080AX zs^?2E)aUP4(vIih?|`*Sr>KyM^mwBWiK0K*c%HHM%RUEw5sg{W*zr5&71h67NwV~u zK&=75?qg<)7Ue+##Eb_*(#5Y;0d?G5WuwPe#{#u853%892x6k`!5|lf0Gzx*F!v)g zlELCZrDfIYnx~v^0m0J+Zx%OSY*}em5WUr~ARkw-ewX*B6GU6!#M}Fhp}aT>@~5&? zQfG~7>%lHUH3SHAu3Gi^x@=k&lng2jDm=KEZe!yjrU0X3vM+);5`0Yj>yP+)s``RD zN|TC(Qt>o`R`8ySv@Q5>kxZNt|;qTeVKUy)(;KC>ovN4u3w}uk>;zC*`JgePiB>5LRl&`NpLAW4je1(iVU&v6uf?VRB`WL&(xR!0nJik}U@^Fgtxn8H9}n zd~)Fe_jZIMzW((-CW@+ro9MzZpBahg(rrYwzl=I&Ou8;oAVGpvOup!?EVWpk!aS}t zJyfp1)KY0bagZFIsmZv^X*=h8{kT|pt1OYQq(y0hVwyLiaAHkgPHf|O$M?&fr_UTX z{jfMYU8VToK|O#Dllbauwi5?|XM|R6veAB7o4RxVBW&#N9?H%WS2ezD4(O_gg@v<} znmVcJJmYR7e}S4*m-qfM%VhR8U3Zs%J71rCw!<{8CL%-_7#XjSp?*lnx+bx0x@63H z_I}u?{e!-mKMXsoq|*3LBQaio;07f4_lBVkt>S+I4d(q%=G~k1nM87RU)_N0ho_7u zf}CC6#gVj4j;{@5Z?s~2ye5+*^7bM5_6%CY!`JI0J-Oo_1eETX-c=xjCu4`ih5=C@ z+>Ix=8nAF_;!>rrKa+GIrq1F)m;1-l4@czOnu8_3hLqLxf6OwH4klIFk7rx;4zL^Q zKh-LH^Kn?f^tGMm!A=jm@b?Ulr3BXWO>=MIii#r{T@7nDY+%ScYmM`qY436N^1;3^ zpc!T&s9h6Bii*oC-b{0U(wIj?`?rRaRiUBCmP8tS%UbT)nds0kvR+Y9StV9P_Tll` zjv}A*USGArP#cJ#EFO{Fp^T_sB0>N~j8YFRo;Z~rIgs$k9TtI+q1ulgMh}maR~wVd zD&7pII+%VR8Fi>+EN5_Bta1K4e2_Rvxc~CGRfmKgz4OnsT&S%2P}hAezCwr3Y+L+S z$om7QyT+Pa0uWNKB@Vh0pbWX$aQ23DmiNj(gLMlxJS?P(GxJTitd-1zvS$-(a1hT5~&&o)_8tM-Gj(^EYu3>NfioX z^1unET*v8xqDjmREo145^oWxlZh^T_dQRR@hhmL#_A`F9z6Hu%F+fYiDp~6|T@#op or^SW-yU3vNr2(ILcGmFK-R5I24uy{ce?Qd7+dW;2hzHO7A7)AZ5dZ)H diff --git a/__tests__/integration/__node__tests__/webgl/snapshots/path.png b/__tests__/integration/__node__tests__/webgl/snapshots/path.png index ded062ee1287dd8e5bcd7a196e376b5c3a0ad43b..fbb279a23bd357b6792693516f41472c1fd247c7 100644 GIT binary patch literal 8472 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 SJn*j$=M-gC9_K$a^8Ft${B6nr literal 8272 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

aMx>y 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 literal 11775 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 diff --git a/packages/g-camera-api/CHANGELOG.md b/packages/g-camera-api/CHANGELOG.md index cfa87ce00..82d4ba614 100644 --- a/packages/g-camera-api/CHANGELOG.md +++ b/packages/g-camera-api/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-camera-api +## 1.2.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.2.5 ### Patch Changes diff --git a/packages/g-camera-api/package.json b/packages/g-camera-api/package.json index ba24eced9..2950be9e4 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.2.5", + "version": "1.2.6", "description": "A simple implementation of Camera API.", "keywords": [ "antv", diff --git a/packages/g-canvas/CHANGELOG.md b/packages/g-canvas/CHANGELOG.md index 8c8736f78..5691a829b 100644 --- a/packages/g-canvas/CHANGELOG.md +++ b/packages/g-canvas/CHANGELOG.md @@ -1,5 +1,22 @@ # @antv/g-canvas +## 1.11.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-plugin-canvas-path-generator@1.3.6 + - @antv/g-plugin-canvas-picker@1.10.6 + - @antv/g-plugin-canvas-renderer@1.9.6 + - @antv/g-plugin-dom-interaction@1.9.6 + - @antv/g-plugin-html-renderer@1.9.6 + - @antv/g-plugin-image-loader@1.3.6 + ## 1.11.5 ### Patch Changes diff --git a/packages/g-canvas/package.json b/packages/g-canvas/package.json index 57b0126e7..f7787e5b5 100644 --- a/packages/g-canvas/package.json +++ b/packages/g-canvas/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-canvas", - "version": "1.11.5", + "version": "1.11.6", "description": "A renderer implemented by Canvas 2D API", "keywords": [ "antv", diff --git a/packages/g-canvaskit/CHANGELOG.md b/packages/g-canvaskit/CHANGELOG.md index b5be877fc..d0409ba4d 100644 --- a/packages/g-canvaskit/CHANGELOG.md +++ b/packages/g-canvaskit/CHANGELOG.md @@ -1,5 +1,22 @@ # @antv/g-canvaskit +## 0.10.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-plugin-canvas-path-generator@1.3.6 + - @antv/g-plugin-canvas-picker@1.10.6 + - @antv/g-plugin-canvaskit-renderer@1.3.6 + - @antv/g-plugin-dom-interaction@1.9.6 + - @antv/g-plugin-html-renderer@1.9.6 + - @antv/g-plugin-image-loader@1.3.6 + ## 0.10.5 ### Patch Changes diff --git a/packages/g-canvaskit/package.json b/packages/g-canvaskit/package.json index 0fa983d1b..4ea1f414f 100644 --- a/packages/g-canvaskit/package.json +++ b/packages/g-canvaskit/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-canvaskit", - "version": "0.10.5", + "version": "0.10.6", "description": "A renderer implemented by CanvasKit", "keywords": [ "antv", diff --git a/packages/g-components/CHANGELOG.md b/packages/g-components/CHANGELOG.md index aad1ad8cb..e0b6d527b 100644 --- a/packages/g-components/CHANGELOG.md +++ b/packages/g-components/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-components +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-components/package.json b/packages/g-components/package.json index 27122f63e..16516880b 100644 --- a/packages/g-components/package.json +++ b/packages/g-components/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-components", - "version": "1.9.5", + "version": "1.9.6", "description": "Components for g", "keywords": [ "antv", diff --git a/packages/g-dom-mutation-observer-api/CHANGELOG.md b/packages/g-dom-mutation-observer-api/CHANGELOG.md index 2fe4168ba..be4a38b48 100644 --- a/packages/g-dom-mutation-observer-api/CHANGELOG.md +++ b/packages/g-dom-mutation-observer-api/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-dom-mutation-observer-api +## 1.2.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.2.5 ### Patch Changes diff --git a/packages/g-dom-mutation-observer-api/package.json b/packages/g-dom-mutation-observer-api/package.json index eb8ce6aa0..1d75affb4 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.2.5", + "version": "1.2.6", "description": "A simple implementation of DOM MutationObserver API.", "keywords": [ "antv", diff --git a/packages/g-gesture/CHANGELOG.md b/packages/g-gesture/CHANGELOG.md index 4e41b7621..e86e990c8 100644 --- a/packages/g-gesture/CHANGELOG.md +++ b/packages/g-gesture/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-gesture +## 2.2.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 2.2.5 ### Patch Changes diff --git a/packages/g-gesture/package.json b/packages/g-gesture/package.json index adf799b81..33bb32f84 100644 --- a/packages/g-gesture/package.json +++ b/packages/g-gesture/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-gesture", - "version": "2.2.5", + "version": "2.2.6", "description": "G Gesture", "keywords": [ "antv", diff --git a/packages/g-image-exporter/CHANGELOG.md b/packages/g-image-exporter/CHANGELOG.md index 1bba4d692..723fbf3d0 100644 --- a/packages/g-image-exporter/CHANGELOG.md +++ b/packages/g-image-exporter/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-image-exporter +## 0.7.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 0.7.5 ### Patch Changes diff --git a/packages/g-image-exporter/package.json b/packages/g-image-exporter/package.json index 3da0fb112..502a37c9e 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.7.5", + "version": "0.7.6", "description": "A image exporter for G using DOM API", "keywords": [ "antv", diff --git a/packages/g-lite/CHANGELOG.md b/packages/g-lite/CHANGELOG.md index 2e06b4b1e..ef8111ffc 100644 --- a/packages/g-lite/CHANGELOG.md +++ b/packages/g-lite/CHANGELOG.md @@ -1,5 +1,15 @@ # @antv/g-lite +## 1.2.6 + +### Patch Changes + +- 1b0901ba: Make FillMesh instanced to enhance perf. +- 1b0901ba: ConvertToPath should account for Rect with undefined x/y. +- 1b0901ba: Make textBaseline in SVG the same with Canvas. +- 1b0901ba: Add a fixed offset for Text. +- 1b0901ba: ConvertToPath should be compatible with empty coords. + ## 1.2.5 ### Patch Changes diff --git a/packages/g-lite/package.json b/packages/g-lite/package.json index 3cfbba4f8..7e9150644 100644 --- a/packages/g-lite/package.json +++ b/packages/g-lite/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-lite", - "version": "1.2.5", + "version": "1.2.6", "description": "A core module for rendering engine implements DOM API.", "keywords": [ "antv", diff --git a/packages/g-lite/src/utils/path.ts b/packages/g-lite/src/utils/path.ts index c33b046b4..d3f6cb2ca 100644 --- a/packages/g-lite/src/utils/path.ts +++ b/packages/g-lite/src/utils/path.ts @@ -854,16 +854,21 @@ export function convertToPath( let commands: AbsoluteArray = [] as unknown as AbsoluteArray; switch (object.nodeName) { case Shape.LINE: - const { x1, y1, x2, y2 } = (object as Line).parsedStyle; + const { x1 = 0, y1 = 0, x2 = 0, y2 = 0 } = (object as Line).parsedStyle; commands = lineToCommands(x1, y1, x2, y2); break; case Shape.CIRCLE: { - const { r, cx, cy } = (object as Circle).parsedStyle; + const { r = 0, cx = 0, cy = 0 } = (object as Circle).parsedStyle; commands = ellipseToCommands(r, r, cx, cy); break; } case Shape.ELLIPSE: { - const { rx, ry, cx, cy } = (object as Ellipse).parsedStyle; + const { + rx = 0, + ry = 0, + cx = 0, + cy = 0, + } = (object as Ellipse).parsedStyle; commands = ellipseToCommands(rx, ry, cx, cy); break; } @@ -876,7 +881,13 @@ export function convertToPath( ); break; case Shape.RECT: - const { width, height, x, y, radius } = (object as Rect).parsedStyle; + const { + width = 0, + height = 0, + x = 0, + y = 0, + radius, + } = (object as Rect).parsedStyle; const hasRadius = radius && radius.some((r) => r !== 0); commands = rectToCommands( diff --git a/packages/g-lottie-player/CHANGELOG.md b/packages/g-lottie-player/CHANGELOG.md index f8b05731c..3b21d3d3d 100644 --- a/packages/g-lottie-player/CHANGELOG.md +++ b/packages/g-lottie-player/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-lottie-player +## 0.2.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 0.2.5 ### Patch Changes diff --git a/packages/g-lottie-player/package.json b/packages/g-lottie-player/package.json index 022e76414..c76100b55 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.2.5", + "version": "0.2.6", "description": "A lottie player for G", "keywords": [ "antv", diff --git a/packages/g-mobile-canvas-element/CHANGELOG.md b/packages/g-mobile-canvas-element/CHANGELOG.md index 4c69a8f93..86f889bb4 100644 --- a/packages/g-mobile-canvas-element/CHANGELOG.md +++ b/packages/g-mobile-canvas-element/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-mobile-canvas-element +## 0.8.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 0.8.5 ### Patch Changes diff --git a/packages/g-mobile-canvas-element/package.json b/packages/g-mobile-canvas-element/package.json index 39688b572..6901dc1de 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.8.5", + "version": "0.8.6", "description": "Create a CanvasLike element from existed context in mobile environment", "keywords": [ "antv", diff --git a/packages/g-mobile-canvas/CHANGELOG.md b/packages/g-mobile-canvas/CHANGELOG.md index 3b62b7836..4a73d139a 100644 --- a/packages/g-mobile-canvas/CHANGELOG.md +++ b/packages/g-mobile-canvas/CHANGELOG.md @@ -1,5 +1,22 @@ # @antv/g-mobile-canvas +## 0.10.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-plugin-canvas-path-generator@1.3.6 + - @antv/g-plugin-canvas-picker@1.10.6 + - @antv/g-plugin-canvas-renderer@1.9.6 + - @antv/g-plugin-dragndrop@1.8.6 + - @antv/g-plugin-image-loader@1.3.6 + - @antv/g-plugin-mobile-interaction@0.9.6 + ## 0.10.5 ### Patch Changes diff --git a/packages/g-mobile-canvas/package.json b/packages/g-mobile-canvas/package.json index 56ebf7b5c..18a27331f 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.10.5", + "version": "0.10.6", "description": "A renderer implemented with Canvas2D API in mobile environment", "keywords": [ "antv", diff --git a/packages/g-mobile-svg/CHANGELOG.md b/packages/g-mobile-svg/CHANGELOG.md index ae20789b6..3fc00ebbd 100644 --- a/packages/g-mobile-svg/CHANGELOG.md +++ b/packages/g-mobile-svg/CHANGELOG.md @@ -1,5 +1,20 @@ # @antv/g-mobile-svg +## 0.10.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-plugin-svg-renderer@1.10.6 + - @antv/g-plugin-dragndrop@1.8.6 + - @antv/g-plugin-mobile-interaction@0.9.6 + - @antv/g-plugin-svg-picker@1.9.6 + ## 0.10.5 ### Patch Changes diff --git a/packages/g-mobile-svg/package.json b/packages/g-mobile-svg/package.json index 8df5ec3af..d100dcbbc 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.10.5", + "version": "0.10.6", "description": "A renderer implemented by SVG in mobile environment", "keywords": [ "antv", diff --git a/packages/g-mobile-webgl/CHANGELOG.md b/packages/g-mobile-webgl/CHANGELOG.md index c9909d903..7cc16c742 100644 --- a/packages/g-mobile-webgl/CHANGELOG.md +++ b/packages/g-mobile-webgl/CHANGELOG.md @@ -1,5 +1,24 @@ # @antv/g-mobile-webgl +## 0.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-plugin-device-renderer@1.9.6 + - @antv/g-lite@1.2.6 + - @antv/g-plugin-webgl-device@1.9.6 + - @antv/g-plugin-dragndrop@1.8.6 + - @antv/g-plugin-html-renderer@1.9.6 + - @antv/g-plugin-image-loader@1.3.6 + - @antv/g-plugin-mobile-interaction@0.9.6 + ## 0.9.5 ### Patch Changes diff --git a/packages/g-mobile-webgl/package.json b/packages/g-mobile-webgl/package.json index dbcd36395..a33db548b 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.9.5", + "version": "0.9.6", "description": "A renderer implemented by WebGL1/2 in mobile environment", "keywords": [ "antv", diff --git a/packages/g-pattern/CHANGELOG.md b/packages/g-pattern/CHANGELOG.md index f2c7b657b..f2ffc82e1 100644 --- a/packages/g-pattern/CHANGELOG.md +++ b/packages/g-pattern/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-pattern +## 1.2.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.2.5 ### Patch Changes diff --git a/packages/g-pattern/package.json b/packages/g-pattern/package.json index ab1e49660..5ab00d405 100644 --- a/packages/g-pattern/package.json +++ b/packages/g-pattern/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-pattern", - "version": "1.2.5", + "version": "1.2.6", "description": "A pattern libs for G", "keywords": [ "antv", diff --git a/packages/g-plugin-3d/CHANGELOG.md b/packages/g-plugin-3d/CHANGELOG.md index d563bb615..93b95cedd 100644 --- a/packages/g-plugin-3d/CHANGELOG.md +++ b/packages/g-plugin-3d/CHANGELOG.md @@ -1,5 +1,20 @@ # @antv/g-plugin-3d +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-plugin-device-renderer@1.9.6 + - @antv/g-shader-components@1.8.2 + - @antv/g-lite@1.2.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-3d/package.json b/packages/g-plugin-3d/package.json index 1819034b9..51802eeda 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.9.5", + "version": "1.9.6", "description": "Provide 3D extension for G", "keywords": [ "antv", diff --git a/packages/g-plugin-a11y/CHANGELOG.md b/packages/g-plugin-a11y/CHANGELOG.md index 380e0592d..ff801f4f3 100644 --- a/packages/g-plugin-a11y/CHANGELOG.md +++ b/packages/g-plugin-a11y/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-a11y +## 0.6.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 0.6.5 ### Patch Changes diff --git a/packages/g-plugin-a11y/package.json b/packages/g-plugin-a11y/package.json index eac84d52c..299d4de70 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.6.5", + "version": "0.6.6", "description": "A G plugin for accessibility", "keywords": [ "antv", diff --git a/packages/g-plugin-annotation/CHANGELOG.md b/packages/g-plugin-annotation/CHANGELOG.md index a1ea78aa6..175429a62 100644 --- a/packages/g-plugin-annotation/CHANGELOG.md +++ b/packages/g-plugin-annotation/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-annotation +## 0.4.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 0.4.5 ### Patch Changes diff --git a/packages/g-plugin-annotation/package.json b/packages/g-plugin-annotation/package.json index 286b0f89d..05773b16e 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.4.5", + "version": "0.4.6", "description": "A G plugin for annotation", "keywords": [ "antv", diff --git a/packages/g-plugin-box2d/CHANGELOG.md b/packages/g-plugin-box2d/CHANGELOG.md index 6d937c1da..7735db347 100644 --- a/packages/g-plugin-box2d/CHANGELOG.md +++ b/packages/g-plugin-box2d/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-box2d +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-box2d/package.json b/packages/g-plugin-box2d/package.json index 7411d09e0..975543fae 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.9.5", + "version": "1.9.6", "description": "A G plugin for Box2D", "keywords": [ "antv", diff --git a/packages/g-plugin-canvas-path-generator/CHANGELOG.md b/packages/g-plugin-canvas-path-generator/CHANGELOG.md index 9ed340881..397f4b606 100644 --- a/packages/g-plugin-canvas-path-generator/CHANGELOG.md +++ b/packages/g-plugin-canvas-path-generator/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-canvas-path-generator +## 1.3.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.3.5 ### Patch Changes diff --git a/packages/g-plugin-canvas-path-generator/package.json b/packages/g-plugin-canvas-path-generator/package.json index 669c4642b..015b925df 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.3.5", + "version": "1.3.6", "description": "A G plugin of path generator with Canvas2D API", "keywords": [ "antv", diff --git a/packages/g-plugin-canvas-picker/CHANGELOG.md b/packages/g-plugin-canvas-picker/CHANGELOG.md index 08d8d39c2..785f3ed22 100644 --- a/packages/g-plugin-canvas-picker/CHANGELOG.md +++ b/packages/g-plugin-canvas-picker/CHANGELOG.md @@ -1,5 +1,18 @@ # @antv/g-plugin-canvas-picker +## 1.10.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-plugin-canvas-path-generator@1.3.6 + - @antv/g-plugin-canvas-renderer@1.9.6 + ## 1.10.5 ### Patch Changes diff --git a/packages/g-plugin-canvas-picker/package.json b/packages/g-plugin-canvas-picker/package.json index ade327981..c6bf9916d 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.10.5", + "version": "1.10.6", "description": "A G plugin for picking in canvas", "keywords": [ "antv", diff --git a/packages/g-plugin-canvas-renderer/CHANGELOG.md b/packages/g-plugin-canvas-renderer/CHANGELOG.md index 8c701db8a..15d7e604d 100644 --- a/packages/g-plugin-canvas-renderer/CHANGELOG.md +++ b/packages/g-plugin-canvas-renderer/CHANGELOG.md @@ -1,5 +1,18 @@ # @antv/g-plugin-canvas-renderer +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-plugin-canvas-path-generator@1.3.6 + - @antv/g-plugin-image-loader@1.3.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-canvas-renderer/package.json b/packages/g-plugin-canvas-renderer/package.json index 0207dd9fe..da90a1e3b 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.9.5", + "version": "1.9.6", "description": "A G plugin of renderer implementation with Canvas2D API", "keywords": [ "antv", diff --git a/packages/g-plugin-canvaskit-renderer/CHANGELOG.md b/packages/g-plugin-canvaskit-renderer/CHANGELOG.md index da1a1a661..aa504bbaf 100644 --- a/packages/g-plugin-canvaskit-renderer/CHANGELOG.md +++ b/packages/g-plugin-canvaskit-renderer/CHANGELOG.md @@ -1,5 +1,17 @@ # @antv/g-plugin-canvaskit-renderer +## 1.3.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-plugin-image-loader@1.3.6 + ## 1.3.5 ### Patch Changes diff --git a/packages/g-plugin-canvaskit-renderer/package.json b/packages/g-plugin-canvaskit-renderer/package.json index 0a40882f3..6bfc1cc61 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.3.5", + "version": "1.3.6", "description": "A G plugin of renderer implementation with CanvasKit", "keywords": [ "antv", diff --git a/packages/g-plugin-control/CHANGELOG.md b/packages/g-plugin-control/CHANGELOG.md index 487abd26b..3c87ab950 100644 --- a/packages/g-plugin-control/CHANGELOG.md +++ b/packages/g-plugin-control/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-control +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-control/package.json b/packages/g-plugin-control/package.json index 3577e4b03..277a8dbb0 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.9.5", + "version": "1.9.6", "description": "A G plugin for orbit control", "keywords": [ "antv", diff --git a/packages/g-plugin-css-select/CHANGELOG.md b/packages/g-plugin-css-select/CHANGELOG.md index a9f27b6cc..229a246d4 100644 --- a/packages/g-plugin-css-select/CHANGELOG.md +++ b/packages/g-plugin-css-select/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-css-select +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-css-select/package.json b/packages/g-plugin-css-select/package.json index 69ee8a939..130dfd683 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.9.5", + "version": "1.9.6", "description": "A G plugin for using CSS select syntax in query selector", "keywords": [ "antv", diff --git a/packages/g-plugin-device-renderer/CHANGELOG.md b/packages/g-plugin-device-renderer/CHANGELOG.md index a73f48ab5..5771a0b23 100644 --- a/packages/g-plugin-device-renderer/CHANGELOG.md +++ b/packages/g-plugin-device-renderer/CHANGELOG.md @@ -1,5 +1,25 @@ # @antv/g-plugin-device-renderer +## 1.9.6 + +### Patch Changes + +- 1b0901ba: Make FillMesh instanced to enhance perf. +- 1b0901ba: ConvertToPath should account for Rect with undefined x/y. +- 1b0901ba: Make textBaseline in SVG the same with Canvas. +- 1b0901ba: Add a fixed offset for Text. +- 1b0901ba: ConvertToPath should be compatible with empty coords. +- 1b0901ba: Draw 1px sub-pixel line correctly in webgl. +- 1b0901ba: Enhance perf of Text when fontSize changed in webgl. +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-shader-components@1.8.2 + - @antv/g-lite@1.2.6 + - @antv/g-plugin-image-loader@1.3.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-device-renderer/package.json b/packages/g-plugin-device-renderer/package.json index 5ee4b2cff..c13eb6307 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.9.5", + "version": "1.9.6", "description": "A G plugin of renderer implementation with GPUDevice", "keywords": [ "antv", diff --git a/packages/g-plugin-device-renderer/src/meshes/Fill.ts b/packages/g-plugin-device-renderer/src/meshes/Fill.ts deleted file mode 100644 index 46e7096ed..000000000 --- a/packages/g-plugin-device-renderer/src/meshes/Fill.ts +++ /dev/null @@ -1,210 +0,0 @@ -import type { - DisplayObject, - ParsedBaseStyleProps, - Tuple4Number, -} from '@antv/g-lite'; -import { Shape, isCSSRGB } from '@antv/g-lite'; -import { mat4, vec3 } from 'gl-matrix'; -import { - FILL_TEXTURE_MAPPING, - Instanced, - VertexAttributeBufferIndex, - VertexAttributeLocation, -} from '../meshes/Instanced'; -import { Format, VertexBufferFrequency } from '../platform'; -import { RENDER_ORDER_SCALE } from '../renderer/Batch'; -import meshFrag from '../shader/mesh.frag'; -import meshVert from '../shader/mesh.vert'; -import { Uniform, updateBuffer } from './Line'; - -export class FillMesh extends Instanced { - shouldMerge(object: DisplayObject, index: number) { - return false; - } - - createGeometry(objects: DisplayObject[]): void { - const instance = objects[0]; - - // use triangles for Polygon - const { triangles, pointsBuffer } = updateBuffer(instance, true); - this.geometry.setVertexBuffer({ - bufferIndex: VertexAttributeBufferIndex.POSITION, - byteStride: 4 * 2, - frequency: VertexBufferFrequency.PerVertex, - attributes: [ - { - format: Format.F32_RG, - bufferByteOffset: 4 * 0, - location: VertexAttributeLocation.POSITION, - }, - ], - data: new Float32Array(pointsBuffer), - }); - const { halfExtents } = instance.getGeometryBounds(); - const uvsBuffer = pointsBuffer.map((x, i) => x / halfExtents[i % 2] / 2); - this.geometry.setVertexBuffer({ - bufferIndex: VertexAttributeBufferIndex.UV, - byteStride: 4 * 2, - frequency: VertexBufferFrequency.PerVertex, - attributes: [ - { - format: Format.F32_RG, - bufferByteOffset: 4 * 0, - location: VertexAttributeLocation.UV, - }, - ], - data: new Float32Array(uvsBuffer), - }); - this.geometry.vertexCount = triangles.length; - this.geometry.setIndexBuffer(new Uint32Array(triangles)); - } - - createMaterial(objects: DisplayObject[]): void { - this.material.vertexShader = meshVert; - this.material.fragmentShader = meshFrag; - - const instance = objects[0]; - const { fill, opacity, fillOpacity, anchor, visibility } = - instance.parsedStyle as ParsedBaseStyleProps; - let fillColor: Tuple4Number = [0, 0, 0, 0]; - if (isCSSRGB(fill)) { - fillColor = [ - Number(fill.r) / 255, - Number(fill.g) / 255, - Number(fill.b) / 255, - Number(fill.alpha), - ]; - } - - const encodedPickingColor = (instance.isInteractive() && - // @ts-ignore - instance.renderable3D?.encodedPickingColor) || [0, 0, 0]; - let translateX = 0; - let translateY = 0; - const contentBounds = instance.getGeometryBounds(); - if (contentBounds) { - const { halfExtents } = contentBounds; - translateX = -halfExtents[0] * anchor[0] * 2; - translateY = -halfExtents[1] * anchor[1] * 2; - } - - const m = mat4.create(); - mat4.mul( - m, - instance.getWorldTransform(), // apply anchor - mat4.fromTranslation(m, vec3.fromValues(translateX, translateY, 0)), - ); - - this.material.setUniforms({ - [Uniform.MODEL_MATRIX]: m, - [Uniform.FILL_COLOR]: fillColor, - [Uniform.PICKING_COLOR]: encodedPickingColor, - [Uniform.OPACITY]: opacity, - [Uniform.FILL_OPACITY]: fillOpacity, - [Uniform.VISIBLE]: visibility === 'visible' ? 1 : 0, - [Uniform.Z_INDEX]: instance.sortable.renderOrder * RENDER_ORDER_SCALE, - }); - } - - updateAttribute( - objects: DisplayObject[], - startIndex: number, - name: string, - value: any, - ): void { - super.updateAttribute(objects, startIndex, name, value); - - objects.forEach((object) => { - const { fill, opacity, fillOpacity, anchor, visibility } = - object.parsedStyle as ParsedBaseStyleProps; - if ( - name === 'lineJoin' || - name === 'lineCap' || - name === 'markerStart' || - name === 'markerEnd' || - name === 'markerStartOffset' || - name === 'markerEndOffset' || - (object.nodeName === Shape.RECT && - (name === 'width' || name === 'height' || name === 'radius')) || - (object.nodeName === Shape.LINE && - (name === 'x1' || name === 'y1' || name === 'x2' || name === 'y2')) || - (object.nodeName === Shape.POLYLINE && name === 'points') || - (object.nodeName === Shape.POLYGON && name === 'points') || - (object.nodeName === Shape.PATH && name === 'path') - ) { - // need re-calc geometry - this.material.geometryDirty = true; - this.material.programDirty = true; - } else if (name === 'fill') { - if (isCSSRGB(fill)) { - const fillColor = [ - Number(fill.r) / 255, - Number(fill.g) / 255, - Number(fill.b) / 255, - Number(fill.alpha), - ]; - this.material.setUniforms({ - [Uniform.FILL_COLOR]: fillColor, - }); - } else { - const i = this.textureMappings.findIndex( - (m) => m.name === FILL_TEXTURE_MAPPING, - ); - const fillTextureMapping = this.createFillGradientTextureMapping([ - this.instance, - ]); - if (i >= 0) { - this.textureMappings.splice(i, 1, fillTextureMapping); - } - this.material.textureDirty = true; - } - } else if (name === 'opacity') { - this.material.setUniforms({ - [Uniform.OPACITY]: opacity, - }); - } else if (name === 'fillOpacity') { - this.material.setUniforms({ - [Uniform.FILL_OPACITY]: fillOpacity, - }); - } else if (name === 'anchor' || name === 'modelMatrix') { - let translateX = 0; - let translateY = 0; - const contentBounds = object.getGeometryBounds(); - if (contentBounds) { - const { halfExtents } = contentBounds; - translateX = -halfExtents[0] * anchor[0] * 2; - translateY = -halfExtents[1] * anchor[1] * 2; - } - const m = mat4.create(); - mat4.mul( - m, - object.getWorldTransform(), // apply anchor - mat4.fromTranslation(m, vec3.fromValues(translateX, translateY, 0)), - ); - this.material.setUniforms({ - [Uniform.MODEL_MATRIX]: m, - }); - } else if (name === 'visibility') { - this.material.setUniforms({ - [Uniform.VISIBLE]: visibility === 'visible' ? 1 : 0, - }); - } else if (name === 'pointerEvents') { - const encodedPickingColor = (value && - object.isInteractive() && - // @ts-ignore - object.renderable3D?.encodedPickingColor) || [0, 0, 0]; - this.material.setUniforms({ - [Uniform.PICKING_COLOR]: encodedPickingColor, - }); - } - }); - } - - changeRenderOrder(object: DisplayObject, renderOrder: number) { - if (this.material) { - this.material.setUniforms({ - [Uniform.Z_INDEX]: renderOrder * RENDER_ORDER_SCALE, - }); - } - } -} diff --git a/packages/g-plugin-device-renderer/src/meshes/Image.ts b/packages/g-plugin-device-renderer/src/meshes/Image.ts index 0f8f02afe..4c8a68b63 100644 --- a/packages/g-plugin-device-renderer/src/meshes/Image.ts +++ b/packages/g-plugin-device-renderer/src/meshes/Image.ts @@ -45,25 +45,13 @@ export class ImageMesh extends Instanced { super.createGeometry(objects); const instanced: number[] = []; - const interleaved: number[] = []; - const indices: number[] = []; objects.forEach((object, i) => { const image = object as ImageShape; - const offset = i * 4; const { width, height, z, isBillboard } = image.parsedStyle; instanced.push(width, height, z, isBillboard ? 1 : 0); - interleaved.push(0, 0, 1, 0, 1, 1, 0, 1); - indices.push( - 0 + offset, - 2 + offset, - 1 + offset, - 0 + offset, - 3 + offset, - 2 + offset, - ); }); - this.geometry.setIndexBuffer(new Uint32Array(indices)); + this.geometry.setIndexBuffer(new Uint32Array([0, 2, 1, 0, 3, 2])); this.geometry.vertexCount = 6; this.geometry.setVertexBuffer({ bufferIndex: VertexAttributeBufferIndex.POSITION, @@ -89,7 +77,7 @@ export class ImageMesh extends Instanced { location: VertexAttributeLocation.UV, }, ], - data: new Float32Array(interleaved), + data: new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), }); } diff --git a/packages/g-plugin-device-renderer/src/meshes/Instanced.ts b/packages/g-plugin-device-renderer/src/meshes/Instanced.ts index 66b687b5a..beec10c8a 100644 --- a/packages/g-plugin-device-renderer/src/meshes/Instanced.ts +++ b/packages/g-plugin-device-renderer/src/meshes/Instanced.ts @@ -151,12 +151,12 @@ export abstract class Instanced { */ protected mergeAnchorIntoModelMatrix = false; - protected abstract createMaterial(objects: DisplayObject[]): void; - /** - * Get called when instance created or recreated. + * Create a new batch if the number of instances exceeds. */ - onCreate(object: DisplayObject) {} + maxInstances = 5000; + + protected abstract createMaterial(objects: DisplayObject[]): void; get instance() { return this.objects[0]; diff --git a/packages/g-plugin-device-renderer/src/meshes/InstancedFill.ts b/packages/g-plugin-device-renderer/src/meshes/InstancedFill.ts new file mode 100644 index 000000000..43c6660c7 --- /dev/null +++ b/packages/g-plugin-device-renderer/src/meshes/InstancedFill.ts @@ -0,0 +1,134 @@ +import type { DisplayObject } from '@antv/g-lite'; +import { + Instanced, + VertexAttributeBufferIndex, + VertexAttributeLocation, +} from '../meshes/Instanced'; +import { Format, VertexBufferFrequency } from '../platform'; +import meshFrag from '../shader/mesh.frag'; +import meshVert from '../shader/mesh.vert'; +import { updateBuffer } from './InstancedPath'; +import { RenderHelper } from '../render'; +import { TexturePool } from '../TexturePool'; +import { LightPool } from '../LightPool'; + +const SEGMENT_NUM = 12; + +export class InstancedFillMesh extends Instanced { + constructor( + protected renderHelper: RenderHelper, + protected texturePool: TexturePool, + protected lightPool: LightPool, + object: DisplayObject, + ) { + super(renderHelper, texturePool, lightPool, object); + this.trianglesHash = this.calcSegmentNum(object); + } + + private trianglesHash: [number[], number[]] = [[], []]; + private calcSegmentNum(object: DisplayObject): [number[], number[]] { + const { triangles, pointsBuffer } = updateBuffer(object, true, SEGMENT_NUM); + return [triangles, pointsBuffer]; + } + + private compareTrianglesHash(hash: [number[], number[]]) { + const [triangles, points] = this.trianglesHash; + const [t, p] = hash; + if (triangles.length !== t.length || points.length !== p.length) { + return false; + } + + if ( + triangles.some((n, i) => n !== t[i]) || + points.some((n, i) => n !== p[i]) + ) { + return false; + } + + return true; + } + + shouldMerge(object: DisplayObject, index: number) { + const shouldMerge = super.shouldMerge(object, index); + if (!shouldMerge) { + return false; + } + + const trianglesHash = this.calcSegmentNum(object); + return this.compareTrianglesHash(trianglesHash); + } + + createGeometry(objects: DisplayObject[]): void { + // use default common attributes + super.createGeometry(objects); + + const indices: number[] = []; + const pointsBuffer: number[] = []; + const uvsBuffer: number[] = []; + objects.forEach((object, i) => { + // use triangles for Polygon + const { triangles, pointsBuffer: pBuffer } = updateBuffer( + object, + true, + SEGMENT_NUM, + ); + + const { halfExtents } = object.getGeometryBounds(); + const uvBuffer = pBuffer.map((x, i) => x / halfExtents[i % 2] / 2); + + pointsBuffer.push(...pBuffer); + uvsBuffer.push(...uvBuffer); + indices.push(...triangles.map((n) => n + (i * pBuffer.length) / 2)); + }); + + this.geometry.setVertexBuffer({ + bufferIndex: VertexAttributeBufferIndex.POSITION, + byteStride: 4 * 2, + frequency: VertexBufferFrequency.PerVertex, + attributes: [ + { + format: Format.F32_RG, + bufferByteOffset: 4 * 0, + location: VertexAttributeLocation.POSITION, + }, + ], + data: new Float32Array(pointsBuffer), + }); + + this.geometry.setVertexBuffer({ + bufferIndex: VertexAttributeBufferIndex.UV, + byteStride: 4 * 2, + frequency: VertexBufferFrequency.PerVertex, + attributes: [ + { + format: Format.F32_RG, + bufferByteOffset: 4 * 0, + location: VertexAttributeLocation.UV, + }, + ], + data: new Float32Array(uvsBuffer), + }); + this.geometry.vertexCount = indices.length / objects.length; + this.geometry.setIndexBuffer(new Uint32Array(indices)); + } + + createMaterial(objects: DisplayObject[]): void { + this.material.vertexShader = meshVert; + this.material.fragmentShader = meshFrag; + this.material.defines = { + ...this.material.defines, + INSTANCED: true, + }; + } + + updateAttribute( + objects: DisplayObject[], + startIndex: number, + name: string, + value: any, + ): void { + super.updateAttribute(objects, startIndex, name, value); + + this.updateBatchedAttribute(objects, startIndex, name, value); + } +} diff --git a/packages/g-plugin-device-renderer/src/meshes/InstancedPath.ts b/packages/g-plugin-device-renderer/src/meshes/InstancedPath.ts index 4bc9813f0..b076a26eb 100644 --- a/packages/g-plugin-device-renderer/src/meshes/InstancedPath.ts +++ b/packages/g-plugin-device-renderer/src/meshes/InstancedPath.ts @@ -2,7 +2,21 @@ * Instanced line which has a better performance. * @see https://www.yuque.com/antv/ou292n/gg1gh5 */ -import { DisplayObject, ParsedPathStyleProps, Path, Shape } from '@antv/g-lite'; +import { + DisplayObject, + ParsedPathStyleProps, + Path, + Shape, + ParsedBaseStyleProps, + ParsedLineStyleProps, + Polyline, + isDisplayObject, + parsePath, + convertToPath, +} from '@antv/g-lite'; +import { mat4 } from 'gl-matrix'; +import { arcToCubic } from '@antv/util'; +import earcut from 'earcut'; import { Format, VertexBufferFrequency } from '../platform'; import frag from '../shader/line.frag'; import vert from '../shader/line.vert'; @@ -12,7 +26,10 @@ import { VertexAttributeBufferIndex, VertexAttributeLocation, } from './Instanced'; -import { updateBuffer } from './Line'; +import { RenderHelper } from '../render'; +import { TexturePool } from '../TexturePool'; +import { LightPool } from '../LightPool'; +import { bezierCurveTo, quadCurveTo } from '../utils'; enum LineVertexAttributeBufferIndex { PACKED = VertexAttributeBufferIndex.POSITION + 1, @@ -38,19 +55,13 @@ const SEGMENT_NUM = 12; * Used for Curve only contains 2 commands, e.g. [[M], [C | Q | A]] */ export class InstancedPathMesh extends Instanced { - static isOneCommandCurve(object: DisplayObject) { - if (object.nodeName === Shape.PATH) { - const { - path: { absolutePath }, - } = object.parsedStyle as ParsedPathStyleProps; - if (absolutePath.length >= 2) { - return true; - } - } - return false; - } - - onCreate(object: DisplayObject) { + constructor( + protected renderHelper: RenderHelper, + protected texturePool: TexturePool, + protected lightPool: LightPool, + object: DisplayObject, + ) { + super(renderHelper, texturePool, lightPool, object); this.segmentNum = this.calcSegmentNum(object); } @@ -262,7 +273,20 @@ export class InstancedPathMesh extends Instanced { this.updateBatchedAttribute(objects, startIndex, name, value); if ( + name === 'r' || + name === 'rx' || + name === 'ry' || + name === 'width' || + name === 'height' || + name === 'radius' || + name === 'x1' || + name === 'y1' || + name === 'x2' || + name === 'y2' || + name === 'points' || name === 'path' || + name === 'lineJoin' || + name === 'lineCap' || name === 'markerStartOffset' || name === 'markerEndOffset' || name === 'markerStart' || @@ -340,3 +364,444 @@ export class InstancedPathMesh extends Instanced { } } } + +export enum JOINT_TYPE { + NONE = 0, + FILL = 1, + JOINT_BEVEL = 4, + JOINT_MITER = 8, + JOINT_ROUND = 12, + JOINT_CAP_BUTT = 16, + JOINT_CAP_SQUARE = 18, + JOINT_CAP_ROUND = 20, + FILL_EXPAND = 24, + CAP_BUTT = 1 << 5, + CAP_SQUARE = 2 << 5, + CAP_ROUND = 3 << 5, + CAP_BUTT2 = 4 << 5, +} + +const stridePoints = 2; +const strideFloats = 3; + +export function updateBuffer( + object: DisplayObject, + needEarcut = false, + segmentNum?: number, +) { + const { lineCap, lineJoin } = object.parsedStyle as ParsedBaseStyleProps; + let { defX, defY } = object.parsedStyle; + const { markerStart, markerEnd, markerStartOffset, markerEndOffset } = + object.parsedStyle as ParsedLineStyleProps; + + const points: number[][] = []; + let triangles: number[] = []; + + if (object.nodeName === Shape.POLYLINE || object.nodeName === Shape.POLYGON) { + const polylineControlPoints = (object as Polyline).parsedStyle.points + .points; + const length = polylineControlPoints.length; + let startOffsetX = 0; + let startOffsetY = 0; + let endOffsetX = 0; + let endOffsetY = 0; + + let rad = 0; + let x: number; + let y: number; + + if (markerStart && isDisplayObject(markerStart) && markerStartOffset) { + x = polylineControlPoints[1][0] - polylineControlPoints[0][0]; + y = polylineControlPoints[1][1] - polylineControlPoints[0][1]; + rad = Math.atan2(y, x); + startOffsetX = Math.cos(rad) * (markerStartOffset || 0); + startOffsetY = Math.sin(rad) * (markerStartOffset || 0); + } + + if (markerEnd && isDisplayObject(markerEnd) && markerEndOffset) { + x = + polylineControlPoints[length - 2][0] - + polylineControlPoints[length - 1][0]; + y = + polylineControlPoints[length - 2][1] - + polylineControlPoints[length - 1][1]; + rad = Math.atan2(y, x); + endOffsetX = Math.cos(rad) * (markerEndOffset || 0); + endOffsetY = Math.sin(rad) * (markerEndOffset || 0); + } + + points[0] = polylineControlPoints.reduce((prev, cur, i) => { + let offsetX = 0; + let offsetY = 0; + if (i === 0) { + offsetX = startOffsetX; + offsetY = startOffsetY; + } else if (i === length - 1) { + offsetX = endOffsetX; + offsetY = endOffsetY; + } + + prev.push(cur[0] - defX + offsetX, cur[1] - defY + offsetY); + return prev; + }, [] as number[]); + + // close polygon, dealing with extra joint + if (object.nodeName === Shape.POLYGON) { + if (needEarcut) { + // use earcut for triangulation + triangles = earcut(points[0], [], 2); + return { + pointsBuffer: points[0], + travelBuffer: [], + triangles, + instancedCount: Math.round(points[0].length / stridePoints), + }; + } else { + points[0].push(points[0][0], points[0][1]); + points[0].push( + ...addTailSegment( + points[0][0], + points[0][1], + points[0][2], + points[0][3], + ), + ); + } + } + } else if ( + object.nodeName === Shape.PATH || + object.nodeName === Shape.CIRCLE || + object.nodeName === Shape.ELLIPSE || + object.nodeName === Shape.RECT + ) { + let path: ParsedPathStyleProps['path']; + if (object.nodeName !== Shape.PATH) { + path = parsePath(convertToPath(object, mat4.identity(mat4.create()))); + defX = path.rect.x; + defY = path.rect.y; + + // support negative width/height of Rect + if (object.nodeName === Shape.RECT) { + const { width, height } = object.parsedStyle; + if (width < 0) { + defX += path.rect.width; + } + if (height < 0) { + defY += path.rect.height; + } + } + } else { + path = object.parsedStyle.path; + } + const { absolutePath, segments } = path; + + let startOffsetX = 0; + let startOffsetY = 0; + let endOffsetX = 0; + let endOffsetY = 0; + + let rad = 0; + let x: number; + let y: number; + + if (markerStart && isDisplayObject(markerStart) && markerStartOffset) { + const [p1, p2] = (markerStart.parentNode as Path).getStartTangent(); + x = p1[0] - p2[0]; + y = p1[1] - p2[1]; + + rad = Math.atan2(y, x); + startOffsetX = Math.cos(rad) * (markerStartOffset || 0); + startOffsetY = Math.sin(rad) * (markerStartOffset || 0); + } + + if (markerEnd && isDisplayObject(markerEnd) && markerEndOffset) { + const [p1, p2] = (markerEnd.parentNode as Path).getEndTangent(); + x = p1[0] - p2[0]; + y = p1[1] - p2[1]; + rad = Math.atan2(y, x); + endOffsetX = Math.cos(rad) * (markerEndOffset || 0); + endOffsetY = Math.sin(rad) * (markerEndOffset || 0); + } + + let startPointIndex = -1; + let mCommandsNum = -1; + absolutePath.forEach(([command, ...params], i) => { + const nextSegment = absolutePath[i + 1]; + const useStartOffset = + i === 0 && (startOffsetX !== 0 || startOffsetY !== 0); + const useEndOffset = + (i === absolutePath.length - 1 || + (nextSegment && + (nextSegment[0] === 'M' || nextSegment[0] === 'Z'))) && + endOffsetX !== 0 && + endOffsetY !== 0; + + if (command === 'M') { + mCommandsNum++; + points[mCommandsNum] = []; + startPointIndex = points[mCommandsNum].length; + + if (useStartOffset) { + points[mCommandsNum].push( + params[0] - defX + startOffsetX, + params[1] - defY + startOffsetY, + params[0] - defX, + params[1] - defY, + ); + } else { + points[mCommandsNum].push(params[0] - defX, params[1] - defY); + } + } else if (command === 'L') { + if (useEndOffset) { + points[mCommandsNum].push( + params[0] - defX + endOffsetX, + params[1] - defY + endOffsetY, + ); + } else { + points[mCommandsNum].push(params[0] - defX, params[1] - defY); + } + } else if (command === 'Q') { + quadCurveTo( + params[0] - defX, + params[1] - defY, + params[2] - defX, + params[3] - defY, + points[mCommandsNum], + segmentNum, + ); + if (useEndOffset) { + points[mCommandsNum].push( + params[2] - defX + endOffsetX, + params[3] - defY + endOffsetY, + ); + } + } else if (command === 'A') { + // convert Arc to Cubic + + const [px1, py1] = segments[i].prePoint; + const args = arcToCubic( + px1, + py1, + params[0], + params[1], + params[2], + params[3], + params[4], + params[5], + params[6], + undefined, + ); + + // fixArc + for (let i = 0; i < args.length; i += 6) { + bezierCurveTo( + args[i] - defX, + args[i + 1] - defY, + args[i + 2] - defX, + args[i + 3] - defY, + args[i + 4] - defX, + args[i + 5] - defY, + points[mCommandsNum], + segmentNum, + ); + } + if (useEndOffset) { + points[mCommandsNum].push( + params[5] - defX + endOffsetX, + params[6] - defY + endOffsetY, + ); + } + } else if (command === 'C') { + bezierCurveTo( + params[0] - defX, + params[1] - defY, + params[2] - defX, + params[3] - defY, + params[4] - defX, + params[5] - defY, + points[mCommandsNum], + segmentNum, + ); + if (useEndOffset) { + points[mCommandsNum].push( + params[4] - defX + endOffsetX, + params[5] - defY + endOffsetY, + ); + } + } else if ( + command === 'Z' && + (object.nodeName === Shape.PATH || object.nodeName === Shape.RECT) + ) { + const epsilon = 0.0001; + // skip if already closed + if ( + Math.abs( + points[mCommandsNum][points[mCommandsNum].length - 2] - + points[mCommandsNum][startPointIndex], + ) > epsilon || + Math.abs( + points[mCommandsNum][points[mCommandsNum].length - 1] - + points[mCommandsNum][startPointIndex + 1], + ) > epsilon + ) { + points[mCommandsNum].push( + points[mCommandsNum][startPointIndex], + points[mCommandsNum][startPointIndex + 1], + ); + } + + points[mCommandsNum].push( + ...addTailSegment( + points[mCommandsNum][startPointIndex], + points[mCommandsNum][startPointIndex + 1], + points[mCommandsNum][startPointIndex + 2], + points[mCommandsNum][startPointIndex + 3], + ), + ); + } + }); + + if (needEarcut) { + const pointsBuffer = points.reduce((prev, cur) => { + prev.push(...cur); + return prev; + }, []); + // use earcut for triangulation + triangles = earcut(pointsBuffer, [], 2); + return { + pointsBuffer, + travelBuffer: [], + triangles, + instancedCount: Math.round(pointsBuffer.length / stridePoints), + }; + } + } + + const jointType = getJointType(lineJoin); + const capType = getCapType(lineCap); + let endJoint = capType; + if (capType === JOINT_TYPE.CAP_ROUND) { + endJoint = JOINT_TYPE.JOINT_CAP_ROUND; + } + if (capType === JOINT_TYPE.CAP_BUTT) { + endJoint = JOINT_TYPE.JOINT_CAP_BUTT; + } + if (capType === JOINT_TYPE.CAP_SQUARE) { + endJoint = JOINT_TYPE.JOINT_CAP_SQUARE; + } + + let j = (Math.round(0 / stridePoints) + 2) * strideFloats; + return points + .map((points) => { + // const needDash = !isNil(lineDash); + let dist = 0; + const pointsBuffer: number[] = []; + const travelBuffer: number[] = []; + for (let i = 0; i < points.length; i += stridePoints) { + // calc travel + // if (needDash) { + if (i > 1) { + dist += Math.sqrt( + Math.pow(points[i] - points[i - 2], 2) + + Math.pow(points[i + 1] - points[i + 1 - 2], 2), + ); + } + travelBuffer.push(dist); + // } else { + // travelBuffer.push(0); + // } + + pointsBuffer[j++] = points[i]; + pointsBuffer[j++] = points[i + 1]; + pointsBuffer[j] = jointType; + if (i == 0 && capType !== JOINT_TYPE.CAP_ROUND) { + pointsBuffer[j] += capType; + } + if (i + stridePoints * 2 >= points.length) { + pointsBuffer[j] += endJoint - jointType; + } else if (i + stridePoints >= points.length) { + pointsBuffer[j] = 0; + } + j++; + } + pointsBuffer[j++] = points[points.length - 4]; + pointsBuffer[j++] = points[points.length - 3]; + pointsBuffer[j++] = 0; + pointsBuffer[0] = points[0]; + pointsBuffer[1] = points[1]; + pointsBuffer[2] = 0; + pointsBuffer[3] = points[2]; + pointsBuffer[4] = points[3]; + pointsBuffer[5] = capType === JOINT_TYPE.CAP_ROUND ? capType : 0; + + const instancedCount = Math.round(points.length / stridePoints); + + return { + pointsBuffer, + travelBuffer, + triangles, + instancedCount, + }; + }) + .reduce( + (prev, cur) => { + prev.pointsBuffer.push(...cur.pointsBuffer); + prev.travelBuffer.push(...cur.travelBuffer); + prev.instancedCount += cur.instancedCount; + return prev; + }, + { + pointsBuffer: [], + travelBuffer: [], + triangles, + instancedCount: 0, + }, + ); +} + +function getJointType(lineJoin: CanvasLineJoin) { + let joint: number; + + switch (lineJoin) { + case 'bevel': + joint = JOINT_TYPE.JOINT_BEVEL; + break; + case 'round': + joint = JOINT_TYPE.JOINT_ROUND; + break; + default: + joint = JOINT_TYPE.JOINT_MITER; + break; + } + + return joint; +} + +function getCapType(lineCap: CanvasLineCap) { + let cap: number; + + switch (lineCap) { + case 'square': + cap = JOINT_TYPE.CAP_SQUARE; + break; + case 'round': + cap = JOINT_TYPE.CAP_ROUND; + break; + default: + cap = JOINT_TYPE.CAP_BUTT; + break; + } + + return cap; +} + +function addTailSegment( + x1: number, + y1: number, + x2: number = x1, + y2: number = y1, +) { + const vec = [x2 - x1, y2 - y1]; + const length = 0.01; + return [x1 + vec[0] * length, y1 + vec[1] * length]; +} diff --git a/packages/g-plugin-device-renderer/src/meshes/Line.ts b/packages/g-plugin-device-renderer/src/meshes/Line.ts deleted file mode 100644 index da72754b1..000000000 --- a/packages/g-plugin-device-renderer/src/meshes/Line.ts +++ /dev/null @@ -1,818 +0,0 @@ -/** - * @see https://www.khronos.org/assets/uploads/developers/presentations/Crazy_Panda_How_to_draw_lines_in_WebGL.pdf - */ -import type { - ParsedBaseStyleProps, - ParsedLineStyleProps, - ParsedPathStyleProps, - Path, - Polyline, - Tuple4Number, -} from '@antv/g-lite'; -import { - convertToPath, - DisplayObject, - parsePath, - Shape, - isCSSRGB, - isDisplayObject, -} from '@antv/g-lite'; -import { arcToCubic } from '@antv/util'; -import earcut from 'earcut'; -import { mat4, vec3 } from 'gl-matrix'; -import { Format, VertexBufferFrequency } from '../platform'; -import { RENDER_ORDER_SCALE } from '../renderer/Batch'; -import frag from '../shader/line.frag'; -import vert from '../shader/line.vert'; -import { bezierCurveTo, quadCurveTo } from '../utils'; -import { enumToObject } from '../utils/enum'; -import { Instanced } from './Instanced'; - -export enum JOINT_TYPE { - NONE = 0, - FILL = 1, - JOINT_BEVEL = 4, - JOINT_MITER = 8, - JOINT_ROUND = 12, - JOINT_CAP_BUTT = 16, - JOINT_CAP_SQUARE = 18, - JOINT_CAP_ROUND = 20, - FILL_EXPAND = 24, - CAP_BUTT = 1 << 5, - CAP_SQUARE = 2 << 5, - CAP_ROUND = 3 << 5, - CAP_BUTT2 = 4 << 5, -} - -const stridePoints = 2; -const strideFloats = 3; -// const strideBytes = 3 * 4; - -enum LineVertexAttributeBufferIndex { - PACKED = 0, - VERTEX_NUM, - TRAVEL, -} - -enum LineVertexAttributeLocation { - PREV = 0, - POINT1, - POINT2, - NEXT, - VERTEX_JOINT, - VERTEX_NUM, - TRAVEL, -} - -export enum Uniform { - MODEL_MATRIX = 'u_ModelMatrix', - FILL_COLOR = 'u_FillColor', - STROKE_COLOR = 'u_StrokeColor', - STROKE_WIDTH = 'u_StrokeWidth', - INCREASED_LINE_WIDTH_FOR_HIT_TESTING = 'u_IncreasedLineWidthForHitTesting', - OPACITY = 'u_Opacity', - FILL_OPACITY = 'u_FillOpacity', - STROKE_OPACITY = 'u_StrokeOpacity', - EXPAND = 'u_Expand', - MITER_LIMIT = 'u_MiterLimit', - SCALE_MODE = 'u_ScaleMode', - ALIGNMENT = 'u_Alignment', - PICKING_COLOR = 'u_PickingColor', - DASH = 'u_Dash', - GAP = 'u_Gap', - DASH_OFFSET = 'u_DashOffset', - VISIBLE = 'u_Visible', - Z_INDEX = 'u_ZIndex', -} - -export class LineMesh extends Instanced { - shouldMerge(object: DisplayObject, index: number) { - return false; - } - - updateAttribute( - objects: DisplayObject[], - startIndex: number, - name: string, - value: any, - ): void { - super.updateAttribute(objects, startIndex, name, value); - - objects.forEach((object) => { - const { - stroke, - opacity, - fillOpacity, - strokeOpacity, - lineWidth, - increasedLineWidthForHitTesting, - anchor, - lineDash, - lineDashOffset, - visibility, - } = object.parsedStyle as ParsedLineStyleProps; - if ( - name === 'lineJoin' || - name === 'lineCap' || - name === 'markerStart' || - name === 'markerEnd' || - name === 'markerStartOffset' || - name === 'markerEndOffset' || - (object.nodeName === Shape.CIRCLE && name === 'r') || - (object.nodeName === Shape.ELLIPSE && - (name === 'rx' || name === 'ry')) || - (object.nodeName === Shape.RECT && - (name === 'width' || name === 'height' || name === 'radius')) || - (object.nodeName === Shape.LINE && - (name === 'x1' || name === 'y1' || name === 'x2' || name === 'y2')) || - (object.nodeName === Shape.POLYLINE && name === 'points') || - (object.nodeName === Shape.POLYGON && name === 'points') || - (object.nodeName === Shape.PATH && name === 'path') - ) { - // need re-calc geometry - this.material.geometryDirty = true; - this.material.programDirty = true; - } else if (name === 'stroke') { - let strokeColor: Tuple4Number = [0, 0, 0, 0]; - if (isCSSRGB(stroke)) { - strokeColor = [ - Number(stroke.r) / 255, - Number(stroke.g) / 255, - Number(stroke.b) / 255, - Number(stroke.alpha), - ]; - } - this.material.setUniforms({ - [Uniform.STROKE_COLOR]: strokeColor, - }); - } else if (name === 'opacity') { - this.material.setUniforms({ - [Uniform.OPACITY]: opacity, - }); - } else if (name === 'fillOpacity') { - this.material.setUniforms({ - [Uniform.FILL_OPACITY]: fillOpacity, - }); - } else if (name === 'strokeOpacity') { - this.material.setUniforms({ - [Uniform.STROKE_OPACITY]: strokeOpacity, - }); - } else if (name === 'lineWidth') { - this.material.setUniforms({ - [Uniform.STROKE_WIDTH]: lineWidth, - }); - } else if (name === 'increasedLineWidthForHitTesting') { - this.material.setUniforms({ - [Uniform.INCREASED_LINE_WIDTH_FOR_HIT_TESTING]: - increasedLineWidthForHitTesting || 0, - }); - } else if (name === 'anchor' || name === 'modelMatrix') { - let translateX = 0; - let translateY = 0; - const contentBounds = object.getGeometryBounds(); - if (contentBounds) { - const { halfExtents } = contentBounds; - translateX = -halfExtents[0] * anchor[0] * 2; - translateY = -halfExtents[1] * anchor[1] * 2; - } - const m = mat4.create(); - mat4.mul( - m, - object.getWorldTransform(), // apply anchor - mat4.fromTranslation(m, vec3.fromValues(translateX, translateY, 0)), - ); - this.material.setUniforms({ - [Uniform.MODEL_MATRIX]: m, - }); - } else if (name === 'visibility') { - this.material.setUniforms({ - [Uniform.VISIBLE]: visibility === 'visible' ? 1 : 0, - }); - } else if (name === 'lineDash') { - this.material.setUniforms({ - [Uniform.DASH]: (lineDash && lineDash[0]) || 0, - [Uniform.GAP]: (lineDash && lineDash[1]) || 0, - }); - } else if (name === 'lineDashOffset') { - this.material.setUniforms({ - [Uniform.DASH_OFFSET]: lineDashOffset || 0, - }); - } else if (name === 'pointerEvents') { - const encodedPickingColor = (value && - object.isInteractive() && - // @ts-ignore - object.renderable3D?.encodedPickingColor) || [0, 0, 0]; - this.material.setUniforms({ - [Uniform.PICKING_COLOR]: encodedPickingColor, - }); - } - }); - } - - changeRenderOrder(object: DisplayObject, renderOrder: number) { - if (this.material) { - this.material.setUniforms({ - [Uniform.Z_INDEX]: renderOrder * RENDER_ORDER_SCALE, - }); - } - } - - createMaterial(objects: DisplayObject[]): void { - this.material.vertexShader = vert; - this.material.fragmentShader = frag; - this.material.defines = { - ...this.material.defines, - ...enumToObject(LineVertexAttributeLocation), - }; - - const instance = objects[0]; - - const { - fill, - stroke, - opacity, - fillOpacity, - strokeOpacity, - lineWidth, - increasedLineWidthForHitTesting, - anchor, - lineDash, - lineDashOffset, - visibility, - } = instance.parsedStyle as ParsedLineStyleProps; - let fillColor: Tuple4Number = [0, 0, 0, 0]; - if (isCSSRGB(fill)) { - fillColor = [ - Number(fill.r) / 255, - Number(fill.g) / 255, - Number(fill.b) / 255, - Number(fill.alpha), - ]; - } - let strokeColor: Tuple4Number = [0, 0, 0, 0]; - if (isCSSRGB(stroke)) { - strokeColor = [ - Number(stroke.r) / 255, - Number(stroke.g) / 255, - Number(stroke.b) / 255, - Number(stroke.alpha), - ]; - } - - const encodedPickingColor = (instance.isInteractive() && - // @ts-ignore - instance.renderable3D?.encodedPickingColor) || [0, 0, 0]; - let translateX = 0; - let translateY = 0; - const contentBounds = instance.getGeometryBounds(); - if (contentBounds) { - const { halfExtents } = contentBounds; - translateX = -halfExtents[0] * anchor[0] * 2; - translateY = -halfExtents[1] * anchor[1] * 2; - } - - const m = mat4.create(); - mat4.mul( - m, - instance.getWorldTransform(), // apply anchor - mat4.fromTranslation(m, vec3.fromValues(translateX, translateY, 0)), - ); - - this.material.setUniforms({ - [Uniform.MODEL_MATRIX]: m, - [Uniform.FILL_COLOR]: fillColor, - [Uniform.STROKE_COLOR]: strokeColor, - [Uniform.STROKE_WIDTH]: lineWidth, - [Uniform.INCREASED_LINE_WIDTH_FOR_HIT_TESTING]: - increasedLineWidthForHitTesting || 0, - [Uniform.OPACITY]: opacity, - [Uniform.FILL_OPACITY]: fillOpacity, - [Uniform.STROKE_OPACITY]: strokeOpacity, - [Uniform.EXPAND]: 1, - [Uniform.MITER_LIMIT]: 5, - [Uniform.SCALE_MODE]: 1, - [Uniform.ALIGNMENT]: 0.5, - [Uniform.PICKING_COLOR]: encodedPickingColor, - [Uniform.DASH]: (lineDash && lineDash[0]) || 0, - [Uniform.GAP]: (lineDash && lineDash[1]) || 0, - [Uniform.DASH_OFFSET]: lineDashOffset || 0, - [Uniform.VISIBLE]: visibility === 'visible' ? 1 : 0, - [Uniform.Z_INDEX]: instance.sortable.renderOrder * RENDER_ORDER_SCALE, - }); - } - - createGeometry(objects: DisplayObject[]): void { - const instance = objects[0]; - - // use triangles for Polygon - const { pointsBuffer, travelBuffer, instancedCount } = - updateBuffer(instance); - - // Empty path definition will cause WebGL context lost. - // @see https://github.com/antvis/G/issues/1417 - if (pointsBuffer.length) { - this.geometry.setVertexBuffer({ - bufferIndex: LineVertexAttributeBufferIndex.PACKED, - byteStride: 4 * (3 + 3 + 3 + 3), - frequency: VertexBufferFrequency.PerInstance, - attributes: [ - { - format: Format.F32_RG, - bufferByteOffset: 4 * 0, - byteStride: 4 * 3, - location: LineVertexAttributeLocation.PREV, - divisor: 1, - }, - { - format: Format.F32_RG, - bufferByteOffset: 4 * 3, - byteStride: 4 * 3, - location: LineVertexAttributeLocation.POINT1, - divisor: 1, - }, - { - format: Format.F32_R, - bufferByteOffset: 4 * 5, - byteStride: 4 * 3, - location: LineVertexAttributeLocation.VERTEX_JOINT, - divisor: 1, - }, - { - format: Format.F32_RG, - bufferByteOffset: 4 * 6, - byteStride: 4 * 3, - location: LineVertexAttributeLocation.POINT2, - divisor: 1, - }, - { - format: Format.F32_RG, - bufferByteOffset: 4 * 9, - byteStride: 4 * 3, - location: LineVertexAttributeLocation.NEXT, - divisor: 1, - }, - ], - data: new Float32Array(pointsBuffer), - }); - this.geometry.setVertexBuffer({ - bufferIndex: LineVertexAttributeBufferIndex.VERTEX_NUM, - byteStride: 4 * 1, - frequency: VertexBufferFrequency.PerInstance, - attributes: [ - { - format: Format.F32_R, - bufferByteOffset: 4 * 0, - byteStride: 4 * 1, - location: LineVertexAttributeLocation.VERTEX_NUM, - divisor: 0, - }, - ], - data: new Float32Array([0, 1, 2, 3, 4, 5, 6, 7, 8]), - }); - this.geometry.setVertexBuffer({ - bufferIndex: LineVertexAttributeBufferIndex.TRAVEL, - byteStride: 4 * 1, - frequency: VertexBufferFrequency.PerInstance, - attributes: [ - { - format: Format.F32_R, - bufferByteOffset: 4 * 0, - byteStride: 4 * 1, - location: LineVertexAttributeLocation.TRAVEL, - divisor: 1, - }, - ], - data: new Float32Array(travelBuffer), - }); - - this.geometry.vertexCount = 15; - this.geometry.instancedCount = instancedCount; - - this.geometry.setIndexBuffer( - new Uint32Array([0, 2, 1, 0, 3, 2, 4, 6, 5, 4, 7, 6, 4, 7, 8]), - ); - } - } -} - -export function updateBuffer( - object: DisplayObject, - needEarcut = false, - segmentNum?: number, -) { - const { lineCap, lineJoin } = object.parsedStyle as ParsedBaseStyleProps; - let { defX, defY } = object.parsedStyle; - const { markerStart, markerEnd, markerStartOffset, markerEndOffset } = - object.parsedStyle as ParsedLineStyleProps; - - const points: number[][] = []; - let triangles: number[] = []; - - if (object.nodeName === Shape.POLYLINE || object.nodeName === Shape.POLYGON) { - const polylineControlPoints = (object as Polyline).parsedStyle.points - .points; - const length = polylineControlPoints.length; - let startOffsetX = 0; - let startOffsetY = 0; - let endOffsetX = 0; - let endOffsetY = 0; - - let rad = 0; - let x: number; - let y: number; - - if (markerStart && isDisplayObject(markerStart) && markerStartOffset) { - x = polylineControlPoints[1][0] - polylineControlPoints[0][0]; - y = polylineControlPoints[1][1] - polylineControlPoints[0][1]; - rad = Math.atan2(y, x); - startOffsetX = Math.cos(rad) * (markerStartOffset || 0); - startOffsetY = Math.sin(rad) * (markerStartOffset || 0); - } - - if (markerEnd && isDisplayObject(markerEnd) && markerEndOffset) { - x = - polylineControlPoints[length - 2][0] - - polylineControlPoints[length - 1][0]; - y = - polylineControlPoints[length - 2][1] - - polylineControlPoints[length - 1][1]; - rad = Math.atan2(y, x); - endOffsetX = Math.cos(rad) * (markerEndOffset || 0); - endOffsetY = Math.sin(rad) * (markerEndOffset || 0); - } - - points[0] = polylineControlPoints.reduce((prev, cur, i) => { - let offsetX = 0; - let offsetY = 0; - if (i === 0) { - offsetX = startOffsetX; - offsetY = startOffsetY; - } else if (i === length - 1) { - offsetX = endOffsetX; - offsetY = endOffsetY; - } - - prev.push(cur[0] - defX + offsetX, cur[1] - defY + offsetY); - return prev; - }, [] as number[]); - - // close polygon, dealing with extra joint - if (object.nodeName === Shape.POLYGON) { - if (needEarcut) { - // use earcut for triangulation - triangles = earcut(points[0], [], 2); - return { - pointsBuffer: points[0], - travelBuffer: [], - triangles, - instancedCount: Math.round(points[0].length / stridePoints), - }; - } else { - points[0].push(points[0][0], points[0][1]); - points[0].push( - ...addTailSegment( - points[0][0], - points[0][1], - points[0][2], - points[0][3], - ), - ); - } - } - } else if ( - object.nodeName === Shape.PATH || - object.nodeName === Shape.CIRCLE || - object.nodeName === Shape.ELLIPSE || - object.nodeName === Shape.RECT - ) { - let path: ParsedPathStyleProps['path']; - if (object.nodeName !== Shape.PATH) { - path = parsePath(convertToPath(object, mat4.identity(mat4.create()))); - defX = path.rect.x; - defY = path.rect.y; - - // support negative width/height of Rect - if (object.nodeName === Shape.RECT) { - const { width, height } = object.parsedStyle; - if (width < 0) { - defX += path.rect.width; - } - if (height < 0) { - defY += path.rect.height; - } - } - } else { - path = object.parsedStyle.path; - } - const { absolutePath, segments } = path; - - let startOffsetX = 0; - let startOffsetY = 0; - let endOffsetX = 0; - let endOffsetY = 0; - - let rad = 0; - let x: number; - let y: number; - - if (markerStart && isDisplayObject(markerStart) && markerStartOffset) { - const [p1, p2] = (markerStart.parentNode as Path).getStartTangent(); - x = p1[0] - p2[0]; - y = p1[1] - p2[1]; - - rad = Math.atan2(y, x); - startOffsetX = Math.cos(rad) * (markerStartOffset || 0); - startOffsetY = Math.sin(rad) * (markerStartOffset || 0); - } - - if (markerEnd && isDisplayObject(markerEnd) && markerEndOffset) { - const [p1, p2] = (markerEnd.parentNode as Path).getEndTangent(); - x = p1[0] - p2[0]; - y = p1[1] - p2[1]; - rad = Math.atan2(y, x); - endOffsetX = Math.cos(rad) * (markerEndOffset || 0); - endOffsetY = Math.sin(rad) * (markerEndOffset || 0); - } - - let startPointIndex = -1; - let mCommandsNum = -1; - absolutePath.forEach(([command, ...params], i) => { - const nextSegment = absolutePath[i + 1]; - const useStartOffset = - i === 0 && (startOffsetX !== 0 || startOffsetY !== 0); - const useEndOffset = - (i === absolutePath.length - 1 || - (nextSegment && - (nextSegment[0] === 'M' || nextSegment[0] === 'Z'))) && - endOffsetX !== 0 && - endOffsetY !== 0; - - if (command === 'M') { - mCommandsNum++; - points[mCommandsNum] = []; - startPointIndex = points[mCommandsNum].length; - - if (useStartOffset) { - points[mCommandsNum].push( - params[0] - defX + startOffsetX, - params[1] - defY + startOffsetY, - params[0] - defX, - params[1] - defY, - ); - } else { - points[mCommandsNum].push(params[0] - defX, params[1] - defY); - } - } else if (command === 'L') { - if (useEndOffset) { - points[mCommandsNum].push( - params[0] - defX + endOffsetX, - params[1] - defY + endOffsetY, - ); - } else { - points[mCommandsNum].push(params[0] - defX, params[1] - defY); - } - } else if (command === 'Q') { - quadCurveTo( - params[0] - defX, - params[1] - defY, - params[2] - defX, - params[3] - defY, - points[mCommandsNum], - segmentNum, - ); - if (useEndOffset) { - points[mCommandsNum].push( - params[2] - defX + endOffsetX, - params[3] - defY + endOffsetY, - ); - } - } else if (command === 'A') { - // convert Arc to Cubic - - const [px1, py1] = segments[i].prePoint; - const args = arcToCubic( - px1, - py1, - params[0], - params[1], - params[2], - params[3], - params[4], - params[5], - params[6], - undefined, - ); - - // fixArc - for (let i = 0; i < args.length; i += 6) { - bezierCurveTo( - args[i] - defX, - args[i + 1] - defY, - args[i + 2] - defX, - args[i + 3] - defY, - args[i + 4] - defX, - args[i + 5] - defY, - points[mCommandsNum], - segmentNum, - ); - } - if (useEndOffset) { - points[mCommandsNum].push( - params[5] - defX + endOffsetX, - params[6] - defY + endOffsetY, - ); - } - } else if (command === 'C') { - bezierCurveTo( - params[0] - defX, - params[1] - defY, - params[2] - defX, - params[3] - defY, - params[4] - defX, - params[5] - defY, - points[mCommandsNum], - segmentNum, - ); - if (useEndOffset) { - points[mCommandsNum].push( - params[4] - defX + endOffsetX, - params[5] - defY + endOffsetY, - ); - } - } else if ( - command === 'Z' && - (object.nodeName === Shape.PATH || object.nodeName === Shape.RECT) - ) { - const epsilon = 0.0001; - // skip if already closed - if ( - Math.abs( - points[mCommandsNum][points[mCommandsNum].length - 2] - - points[mCommandsNum][startPointIndex], - ) > epsilon || - Math.abs( - points[mCommandsNum][points[mCommandsNum].length - 1] - - points[mCommandsNum][startPointIndex + 1], - ) > epsilon - ) { - points[mCommandsNum].push( - points[mCommandsNum][startPointIndex], - points[mCommandsNum][startPointIndex + 1], - ); - } - - points[mCommandsNum].push( - ...addTailSegment( - points[mCommandsNum][startPointIndex], - points[mCommandsNum][startPointIndex + 1], - points[mCommandsNum][startPointIndex + 2], - points[mCommandsNum][startPointIndex + 3], - ), - ); - } - }); - - if (needEarcut) { - const pointsBuffer = points.reduce((prev, cur) => { - prev.push(...cur); - return prev; - }, []); - // use earcut for triangulation - triangles = earcut(pointsBuffer, [], 2); - return { - pointsBuffer, - travelBuffer: [], - triangles, - instancedCount: Math.round(pointsBuffer.length / stridePoints), - }; - } - } - - const jointType = getJointType(lineJoin); - const capType = getCapType(lineCap); - let endJoint = capType; - if (capType === JOINT_TYPE.CAP_ROUND) { - endJoint = JOINT_TYPE.JOINT_CAP_ROUND; - } - if (capType === JOINT_TYPE.CAP_BUTT) { - endJoint = JOINT_TYPE.JOINT_CAP_BUTT; - } - if (capType === JOINT_TYPE.CAP_SQUARE) { - endJoint = JOINT_TYPE.JOINT_CAP_SQUARE; - } - - let j = (Math.round(0 / stridePoints) + 2) * strideFloats; - return points - .map((points) => { - // const needDash = !isNil(lineDash); - let dist = 0; - const pointsBuffer: number[] = []; - const travelBuffer: number[] = []; - for (let i = 0; i < points.length; i += stridePoints) { - // calc travel - // if (needDash) { - if (i > 1) { - dist += Math.sqrt( - Math.pow(points[i] - points[i - 2], 2) + - Math.pow(points[i + 1] - points[i + 1 - 2], 2), - ); - } - travelBuffer.push(dist); - // } else { - // travelBuffer.push(0); - // } - - pointsBuffer[j++] = points[i]; - pointsBuffer[j++] = points[i + 1]; - pointsBuffer[j] = jointType; - if (i == 0 && capType !== JOINT_TYPE.CAP_ROUND) { - pointsBuffer[j] += capType; - } - if (i + stridePoints * 2 >= points.length) { - pointsBuffer[j] += endJoint - jointType; - } else if (i + stridePoints >= points.length) { - pointsBuffer[j] = 0; - } - j++; - } - pointsBuffer[j++] = points[points.length - 4]; - pointsBuffer[j++] = points[points.length - 3]; - pointsBuffer[j++] = 0; - pointsBuffer[0] = points[0]; - pointsBuffer[1] = points[1]; - pointsBuffer[2] = 0; - pointsBuffer[3] = points[2]; - pointsBuffer[4] = points[3]; - pointsBuffer[5] = capType === JOINT_TYPE.CAP_ROUND ? capType : 0; - - const instancedCount = Math.round(points.length / stridePoints); - - return { - pointsBuffer, - travelBuffer, - triangles, - instancedCount, - }; - }) - .reduce( - (prev, cur) => { - prev.pointsBuffer.push(...cur.pointsBuffer); - prev.travelBuffer.push(...cur.travelBuffer); - prev.instancedCount += cur.instancedCount; - return prev; - }, - { - pointsBuffer: [], - travelBuffer: [], - triangles, - instancedCount: 0, - }, - ); -} - -function getJointType(lineJoin: CanvasLineJoin) { - let joint: number; - - switch (lineJoin) { - case 'bevel': - joint = JOINT_TYPE.JOINT_BEVEL; - break; - case 'round': - joint = JOINT_TYPE.JOINT_ROUND; - break; - default: - joint = JOINT_TYPE.JOINT_MITER; - break; - } - - return joint; -} - -function getCapType(lineCap: CanvasLineCap) { - let cap: number; - - switch (lineCap) { - case 'square': - cap = JOINT_TYPE.CAP_SQUARE; - break; - case 'round': - cap = JOINT_TYPE.CAP_ROUND; - break; - default: - cap = JOINT_TYPE.CAP_BUTT; - break; - } - - return cap; -} - -function addTailSegment( - x1: number, - y1: number, - x2: number = x1, - y2: number = y1, -) { - const vec = [x2 - x1, y2 - y1]; - const length = 0.01; - return [x1 + vec[0] * length, y1 + vec[1] * length]; -} diff --git a/packages/g-plugin-device-renderer/src/meshes/SDF.ts b/packages/g-plugin-device-renderer/src/meshes/SDF.ts index ab0ce420b..a6a64a2a6 100644 --- a/packages/g-plugin-device-renderer/src/meshes/SDF.ts +++ b/packages/g-plugin-device-renderer/src/meshes/SDF.ts @@ -41,19 +41,19 @@ export class SDFMesh extends Instanced { return false; } - if ( - this.needDrawStrokeSeparately(object.parsedStyle) || - this.needDrawStrokeSeparately(this.instance.parsedStyle) - ) { - return false; - } - - const { fill: instanceFill } = this.instance - .parsedStyle as ParsedBaseStyleProps; - const { fill } = object.parsedStyle as ParsedBaseStyleProps; - if ((instanceFill as CSSRGB).isNone !== (fill as CSSRGB).isNone) { - return false; - } + // if ( + // this.needDrawStrokeSeparately(object.parsedStyle) || + // this.needDrawStrokeSeparately(this.instance.parsedStyle) + // ) { + // return false; + // } + + // const { fill: instanceFill } = this.instance + // .parsedStyle as ParsedBaseStyleProps; + // const { fill } = object.parsedStyle as ParsedBaseStyleProps; + // if ((instanceFill as CSSRGB).isNone !== (fill as CSSRGB).isNone) { + // return false; + // } return true; } @@ -71,12 +71,9 @@ export class SDFMesh extends Instanced { // use default common attributes super.createGeometry(objects); - const interleaved = []; const instanced = []; - const indices = []; objects.forEach((object, i) => { const circle = object as Circle; - const offset = i * 4; // @ts-ignore const { radius } = circle.parsedStyle; const omitStroke = this.shouldOmitStroke(circle.parsedStyle); @@ -88,18 +85,9 @@ export class SDFMesh extends Instanced { omitStroke ? 1 : 0, circle.parsedStyle.isBillboard ? 1 : 0, ); - interleaved.push(-1, -1, 0, 0, 1, -1, 1, 0, 1, 1, 1, 1, -1, 1, 0, 1); - indices.push( - 0 + offset, - 2 + offset, - 1 + offset, - 0 + offset, - 3 + offset, - 2 + offset, - ); }); - this.geometry.setIndexBuffer(new Uint32Array(indices)); + this.geometry.setIndexBuffer(new Uint32Array([0, 2, 1, 0, 3, 2])); this.geometry.vertexCount = 6; this.geometry.setVertexBuffer({ bufferIndex: VertexAttributeBufferIndex.POSITION, @@ -117,7 +105,9 @@ export class SDFMesh extends Instanced { location: VertexAttributeLocation.UV, }, ], - data: new Float32Array(interleaved), + data: new Float32Array([ + -1, -1, 0, 0, 1, -1, 1, 0, 1, 1, 1, 1, -1, 1, 0, 1, + ]), }); this.geometry.setVertexBuffer({ bufferIndex: SDFVertexAttributeBufferIndex.PACKED_STYLE, @@ -161,7 +151,8 @@ export class SDFMesh extends Instanced { name === 'stroke' || name === 'lineDash' || name === 'strokeOpacity' || - name === 'radius' + name === 'radius' || + name === 'isBillboard' ) { const packed: number[] = []; objects.forEach((object) => { diff --git a/packages/g-plugin-device-renderer/src/meshes/Text.ts b/packages/g-plugin-device-renderer/src/meshes/Text.ts index 8f54226b4..ba18add77 100644 --- a/packages/g-plugin-device-renderer/src/meshes/Text.ts +++ b/packages/g-plugin-device-renderer/src/meshes/Text.ts @@ -4,7 +4,7 @@ import type { Text as TextShape, Tuple4Number, } from '@antv/g-lite'; -import { isCSSRGB } from '@antv/g-lite'; +import { isCSSRGB, runtime } from '@antv/g-lite'; import { mat4 } from 'gl-matrix'; import { CullMode, Format, VertexBufferFrequency } from '../platform'; import { RENDER_ORDER_SCALE } from '../renderer/Batch'; @@ -20,6 +20,9 @@ import type GlyphAtlas from './symbol/GlyphAtlas'; import { BASE_FONT_WIDTH, GlyphManager } from './symbol/GlyphManager'; import { getGlyphQuads } from './symbol/SymbolQuad'; import { packUint8ToFloat } from '../utils/compression'; +import { LightPool } from '../LightPool'; +import { TexturePool } from '../TexturePool'; +import { RenderHelper } from '../render'; enum TextVertexAttributeBufferIndex { INSTANCED = VertexAttributeBufferIndex.POSITION + 1, @@ -50,18 +53,19 @@ export class TextMesh extends Instanced { private tmpMat4 = mat4.create(); - shouldMerge(object: DisplayObject, index: number) { - const shouldMerge = super.shouldMerge(object, index); - - if (!shouldMerge) { - return false; - } + private fontHash: string; - if (this.index !== index) { - return false; - } + constructor( + protected renderHelper: RenderHelper, + protected texturePool: TexturePool, + protected lightPool: LightPool, + object: DisplayObject, + ) { + super(renderHelper, texturePool, lightPool, object); + this.fontHash = this.calcFontHash(object); + } - const instance = this.instance; + private calcFontHash(object: DisplayObject) { const instancedAttributes = [ 'fontSize', 'fontFamily', @@ -69,22 +73,26 @@ export class TextMesh extends Instanced { 'textBaseline', 'letterSpacing', ]; + return ( + object.parsedStyle.metrics.font + + instancedAttributes.reduce((prev, cur) => { + return prev + object.parsedStyle[cur]; + }, '') + ); + } - // fontStack & fontSize should be same - // if (instance.parsedStyle.fontSize !== object.parsedStyle.fontSize) { - // return false; - // } + shouldMerge(object: DisplayObject, index: number) { + const shouldMerge = super.shouldMerge(object, index); - if ( - instance.parsedStyle.metrics.font !== object.parsedStyle.metrics.font || - instancedAttributes.some( - (name) => instance.parsedStyle[name] !== object.parsedStyle[name], - ) - ) { + if (!shouldMerge) { + return false; + } + + if (this.index !== index) { return false; } - return true; + return this.fontHash === this.calcFontHash(object); } createGeometry(objects: DisplayObject[]): void { @@ -116,6 +124,9 @@ export class TextMesh extends Instanced { linePositionY = 0; } else if (textBaseline === 'alphabetic') { linePositionY = -height + lineHeight * 0.25; + if (!runtime.enableCSSParsing) { + linePositionY = -height; + } // linePositionY = -height + fontProperties.ascent; } else if (textBaseline === 'ideographic') { linePositionY = -height; @@ -307,7 +318,6 @@ export class TextMesh extends Instanced { name === 'lineHeight' || name === 'wordWrap' || name === 'textAlign' || - name === 'visibility' || name === 'dx' || name === 'dy' ) { @@ -323,7 +333,9 @@ export class TextMesh extends Instanced { name === 'strokeOpacity' || name === 'opacity' || name === 'lineWidth' || - name === 'pointerEvents' + name === 'visibility' || + name === 'pointerEvents' || + name === 'isBillboard' ) { const vertice = this.geometry.vertices[ TextVertexAttributeBufferIndex.INSTANCED @@ -370,10 +382,7 @@ export class TextMesh extends Instanced { // @ts-ignore object.renderable3D?.encodedPickingColor) || [0, 0, 0]; - const modelMatrix = - name === 'modelMatrix' - ? mat4.copy(this.tmpMat4, object.getWorldTransform()) - : null; + const modelMatrix = mat4.copy(this.tmpMat4, object.getWorldTransform()); const [start, end] = this.packedBufferObjectMap.get(object); const sliced = vertice.slice(start, end); @@ -413,6 +422,7 @@ export class TextMesh extends Instanced { sliced[i + 28] = encodedPickingColor[0]; sliced[i + 29] = encodedPickingColor[1]; sliced[i + 30] = encodedPickingColor[2]; + // sliced[i + 31] = object.sortable.renderOrder * RENDER_ORDER_SCALE; } this.geometry.updateVertexBuffer( diff --git a/packages/g-plugin-device-renderer/src/meshes/index.ts b/packages/g-plugin-device-renderer/src/meshes/index.ts index 701e9e8a7..366070ae6 100644 --- a/packages/g-plugin-device-renderer/src/meshes/index.ts +++ b/packages/g-plugin-device-renderer/src/meshes/index.ts @@ -2,8 +2,7 @@ export * from './Instanced'; export * from './SDF'; export * from './InstancedLine'; export * from './InstancedPath'; -export * from './Line'; -export * from './Fill'; +export * from './InstancedFill'; export * from './Image'; export * from './Text'; export * from './Mesh'; diff --git a/packages/g-plugin-device-renderer/src/renderer/BatchManager.ts b/packages/g-plugin-device-renderer/src/renderer/BatchManager.ts index 983972c5d..2320b0197 100644 --- a/packages/g-plugin-device-renderer/src/renderer/BatchManager.ts +++ b/packages/g-plugin-device-renderer/src/renderer/BatchManager.ts @@ -13,8 +13,6 @@ import type { Batch } from './Batch'; let stencilRefCounter = 1; -const MAX_INSTANCES_PER_BATCH = 5000; - export type BatchContext = { device: Device } & RenderingPluginContext; export class BatchManager { @@ -45,6 +43,7 @@ export class BatchManager { objectIndices: number[]; name: string; value: any; + // names: string[]; } > = {}; @@ -103,7 +102,7 @@ export class BatchManager { (mesh) => meshTag === mesh.constructor && mesh.index === i && - mesh.objects.length < MAX_INSTANCES_PER_BATCH && + mesh.objects.length < mesh.maxInstances && mesh.shouldMerge(object, i), ); if ( @@ -114,8 +113,8 @@ export class BatchManager { this.renderHelper, this.texturePool, this.lightPool, + object, ); - existedMesh.onCreate(object); existedMesh.renderer = renderer; existedMesh.index = i; this.meshes.push(existedMesh); @@ -192,7 +191,7 @@ export class BatchManager { (mesh) => meshCtor === mesh.constructor && mesh.index === i && - mesh.objects.length < MAX_INSTANCES_PER_BATCH && + mesh.objects.length < mesh.maxInstances && mesh.shouldMerge(object, i), ); @@ -202,11 +201,11 @@ export class BatchManager { this.renderHelper, this.texturePool, this.lightPool, + object, ); existedMesh.renderer = renderer; existedMesh.index = i; existedMesh.init(this.context); - existedMesh.onCreate(object); this.meshes.push(existedMesh); } else { existedMesh.geometryDirty = true; @@ -219,46 +218,46 @@ export class BatchManager { } } - if ( - shouldSubmit && - existedMesh && - existedMesh.inited && - !existedMesh.geometryDirty - ) { - const shouldMerge = existedMesh.shouldMerge(object, i); - if (shouldMerge) { - const objectIdx = existedMesh.objects.indexOf(object); - if (immediately) { - object.parsedStyle[attributeName] = newValue; - existedMesh.updateAttribute( - [object], - objectIdx, - attributeName, - newValue, - ); - } else { - const patchKey = existedMesh.id + attributeName; - if (!this.pendingUpdatePatches[patchKey]) { - this.pendingUpdatePatches[patchKey] = { - instance: existedMesh, - objectIndices: [], - name: attributeName, - value: newValue, - }; - } - if ( - this.pendingUpdatePatches[patchKey].objectIndices.indexOf( - objectIdx, - ) === -1 - ) { - this.pendingUpdatePatches[patchKey].objectIndices.push( + if (shouldSubmit && existedMesh) { + if (existedMesh.inited && !existedMesh.geometryDirty) { + const shouldMerge = existedMesh.shouldMerge(object, i); + if (shouldMerge) { + const objectIdx = existedMesh.objects.indexOf(object); + if (immediately) { + object.parsedStyle[attributeName] = newValue; + existedMesh.updateAttribute( + [object], objectIdx, + attributeName, + newValue, ); + } else { + const patchKey = existedMesh.id + attributeName; + if (!this.pendingUpdatePatches[patchKey]) { + this.pendingUpdatePatches[patchKey] = { + instance: existedMesh, + objectIndices: [], + name: attributeName, + value: newValue, + }; + } + if ( + this.pendingUpdatePatches[patchKey].objectIndices.indexOf( + objectIdx, + ) === -1 + ) { + this.pendingUpdatePatches[patchKey].objectIndices.push( + objectIdx, + ); + } } + } else { + this.remove(object); + this.add(object); } } else { - existedMesh.geometryDirty = true; - existedMesh.onCreate(object); + this.remove(object); + this.add(object); } } }); diff --git a/packages/g-plugin-device-renderer/src/renderer/Circle.ts b/packages/g-plugin-device-renderer/src/renderer/Circle.ts index 8564c747c..b4456ef3d 100644 --- a/packages/g-plugin-device-renderer/src/renderer/Circle.ts +++ b/packages/g-plugin-device-renderer/src/renderer/Circle.ts @@ -3,16 +3,16 @@ import type { DisplayObject, ParsedCircleStyleProps, } from '@antv/g-lite'; -import { LineMesh, SDFMesh } from '../meshes'; +import { InstancedPathMesh, SDFMesh } from '../meshes'; import { Batch } from './Batch'; /** * Use 2 meshes: * * SDF to draw fill & simple stroke if needed. - * * InstancedLine to draw stroke separately. + * * InstancedPathMesh to draw stroke separately. */ export class CircleRenderer extends Batch { - meshes = [SDFMesh, LineMesh]; + meshes = [SDFMesh, InstancedPathMesh]; shouldSubmitRenderInst(object: DisplayObject, index: number) { if (index === 0) { diff --git a/packages/g-plugin-device-renderer/src/renderer/Path.ts b/packages/g-plugin-device-renderer/src/renderer/Path.ts index bf1408b82..36f1bc4ff 100644 --- a/packages/g-plugin-device-renderer/src/renderer/Path.ts +++ b/packages/g-plugin-device-renderer/src/renderer/Path.ts @@ -4,10 +4,9 @@ import type { CSSRGB, DisplayObject, ParsedBaseStyleProps } from '@antv/g-lite'; import { Shape } from '@antv/g-lite'; import { - FillMesh, + InstancedFillMesh, InstancedLineMesh, InstancedPathMesh, - LineMesh, } from '../meshes'; import { Batch } from './Batch'; @@ -18,35 +17,32 @@ import { Batch } from './Batch'; * @see https://github.com/antvis/G/issues/1113 */ export class PathRenderer extends Batch { - meshes = [FillMesh, LineMesh, InstancedLineMesh, InstancedPathMesh]; + meshes = [InstancedFillMesh, InstancedLineMesh, InstancedPathMesh]; shouldSubmitRenderInst(object: DisplayObject, index: number) { - const { fill, stroke, opacity, strokeOpacity, lineDash, lineWidth } = + const { fill, stroke, opacity, strokeOpacity, lineWidth } = object.parsedStyle as ParsedBaseStyleProps; - const nodeName = object.nodeName; const hasStroke = stroke && !(stroke as CSSRGB).isNone; - const hasDash = - lineDash && lineDash.length && lineDash.every((item) => item !== 0); const isLine = InstancedLineMesh.isLine(object); - const isOneCommandCurve = InstancedPathMesh.isOneCommandCurve(object); object.renderable.proxyNodeName = isLine ? Shape.LINE : null; // Polyline don't need fill if ( index === 0 && - (isOneCommandCurve || - object.nodeName === Shape.POLYLINE || - (fill as CSSRGB).isNone) + (object.nodeName === Shape.POLYLINE || (fill as CSSRGB).isNone) ) { return false; } - // stroke mesh + // use Line for simple Path if (index === 1) { + return isLine; + } + + if (index === 2) { if ( isLine || - isOneCommandCurve || strokeOpacity === 0 || opacity === 0 || lineWidth === 0 || @@ -54,20 +50,7 @@ export class PathRenderer extends Batch { ) { return false; } - - if (nodeName === Shape.CIRCLE || nodeName === Shape.ELLIPSE) { - // @see https://github.com/antvis/g/issues/824 - return hasDash; - } - } - - // use Line for simple Path - if (index === 2) { - return isLine; - } - - if (index === 3) { - return !isLine && isOneCommandCurve; + return true; } return true; diff --git a/packages/g-plugin-device-renderer/src/renderer/Rect.ts b/packages/g-plugin-device-renderer/src/renderer/Rect.ts index cc49e8387..b38788b8d 100644 --- a/packages/g-plugin-device-renderer/src/renderer/Rect.ts +++ b/packages/g-plugin-device-renderer/src/renderer/Rect.ts @@ -1,5 +1,5 @@ import type { CSSRGB, DisplayObject, ParsedRectStyleProps } from '@antv/g-lite'; -import { FillMesh, LineMesh, SDFMesh } from '../meshes'; +import { InstancedFillMesh, InstancedPathMesh, SDFMesh } from '../meshes'; import { Batch } from './Batch'; /** @@ -8,7 +8,7 @@ import { Batch } from './Batch'; * * FillMesh & LineMesh to draw rounded rect with different radius. */ export class RectRenderer extends Batch { - meshes = [SDFMesh, FillMesh, LineMesh]; + meshes = [SDFMesh, InstancedFillMesh, InstancedPathMesh]; shouldSubmitRenderInst(object: DisplayObject, index: number) { const { radius } = object.parsedStyle as ParsedRectStyleProps; diff --git a/packages/g-plugin-device-renderer/src/shader/instanced-line.frag b/packages/g-plugin-device-renderer/src/shader/instanced-line.frag index 01ba0b6b5..6aa2b386c 100644 --- a/packages/g-plugin-device-renderer/src/shader/instanced-line.frag +++ b/packages/g-plugin-device-renderer/src/shader/instanced-line.frag @@ -24,7 +24,12 @@ void main() { outputColor = u_Color; #endif - float blur = smoothstep(0.0, v_Distance.y, 1.0 - abs(v_Distance.x)); + float blur; + if (v_Distance.y < 1.0) { + blur = smoothstep(0.0, v_Distance.y, 1.0 - abs(v_Distance.x)); + } else { + blur = 1.0 / v_Distance.y; + } float u_dash_offset = v_Dash.y; float u_dash_array = v_Dash.z; float u_dash_ratio = v_Dash.w; diff --git a/packages/g-plugin-device-renderer/src/shader/instanced-line.vert b/packages/g-plugin-device-renderer/src/shader/instanced-line.vert index 3bae5eb5f..db096fca8 100644 --- a/packages/g-plugin-device-renderer/src/shader/instanced-line.vert +++ b/packages/g-plugin-device-renderer/src/shader/instanced-line.vert @@ -30,6 +30,7 @@ void main() { } else { strokeWidth = u_StrokeWidth; } + float clampedStrokeWidth = max(strokeWidth, 1.0); float isBillboard = a_Dash.w; bool isPerspective = isPerspectiveMatrix(u_ProjectionMatrix); @@ -43,8 +44,8 @@ void main() { vec2 screen1 = u_Viewport * (0.5 * clip1.xy / clip1.w + 0.5); vec2 xBasis = normalize(screen1 - screen0); vec2 yBasis = vec2(-xBasis.y, xBasis.x); - vec2 pt0 = screen0 + strokeWidth * (a_Position.x * xBasis + a_Position.y * yBasis); - vec2 pt1 = screen1 + strokeWidth * (a_Position.x * xBasis + a_Position.y * yBasis); + vec2 pt0 = screen0 + clampedStrokeWidth * (a_Position.x * xBasis + a_Position.y * yBasis); + vec2 pt1 = screen1 + clampedStrokeWidth * (a_Position.x * xBasis + a_Position.y * yBasis); vec2 pt = mix(pt0, pt1, a_Position.z); vec4 clip = mix(clip0, clip1, a_Position.z); gl_Position = vec4(clip.w * (2.0 * pt / u_Viewport - 1.0), clip.z, clip.w); @@ -52,12 +53,12 @@ void main() { vec2 xBasis = a_PointB.xy - a_PointA.xy; vec2 yBasis = normalize(vec2(-xBasis.y, xBasis.x)); - vec2 point = a_PointA.xy + xBasis * a_Position.x + yBasis * strokeWidth * a_Position.y; + vec2 point = a_PointA.xy + xBasis * a_Position.x + yBasis * clampedStrokeWidth * a_Position.y; point = point - u_Anchor.xy * abs(xBasis); // round & square if (a_Cap > 1.0) { - point += sign(a_Position.x - 0.5) * normalize(xBasis) * vec2(strokeWidth / 2.0); + point += sign(a_Position.x - 0.5) * normalize(xBasis) * vec2(clampedStrokeWidth / 2.0); } gl_Position = project(vec4(point, u_ZIndex, 1.0), u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); } diff --git a/packages/g-plugin-device-renderer/src/shader/mesh.frag b/packages/g-plugin-device-renderer/src/shader/mesh.frag index 61439e1f5..31d68dbbd 100644 --- a/packages/g-plugin-device-renderer/src/shader/mesh.frag +++ b/packages/g-plugin-device-renderer/src/shader/mesh.frag @@ -1,30 +1,23 @@ #pragma glslify: import('@antv/g-shader-components/scene.both.glsl') -#pragma glslify: import('@antv/g-shader-components/mesh.both.glsl') + +#pragma glslify: import('@antv/g-shader-components/batch.declaration.frag') #pragma glslify: import('@antv/g-shader-components/uv.declaration.frag') #pragma glslify: import('@antv/g-shader-components/map.declaration.frag') out vec4 outputColor; -#define COLOR_SCALE 1. / 255. - void main(){ - if (u_Visible < 0.5) { - discard; - } + #pragma glslify: import('@antv/g-shader-components/batch.frag') + #pragma glslify: import('@antv/g-shader-components/map.frag') if (u_IsPicking > 0.5) { - vec3 pickingColor = COLOR_SCALE * u_PickingColor; - if (pickingColor.x == 0.0 && pickingColor.y == 0.0 && pickingColor.z == 0.0) { + if (u_PickingColor.x == 0.0 && u_PickingColor.y == 0.0 && u_PickingColor.z == 0.0) { discard; } - outputColor = vec4(pickingColor, 1.0); + outputColor = vec4(u_PickingColor, 1.0); } else { - - vec4 u_Color = u_FillColor; - - #pragma glslify: import('@antv/g-shader-components/map.frag') - outputColor = u_Color; + outputColor.a = outputColor.a * u_Opacity * u_FillOpacity; } } \ No newline at end of file diff --git a/packages/g-plugin-device-renderer/src/shader/mesh.vert b/packages/g-plugin-device-renderer/src/shader/mesh.vert index b43fee2f4..0d92a2bfe 100644 --- a/packages/g-plugin-device-renderer/src/shader/mesh.vert +++ b/packages/g-plugin-device-renderer/src/shader/mesh.vert @@ -1,5 +1,7 @@ #pragma glslify: import('@antv/g-shader-components/scene.both.glsl') -#pragma glslify: import('@antv/g-shader-components/mesh.both.glsl') + +#pragma glslify: import('@antv/g-shader-components/batch.declaration.vert') +#pragma glslify: project = require('@antv/g-shader-components/project.vert') layout(location = POSITION) in vec2 a_Position; #ifdef USE_UV @@ -8,6 +10,8 @@ layout(location = POSITION) in vec2 a_Position; #endif void main() { + #pragma glslify: import('@antv/g-shader-components/batch.vert') #pragma glslify: import('@antv/g-shader-components/uv.vert') - gl_Position = u_ProjectionMatrix * u_ViewMatrix * u_ModelMatrix * vec4(a_Position, u_ZIndex, 1.0); + + gl_Position = project(vec4(a_Position, u_ZIndex, 1.0), u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); } \ No newline at end of file diff --git a/packages/g-plugin-device-renderer/src/shader/text.vert b/packages/g-plugin-device-renderer/src/shader/text.vert index de8df029d..42b02b94e 100644 --- a/packages/g-plugin-device-renderer/src/shader/text.vert +++ b/packages/g-plugin-device-renderer/src/shader/text.vert @@ -22,13 +22,14 @@ void main() { bool isBillboard = a_StylePacked2.y > 0.5; float sizeAttenuation = a_StylePacked2.z; - vec2 offset = a_Offset * fontScale; + vec2 bufferOffset = vec2(0.7, 2.0); + vec2 offset = a_Offset * fontScale + bufferOffset; if (isBillboard) { #pragma glslify: import('@antv/g-shader-components/billboard.vert') v_GammaScale = 1.0; } else { - gl_Position = project(vec4(a_Offset * fontScale, u_ZIndex, 1.0), u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); + gl_Position = project(vec4((a_Offset) * fontScale + bufferOffset, u_ZIndex, 1.0), u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); v_GammaScale = gl_Position.w; } } \ No newline at end of file diff --git a/packages/g-plugin-dom-interaction/CHANGELOG.md b/packages/g-plugin-dom-interaction/CHANGELOG.md index 702c02949..0fce7321b 100644 --- a/packages/g-plugin-dom-interaction/CHANGELOG.md +++ b/packages/g-plugin-dom-interaction/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-dom-interaction +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-dom-interaction/package.json b/packages/g-plugin-dom-interaction/package.json index 6cafa6042..f1833414a 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.9.5", + "version": "1.9.6", "description": "A G plugin", "keywords": [ "antv", diff --git a/packages/g-plugin-dragndrop/CHANGELOG.md b/packages/g-plugin-dragndrop/CHANGELOG.md index f86c72013..0d26b60fc 100644 --- a/packages/g-plugin-dragndrop/CHANGELOG.md +++ b/packages/g-plugin-dragndrop/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-dragndrop +## 1.8.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.8.5 ### Patch Changes diff --git a/packages/g-plugin-dragndrop/package.json b/packages/g-plugin-dragndrop/package.json index 2598c4ef3..350663c02 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.8.5", + "version": "1.8.6", "description": "A G plugin for Drag n Drop implemented with PointerEvents", "keywords": [ "antv", diff --git a/packages/g-plugin-gpgpu/CHANGELOG.md b/packages/g-plugin-gpgpu/CHANGELOG.md index e30fe867b..44c13c31e 100644 --- a/packages/g-plugin-gpgpu/CHANGELOG.md +++ b/packages/g-plugin-gpgpu/CHANGELOG.md @@ -1,5 +1,17 @@ # @antv/g-plugin-gpgpu +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-webgpu@1.9.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-gpgpu/package.json b/packages/g-plugin-gpgpu/package.json index 55f6922f9..f3ecaa059 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.9.5", + "version": "1.9.6", "description": "A G plugin for GPGPU based on WebGPU", "keywords": [ "webgpu", diff --git a/packages/g-plugin-html-renderer/CHANGELOG.md b/packages/g-plugin-html-renderer/CHANGELOG.md index e3a8bd298..27e6f14f2 100644 --- a/packages/g-plugin-html-renderer/CHANGELOG.md +++ b/packages/g-plugin-html-renderer/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-html-renderer +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-html-renderer/package.json b/packages/g-plugin-html-renderer/package.json index 943709080..5de139e5f 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.9.5", + "version": "1.9.6", "description": "A G plugin for rendering HTML", "keywords": [ "antv", diff --git a/packages/g-plugin-image-loader/CHANGELOG.md b/packages/g-plugin-image-loader/CHANGELOG.md index e359d2c2e..1f1280048 100644 --- a/packages/g-plugin-image-loader/CHANGELOG.md +++ b/packages/g-plugin-image-loader/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-image-loader +## 1.3.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.3.5 ### Patch Changes diff --git a/packages/g-plugin-image-loader/package.json b/packages/g-plugin-image-loader/package.json index 84326e03f..a1f311af9 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.3.5", + "version": "1.3.6", "description": "A G plugin for loading image", "keywords": [ "antv", diff --git a/packages/g-plugin-matterjs/CHANGELOG.md b/packages/g-plugin-matterjs/CHANGELOG.md index 919c154c8..e8915acca 100644 --- a/packages/g-plugin-matterjs/CHANGELOG.md +++ b/packages/g-plugin-matterjs/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-matterjs +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-matterjs/package.json b/packages/g-plugin-matterjs/package.json index 126e36046..4297bbae0 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.9.5", + "version": "1.9.6", "description": "A G plugin for matter.js physics engine", "keywords": [ "antv", diff --git a/packages/g-plugin-mobile-interaction/CHANGELOG.md b/packages/g-plugin-mobile-interaction/CHANGELOG.md index be783bbc1..3efa47259 100644 --- a/packages/g-plugin-mobile-interaction/CHANGELOG.md +++ b/packages/g-plugin-mobile-interaction/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-mobile-interaction +## 0.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 0.9.5 ### Patch Changes diff --git a/packages/g-plugin-mobile-interaction/package.json b/packages/g-plugin-mobile-interaction/package.json index 84a2a553a..579356111 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.9.5", + "version": "0.9.6", "description": "A G plugin listening events in mobile environment", "keywords": [ "antv", diff --git a/packages/g-plugin-physx/CHANGELOG.md b/packages/g-plugin-physx/CHANGELOG.md index a3282e317..152d5f845 100644 --- a/packages/g-plugin-physx/CHANGELOG.md +++ b/packages/g-plugin-physx/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-physx +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-physx/package.json b/packages/g-plugin-physx/package.json index b5359a343..e89851911 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.9.5", + "version": "1.9.6", "description": "A G plugin for PhysX", "keywords": [ "antv", diff --git a/packages/g-plugin-rough-canvas-renderer/CHANGELOG.md b/packages/g-plugin-rough-canvas-renderer/CHANGELOG.md index 4310fa47a..53d2532ae 100644 --- a/packages/g-plugin-rough-canvas-renderer/CHANGELOG.md +++ b/packages/g-plugin-rough-canvas-renderer/CHANGELOG.md @@ -1,5 +1,17 @@ # @antv/g-plugin-rough-canvas-renderer +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-canvas@1.11.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-rough-canvas-renderer/package.json b/packages/g-plugin-rough-canvas-renderer/package.json index d30128574..c3dee947f 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.9.5", + "version": "1.9.6", "description": "A G plugin of renderer implementation with rough.js", "keywords": [ "antv", diff --git a/packages/g-plugin-rough-svg-renderer/CHANGELOG.md b/packages/g-plugin-rough-svg-renderer/CHANGELOG.md index 0e57bb81b..a258a5c66 100644 --- a/packages/g-plugin-rough-svg-renderer/CHANGELOG.md +++ b/packages/g-plugin-rough-svg-renderer/CHANGELOG.md @@ -1,5 +1,17 @@ # @antv/g-plugin-rough-svg-renderer +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-svg@1.10.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-rough-svg-renderer/package.json b/packages/g-plugin-rough-svg-renderer/package.json index 9e3823e3c..87a1e4799 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.9.5", + "version": "1.9.6", "description": "A G plugin of renderer implementation with rough.js", "keywords": [ "antv", diff --git a/packages/g-plugin-svg-picker/CHANGELOG.md b/packages/g-plugin-svg-picker/CHANGELOG.md index 8a03155c8..1a2ed1e4d 100644 --- a/packages/g-plugin-svg-picker/CHANGELOG.md +++ b/packages/g-plugin-svg-picker/CHANGELOG.md @@ -1,5 +1,17 @@ # @antv/g-plugin-svg-picker +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-plugin-svg-renderer@1.10.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-svg-picker/package.json b/packages/g-plugin-svg-picker/package.json index 9515385a5..8dc28077b 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.9.5", + "version": "1.9.6", "description": "A G plugin for picking in SVG", "keywords": [ "antv", diff --git a/packages/g-plugin-svg-renderer/CHANGELOG.md b/packages/g-plugin-svg-renderer/CHANGELOG.md index a7629ab58..bcc824271 100644 --- a/packages/g-plugin-svg-renderer/CHANGELOG.md +++ b/packages/g-plugin-svg-renderer/CHANGELOG.md @@ -1,5 +1,19 @@ # @antv/g-plugin-svg-renderer +## 1.10.6 + +### Patch Changes + +- 1b0901ba: Make textBaseline in SVG the same with Canvas. +- 1b0901ba: Add a fixed offset for Text. +- 1b0901ba: ConvertToPath should be compatible with empty coords. +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.10.5 ### Patch Changes diff --git a/packages/g-plugin-svg-renderer/package.json b/packages/g-plugin-svg-renderer/package.json index 4d9a9c113..05ba0d507 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.10.5", + "version": "1.10.6", "description": "A G plugin of renderer implementation with SVG", "keywords": [ "antv", diff --git a/packages/g-plugin-svg-renderer/src/shapes/paths/Text.ts b/packages/g-plugin-svg-renderer/src/shapes/paths/Text.ts index 179d03db9..951ea869f 100644 --- a/packages/g-plugin-svg-renderer/src/shapes/paths/Text.ts +++ b/packages/g-plugin-svg-renderer/src/shapes/paths/Text.ts @@ -63,8 +63,11 @@ export function updateTextElementAttribute( // Since `text-after-edge` is not a standard property value, we use `dy` instead. if (textBaseline === 'bottom' || textBaseline === 'top') { - $el.setAttribute('dominant-baseline', 'middle'); - $el.setAttribute('dy', textBaseline === 'bottom' ? `-0.5em` : '0.5em'); + $el.setAttribute('dominant-baseline', BASELINE_MAP['middle']); + $el.setAttribute( + 'dy', + textBaseline === 'bottom' ? `-${height / 2}px` : `${height / 2}px`, + ); } // only support one line diff --git a/packages/g-plugin-webgl-device/CHANGELOG.md b/packages/g-plugin-webgl-device/CHANGELOG.md index 3a73c4825..e208fb7de 100644 --- a/packages/g-plugin-webgl-device/CHANGELOG.md +++ b/packages/g-plugin-webgl-device/CHANGELOG.md @@ -1,5 +1,19 @@ # @antv/g-plugin-webgl-device +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-plugin-device-renderer@1.9.6 + - @antv/g-lite@1.2.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-webgl-device/package.json b/packages/g-plugin-webgl-device/package.json index 1cf51da27..03aaf0b15 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.9.5", + "version": "1.9.6", "description": "A G plugin implements GPUDevice interface with WebGL API", "keywords": [ "antv", diff --git a/packages/g-plugin-webgpu-device/CHANGELOG.md b/packages/g-plugin-webgpu-device/CHANGELOG.md index f6fb9e5ef..30125a125 100644 --- a/packages/g-plugin-webgpu-device/CHANGELOG.md +++ b/packages/g-plugin-webgpu-device/CHANGELOG.md @@ -1,5 +1,19 @@ # @antv/g-plugin-webgpu-device +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-plugin-device-renderer@1.9.6 + - @antv/g-lite@1.2.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-webgpu-device/package.json b/packages/g-plugin-webgpu-device/package.json index 0dc35d88a..cb22fe0ea 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.9.5", + "version": "1.9.6", "description": "A G plugin implements GPUDevice interface with WebGPU API", "keywords": [ "antv", diff --git a/packages/g-plugin-yoga/CHANGELOG.md b/packages/g-plugin-yoga/CHANGELOG.md index b34ed58f2..7ae4433c9 100644 --- a/packages/g-plugin-yoga/CHANGELOG.md +++ b/packages/g-plugin-yoga/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-plugin-yoga +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-plugin-yoga/package.json b/packages/g-plugin-yoga/package.json index 3a796bbc6..6c28d2f97 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.9.5", + "version": "1.9.6", "description": "A G plugin for Yoga layout engine", "keywords": [ "antv", diff --git a/packages/g-plugin-zdog-canvas-renderer/CHANGELOG.md b/packages/g-plugin-zdog-canvas-renderer/CHANGELOG.md index cd230f72e..43e6fb720 100644 --- a/packages/g-plugin-zdog-canvas-renderer/CHANGELOG.md +++ b/packages/g-plugin-zdog-canvas-renderer/CHANGELOG.md @@ -1,5 +1,17 @@ # @antv/g-plugin-zdog-canvas-renderer +## 1.2.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-canvas@1.11.6 + ## 1.2.5 ### Patch Changes diff --git a/packages/g-plugin-zdog-canvas-renderer/package.json b/packages/g-plugin-zdog-canvas-renderer/package.json index a53007e8f..de2b75bec 100644 --- a/packages/g-plugin-zdog-canvas-renderer/package.json +++ b/packages/g-plugin-zdog-canvas-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-zdog-canvas-renderer", - "version": "1.2.5", + "version": "1.2.6", "description": "A G plugin of renderer implementation with Zdog", "keywords": [ "antv", diff --git a/packages/g-plugin-zdog-svg-renderer/CHANGELOG.md b/packages/g-plugin-zdog-svg-renderer/CHANGELOG.md index 71c7182fb..03efde7ce 100644 --- a/packages/g-plugin-zdog-svg-renderer/CHANGELOG.md +++ b/packages/g-plugin-zdog-svg-renderer/CHANGELOG.md @@ -1,5 +1,18 @@ # @antv/g-plugin-zdog-svg-renderer +## 1.2.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-plugin-svg-renderer@1.10.6 + - @antv/g-svg@1.10.6 + ## 1.2.5 ### Patch Changes diff --git a/packages/g-plugin-zdog-svg-renderer/package.json b/packages/g-plugin-zdog-svg-renderer/package.json index 8dd3b0f76..095f608bd 100644 --- a/packages/g-plugin-zdog-svg-renderer/package.json +++ b/packages/g-plugin-zdog-svg-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-plugin-zdog-svg-renderer", - "version": "1.2.5", + "version": "1.2.6", "description": "A G plugin of renderer implementation with Zdog", "keywords": [ "antv", diff --git a/packages/g-shader-components/CHANGELOG.md b/packages/g-shader-components/CHANGELOG.md index ecc63ffa2..dcf13adde 100644 --- a/packages/g-shader-components/CHANGELOG.md +++ b/packages/g-shader-components/CHANGELOG.md @@ -1,5 +1,14 @@ # @antv/g-shader-components +## 1.8.2 + +### Patch Changes + +- 1b0901ba: Make FillMesh instanced to enhance perf. +- 1b0901ba: Make textBaseline in SVG the same with Canvas. +- 1b0901ba: Add a fixed offset for Text. +- 1b0901ba: ConvertToPath should be compatible with empty coords. + ## 1.8.1 ### Patch Changes diff --git a/packages/g-shader-components/mesh.both.glsl b/packages/g-shader-components/mesh.both.glsl deleted file mode 100644 index 4a04c6bb7..000000000 --- a/packages/g-shader-components/mesh.both.glsl +++ /dev/null @@ -1,9 +0,0 @@ -layout(std140) uniform ub_ObjectParams { - mat4 u_ModelMatrix; - vec4 u_FillColor; - vec3 u_PickingColor; - float u_Opacity; - float u_FillOpacity; - float u_Visible; - float u_ZIndex; -}; \ No newline at end of file diff --git a/packages/g-shader-components/package.json b/packages/g-shader-components/package.json index bee1a202c..d80bdbe6c 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.8.1", + "version": "1.8.2", "description": "Shader components based on glslify", "keywords": [ "antv", diff --git a/packages/g-svg/CHANGELOG.md b/packages/g-svg/CHANGELOG.md index a8701c4ac..0c19c32d0 100644 --- a/packages/g-svg/CHANGELOG.md +++ b/packages/g-svg/CHANGELOG.md @@ -1,5 +1,19 @@ # @antv/g-svg +## 1.10.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-plugin-svg-renderer@1.10.6 + - @antv/g-plugin-dom-interaction@1.9.6 + - @antv/g-plugin-svg-picker@1.9.6 + ## 1.10.5 ### Patch Changes diff --git a/packages/g-svg/package.json b/packages/g-svg/package.json index a146b5ed3..3730e59d0 100644 --- a/packages/g-svg/package.json +++ b/packages/g-svg/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-svg", - "version": "1.10.5", + "version": "1.10.6", "description": "A renderer implemented by SVG", "keywords": [ "antv", diff --git a/packages/g-web-animations-api/CHANGELOG.md b/packages/g-web-animations-api/CHANGELOG.md index ff03695a6..9e32f61cd 100644 --- a/packages/g-web-animations-api/CHANGELOG.md +++ b/packages/g-web-animations-api/CHANGELOG.md @@ -1,5 +1,16 @@ # @antv/g-web-animations-api +## 1.2.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + ## 1.2.5 ### Patch Changes diff --git a/packages/g-web-animations-api/package.json b/packages/g-web-animations-api/package.json index 55a95dff3..232f8c33e 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.2.5", + "version": "1.2.6", "description": "A simple implementation of Web Animations API.", "keywords": [ "antv", diff --git a/packages/g-web-components/CHANGELOG.md b/packages/g-web-components/CHANGELOG.md index 01b75b29b..4fb9291ff 100644 --- a/packages/g-web-components/CHANGELOG.md +++ b/packages/g-web-components/CHANGELOG.md @@ -1,5 +1,18 @@ # @antv/g-web-components +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-webgl@1.9.6 + - @antv/g-canvas@1.11.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-web-components/package.json b/packages/g-web-components/package.json index 546c4d81b..f065bd17e 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.9.5", + "version": "1.9.6", "description": "A declarative usage for G implemented with WebComponents", "keywords": [ "antv", diff --git a/packages/g-webgl/CHANGELOG.md b/packages/g-webgl/CHANGELOG.md index e5ba8c703..fd0e4d3e9 100644 --- a/packages/g-webgl/CHANGELOG.md +++ b/packages/g-webgl/CHANGELOG.md @@ -1,5 +1,23 @@ # @antv/g-webgl +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-plugin-device-renderer@1.9.6 + - @antv/g-lite@1.2.6 + - @antv/g-plugin-webgl-device@1.9.6 + - @antv/g-plugin-dom-interaction@1.9.6 + - @antv/g-plugin-html-renderer@1.9.6 + - @antv/g-plugin-image-loader@1.3.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-webgl/package.json b/packages/g-webgl/package.json index e7e5d1fd2..d22091611 100644 --- a/packages/g-webgl/package.json +++ b/packages/g-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-webgl", - "version": "1.9.5", + "version": "1.9.6", "description": "A renderer implemented by WebGL1/2", "keywords": [ "antv", diff --git a/packages/g-webgpu/CHANGELOG.md b/packages/g-webgpu/CHANGELOG.md index 0e635ba8c..56eca83c2 100644 --- a/packages/g-webgpu/CHANGELOG.md +++ b/packages/g-webgpu/CHANGELOG.md @@ -1,5 +1,23 @@ # @antv/g-webgpu +## 1.9.6 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-plugin-device-renderer@1.9.6 + - @antv/g-lite@1.2.6 + - @antv/g-plugin-webgpu-device@1.9.6 + - @antv/g-plugin-dom-interaction@1.9.6 + - @antv/g-plugin-html-renderer@1.9.6 + - @antv/g-plugin-image-loader@1.3.6 + ## 1.9.5 ### Patch Changes diff --git a/packages/g-webgpu/package.json b/packages/g-webgpu/package.json index 47848378e..906f121c6 100644 --- a/packages/g-webgpu/package.json +++ b/packages/g-webgpu/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g-webgpu", - "version": "1.9.5", + "version": "1.9.6", "description": "A renderer implemented by WebGPU", "keywords": [ "antv", diff --git a/packages/g/CHANGELOG.md b/packages/g/CHANGELOG.md index 2f711c3b0..d5a519998 100644 --- a/packages/g/CHANGELOG.md +++ b/packages/g/CHANGELOG.md @@ -1,5 +1,19 @@ # @antv/g +## 5.18.7 + +### Patch Changes + +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] +- Updated dependencies [1b0901ba] + - @antv/g-lite@1.2.6 + - @antv/g-camera-api@1.2.6 + - @antv/g-dom-mutation-observer-api@1.2.6 + - @antv/g-web-animations-api@1.2.6 + ## 5.18.6 ### Patch Changes diff --git a/packages/g/package.json b/packages/g/package.json index 088aae740..e75c6219a 100644 --- a/packages/g/package.json +++ b/packages/g/package.json @@ -1,6 +1,6 @@ { "name": "@antv/g", - "version": "5.18.6", + "version": "5.18.7", "description": "A core module for rendering engine implements DOM API.", "keywords": [ "antv", diff --git a/packages/react-g/CHANGELOG.md b/packages/react-g/CHANGELOG.md index cbea82bd7..5b8f86f56 100644 --- a/packages/react-g/CHANGELOG.md +++ b/packages/react-g/CHANGELOG.md @@ -1,5 +1,11 @@ # @antv/react-g +## 1.10.7 + +### Patch Changes + +- @antv/g@5.18.7 + ## 1.10.6 ### Patch Changes diff --git a/packages/react-g/package.json b/packages/react-g/package.json index b415716b2..147c6aa48 100644 --- a/packages/react-g/package.json +++ b/packages/react-g/package.json @@ -1,6 +1,6 @@ { "name": "@antv/react-g", - "version": "1.10.6", + "version": "1.10.7", "description": "react render for @antv/g", "keywords": [ "react", diff --git a/site/examples/perf/animation/demo/meta.json b/site/examples/perf/animation/demo/meta.json index 8b75d97cc..51ce7cae1 100644 --- a/site/examples/perf/animation/demo/meta.json +++ b/site/examples/perf/animation/demo/meta.json @@ -27,6 +27,20 @@ "zh": "移动大量节点", "en": "Move nodes" } + }, + { + "filename": "webgl-text.js", + "title": { + "zh": "在 WebGL 中更新 Text 的位置", + "en": "Update position of Text in WebGL" + } + }, + { + "filename": "webgl-opacity.js", + "title": { + "zh": "在 WebGL 中更新 Opacity", + "en": "Update opacity of shapes in WebGL" + } } ] } diff --git a/site/examples/perf/animation/demo/webgl-opacity.js b/site/examples/perf/animation/demo/webgl-opacity.js new file mode 100644 index 000000000..48f930648 --- /dev/null +++ b/site/examples/perf/animation/demo/webgl-opacity.js @@ -0,0 +1,58 @@ +import { Canvas, CanvasEvent, Rect, runtime } from '@antv/g'; +import { Renderer } from '@antv/g-webgl'; +import Stats from 'stats.js'; + +runtime.enableCSSParsing = false; + +const canvas = new Canvas({ + container: 'container', + width: 600, + height: 500, + renderer: new Renderer(), +}); + +canvas.addEventListener(CanvasEvent.READY, () => { + const rect1 = new Rect({ + style: { + x: 200, + y: 200, + width: 200, + height: 200, + fill: 'blue', + }, + }); + + const rect2 = new Rect({ + style: { + x: 250, + y: 250, + width: 100, + height: 100, + fill: 'red', + }, + }); + + canvas.appendChild(rect1); + canvas.appendChild(rect2); + + rect2.animate([{ opacity: 0 }, { opacity: 1 }], { + duration: 2000, + fill: 'both', + iterations: Infinity, + }); +}); + +// 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(); + } +}); diff --git a/site/examples/perf/animation/demo/webgl-text.js b/site/examples/perf/animation/demo/webgl-text.js index e7e29add1..122cd073c 100644 --- a/site/examples/perf/animation/demo/webgl-text.js +++ b/site/examples/perf/animation/demo/webgl-text.js @@ -11,128 +11,31 @@ const canvas = new Canvas({ renderer: new Renderer(), }); -const text1 = new Text({ - style: { - x: 100, - y: 100, - fill: 'black', - text: 'Text1', - }, -}); - -const text2 = new Text({ - style: { - x: 200, - y: 100, - fill: 'black', - text: 'Text2', - }, -}); - -const text3 = new Text({ - style: { - x: 300, - y: 100, - fill: 'black', - text: 'Text3', - }, -}); - -const text4 = new Text({ - style: { - x: 200, - y: 200, - fill: 'black', - text: 'Text3', - }, -}); - -const text5 = new Text({ - style: { - x: 300, - y: 200, - fill: 'black', - text: 'Text3', - }, -}); - canvas.addEventListener(CanvasEvent.READY, () => { - canvas.appendChild(text1); - text1.animate( - [ - { - opacity: 0, - transform: 'translate(0, 0)', + for (let i = 0; i < 1000; i++) { + const text = new Text({ + style: { + x: Math.random() * 600, + y: Math.random() * 500, + fontSize: 16, + fill: 'black', + text: `Text1${i}`, }, + }); + canvas.appendChild(text); + + text.animate( + [ + { opacity: 0, transform: 'translate(0, 0)' }, + { opacity: 1, transform: 'translate(100, 0)' }, + ], { - opacity: 1, - transform: 'translate(100, 0)', + duration: 2000, + fill: 'both', + iterations: Infinity, }, - ], - { - duration: 2000, - fill: 'both', - iterations: Infinity, - }, - ); - - canvas.appendChild(text2); - text2.animate( - [ - { opacity: 0, transform: 'translate(0, 0)' }, - { opacity: 1, transform: 'translate(100, 0)' }, - ], - { - duration: 2000, - fill: 'both', - iterations: Infinity, - }, - ); - - canvas.appendChild(text3); - text3.animate( - [ - { opacity: 0, transform: 'translate(0, 0)' }, - { opacity: 1, transform: 'translate(100, 0)' }, - ], - { - duration: 2000, - fill: 'both', - iterations: Infinity, - }, - ); - - canvas.appendChild(text4); - text4.animate( - [ - { opacity: 0, transform: 'translate(0, 0)' }, - { opacity: 1, transform: 'translate(100, 0)' }, - ], - { - duration: 2000, - fill: 'both', - iterations: Infinity, - }, - ); - - canvas.appendChild(text5); - text5.animate( - [ - { opacity: 0, transform: 'translate(0, 0)' }, - { opacity: 1, transform: 'translate(100, 0)' }, - ], - { - duration: 2000, - fill: 'both', - iterations: Infinity, - }, - ); - - text1.style.fontSize = 32; - text2.style.fontSize = 32; - text3.style.fontSize = 32; - text4.style.fontSize = 32; - text5.style.fontSize = 32; + ); + } }); // stats diff --git a/site/examples/perf/webgl/demo/circle-linedash.js b/site/examples/perf/webgl/demo/circle-linedash.js new file mode 100644 index 000000000..49c1ba69e --- /dev/null +++ b/site/examples/perf/webgl/demo/circle-linedash.js @@ -0,0 +1,99 @@ +import { Canvas, CanvasEvent, Circle } from '@antv/g'; +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 webglRenderer = new WebGLRenderer(); +const webgpuRenderer = new WebGPURenderer({ + shaderCompilerPath: '/glsl_wgsl_compiler_bg.wasm', +}); + +// create a canvas +const canvas = new Canvas({ + container: 'container', + width: 600, + height: 500, + renderer: webglRenderer, +}); + +canvas.addEventListener(CanvasEvent.READY, () => { + for (let i = 0; i < 5000; i++) { + const circle = new Circle({ + style: { + cx: Math.random() * 600, + cy: Math.random() * 500, + r: Math.random() * 100, + stroke: '#5B8FF9', + lineWidth: 1, + lineDash: i % 2 === 0 ? [10, 10] : [0], + fill: 'red', + fillOpacity: 0.5, + }, + }); + canvas.appendChild(circle); + } +}); + +// 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); + +const camera = canvas.getCamera(); +canvas.addEventListener(CanvasEvent.AFTER_RENDER, () => { + if (stats) { + stats.update(); + } + + // manipulate camera instead of the root of canvas + camera.rotate(0, 0, 1); +}); + +// update Camera's zoom +// @see https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/OrbitControls.js +const minZoom = 0; +const maxZoom = Infinity; +canvas + .getContextService() + .getDomElement() // g-canvas/webgl 为 ,g-svg 为 + .addEventListener( + 'wheel', + (e) => { + e.preventDefault(); + let zoom; + if (e.deltaY < 0) { + zoom = Math.max(minZoom, Math.min(maxZoom, camera.getZoom() / 0.95)); + } else { + zoom = Math.max(minZoom, Math.min(maxZoom, camera.getZoom() * 0.95)); + } + camera.setZoom(zoom); + }, + { passive: false }, + ); + +// GUI +const gui = new lil.GUI({ autoPlace: false }); +$wrapper.appendChild(gui.domElement); +const rendererFolder = gui.addFolder('renderer'); +const rendererConfig = { + renderer: 'webgl', +}; +rendererFolder + .add(rendererConfig, 'renderer', ['webgl', 'webgpu']) + .onChange((rendererName) => { + let renderer; + if (rendererName === 'webgl') { + renderer = webglRenderer; + } else if (rendererName === 'webgpu') { + renderer = webgpuRenderer; + } + canvas.setRenderer(renderer); + }); +rendererFolder.open(); diff --git a/site/examples/perf/webgl/demo/meta.json b/site/examples/perf/webgl/demo/meta.json index 4956ab2d5..ab83dc796 100644 --- a/site/examples/perf/webgl/demo/meta.json +++ b/site/examples/perf/webgl/demo/meta.json @@ -1,5 +1,13 @@ { "demos": [ + { + "filename": "circle-linedash.js", + "title": { + "zh": "虚线描边的 Circle", + "en": "LineDashed Circle" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*mu59SqFdEtUAAAAAAAAAAAAADmJ7AQ/original" + }, { "filename": "texts.js", "title": { @@ -24,6 +32,22 @@ }, "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*sQH_T5LdKdcAAAAAAAAAAAAADmJ7AQ/original" }, + { + "filename": "polygons.js", + "title": { + "zh": "大量多边形", + "en": "Instanced Polygons" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*Gmd-SZ3GwIkAAAAAAAAAAAAADmJ7AQ/original" + }, + { + "filename": "polylines.js", + "title": { + "zh": "大量折线", + "en": "Instanced Polylines" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*MQr5SYtG5OsAAAAAAAAAAAAADmJ7AQ/original" + }, { "filename": "images.js", "title": { diff --git a/site/examples/perf/webgl/demo/polygons.js b/site/examples/perf/webgl/demo/polygons.js new file mode 100644 index 000000000..df127bb6e --- /dev/null +++ b/site/examples/perf/webgl/demo/polygons.js @@ -0,0 +1,118 @@ +import { Canvas, CanvasEvent, Polygon } from '@antv/g'; +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 webglRenderer = new WebGLRenderer(); +const webgpuRenderer = new WebGPURenderer({ + shaderCompilerPath: '/glsl_wgsl_compiler_bg.wasm', +}); + +// create a canvas +const canvas = new Canvas({ + container: 'container', + width: 600, + height: 500, + renderer: webglRenderer, +}); + +canvas.addEventListener(CanvasEvent.READY, () => { + for (let i = 0; i < 5000; i++) { + const polygon = new Polygon({ + style: { + points: + i % 2 === 0 + ? [ + [200, 100], + [400, 100], + [ + 400 + 200 * Math.sin(Math.PI / 6), + 100 + 200 * Math.cos(Math.PI / 6), + ], + [400, 100 + 200 * Math.cos(Math.PI / 6) * 2], + [200, 100 + 200 * Math.cos(Math.PI / 6) * 2], + [ + 200 - 200 * Math.sin(Math.PI / 6), + 100 + 200 * Math.cos(Math.PI / 6), + ], + ] + : [ + [200, 100], + [400, 100], + [400, 300], + ], + fill: '#C6E5FF', + stroke: '#5B8FF9', + lineWidth: 1, + transform: `translate(${Math.random() * 600}, ${ + Math.random() * 500 + }) scale(${Math.random()})`, + }, + }); + canvas.appendChild(polygon); + } +}); + +// 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); + +const camera = canvas.getCamera(); +canvas.addEventListener(CanvasEvent.AFTER_RENDER, () => { + if (stats) { + stats.update(); + } + + // manipulate camera instead of the root of canvas + camera.rotate(0, 0, 1); +}); + +// update Camera's zoom +// @see https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/OrbitControls.js +const minZoom = 0; +const maxZoom = Infinity; +canvas + .getContextService() + .getDomElement() // g-canvas/webgl 为 ,g-svg 为 + .addEventListener( + 'wheel', + (e) => { + e.preventDefault(); + let zoom; + if (e.deltaY < 0) { + zoom = Math.max(minZoom, Math.min(maxZoom, camera.getZoom() / 0.95)); + } else { + zoom = Math.max(minZoom, Math.min(maxZoom, camera.getZoom() * 0.95)); + } + camera.setZoom(zoom); + }, + { passive: false }, + ); + +// GUI +const gui = new lil.GUI({ autoPlace: false }); +$wrapper.appendChild(gui.domElement); +const rendererFolder = gui.addFolder('renderer'); +const rendererConfig = { + renderer: 'webgl', +}; +rendererFolder + .add(rendererConfig, 'renderer', ['webgl', 'webgpu']) + .onChange((rendererName) => { + let renderer; + if (rendererName === 'webgl') { + renderer = webglRenderer; + } else if (rendererName === 'webgpu') { + renderer = webgpuRenderer; + } + canvas.setRenderer(renderer); + }); +rendererFolder.open(); diff --git a/site/examples/perf/webgl/demo/polylines.js b/site/examples/perf/webgl/demo/polylines.js new file mode 100644 index 000000000..89fe40fba --- /dev/null +++ b/site/examples/perf/webgl/demo/polylines.js @@ -0,0 +1,117 @@ +import { Canvas, CanvasEvent, Polyline } from '@antv/g'; +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 webglRenderer = new WebGLRenderer(); +const webgpuRenderer = new WebGPURenderer({ + shaderCompilerPath: '/glsl_wgsl_compiler_bg.wasm', +}); + +// create a canvas +const canvas = new Canvas({ + container: 'container', + width: 600, + height: 500, + renderer: webglRenderer, +}); + +canvas.addEventListener(CanvasEvent.READY, () => { + for (let i = 0; i < 5000; i++) { + const polyline = new Polyline({ + style: { + points: + i % 2 === 0 + ? [ + [200, 100], + [400, 100], + [ + 400 + 200 * Math.sin(Math.PI / 6), + 100 + 200 * Math.cos(Math.PI / 6), + ], + [400, 100 + 200 * Math.cos(Math.PI / 6) * 2], + [200, 100 + 200 * Math.cos(Math.PI / 6) * 2], + [ + 200 - 200 * Math.sin(Math.PI / 6), + 100 + 200 * Math.cos(Math.PI / 6), + ], + ] + : [ + [200, 100], + [400, 100], + [400, 300], + ], + stroke: '#5B8FF9', + lineWidth: 4, + transform: `translate(${Math.random() * 600}, ${ + Math.random() * 500 + }) scale(${Math.random()})`, + }, + }); + canvas.appendChild(polyline); + } +}); + +// 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); + +const camera = canvas.getCamera(); +canvas.addEventListener(CanvasEvent.AFTER_RENDER, () => { + if (stats) { + stats.update(); + } + + // manipulate camera instead of the root of canvas + camera.rotate(0, 0, 1); +}); + +// update Camera's zoom +// @see https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/OrbitControls.js +const minZoom = 0; +const maxZoom = Infinity; +canvas + .getContextService() + .getDomElement() // g-canvas/webgl 为 ,g-svg 为 + .addEventListener( + 'wheel', + (e) => { + e.preventDefault(); + let zoom; + if (e.deltaY < 0) { + zoom = Math.max(minZoom, Math.min(maxZoom, camera.getZoom() / 0.95)); + } else { + zoom = Math.max(minZoom, Math.min(maxZoom, camera.getZoom() * 0.95)); + } + camera.setZoom(zoom); + }, + { passive: false }, + ); + +// GUI +const gui = new lil.GUI({ autoPlace: false }); +$wrapper.appendChild(gui.domElement); +const rendererFolder = gui.addFolder('renderer'); +const rendererConfig = { + renderer: 'webgl', +}; +rendererFolder + .add(rendererConfig, 'renderer', ['webgl', 'webgpu']) + .onChange((rendererName) => { + let renderer; + if (rendererName === 'webgl') { + renderer = webglRenderer; + } else if (rendererName === 'webgpu') { + renderer = webgpuRenderer; + } + canvas.setRenderer(renderer); + }); +rendererFolder.open(); diff --git a/site/examples/perf/webgl/demo/rounded-rects.js b/site/examples/perf/webgl/demo/rounded-rects.js index c1afd924d..14781d4b6 100644 --- a/site/examples/perf/webgl/demo/rounded-rects.js +++ b/site/examples/perf/webgl/demo/rounded-rects.js @@ -19,12 +19,12 @@ const canvas = new Canvas({ }); canvas.addEventListener(CanvasEvent.READY, () => { - for (let i = 0; i < 5; i++) { + for (let i = 0; i < 5000; i++) { const rect = new Rect({ style: { x: Math.random() * 600, y: Math.random() * 500, - width: 200, + width: i % 2 === 0 ? 200 : 100, height: 100, fill: '#C6E5FF', stroke: '#5B8FF9', diff --git a/site/examples/shape/line/demo/meta.json b/site/examples/shape/line/demo/meta.json index 037524f8b..eda802c5f 100644 --- a/site/examples/shape/line/demo/meta.json +++ b/site/examples/shape/line/demo/meta.json @@ -19,6 +19,14 @@ "en": "Marker" }, "screenshot": "https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*X5W_TYz-2SIAAAAAAAAAAAAAARQnAQ" + }, + { + "filename": "thin-line.js", + "title": { + "zh": "绘制宽度小于 1px 的线", + "en": "Thin Line" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*FNTzSp46rwgAAAAAAAAAAAAADmJ7AQ/original" } ] } diff --git a/site/examples/shape/line/demo/thin-line.js b/site/examples/shape/line/demo/thin-line.js new file mode 100644 index 000000000..fb82685a6 --- /dev/null +++ b/site/examples/shape/line/demo/thin-line.js @@ -0,0 +1,124 @@ +import { Canvas, CanvasEvent, Line, Path } from '@antv/g'; +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: 'Roboto', + url: '/Roboto-Regular.ttf', + }, + { + name: 'sans-serif', + url: 'https://mdn.alipayobjects.com/huamei_qa8qxu/afts/file/A*064aSK2LUPEAAAAAAAAAAAAADmJ7AQ/NotoSansCJKsc-VF.ttf', + }, + ], +}); +const webgpuRenderer = new WebGPURenderer({ + shaderCompilerPath: '/glsl_wgsl_compiler_bg.wasm', +}); + +// create a canvas +const canvas = new Canvas({ + container: 'container', + width: 600, + height: 500, + renderer: canvasRenderer, +}); + +// create a line +const line1 = new Line({ + style: { + x1: 200, + y1: 100, + x2: 400, + y2: 100, + stroke: '#1890FF', + lineWidth: 0.1, + cursor: 'pointer', + }, +}); +const line2 = line1.cloneNode(); +const line3 = line1.cloneNode(); +const line4 = line1.cloneNode(); +line2.style.lineWidth = 0.5; +line3.style.lineWidth = 1; +line4.style.lineWidth = 2; +line2.translate(0, 50); +line3.translate(0, 100); +line4.translate(0, 150); + +const path = new Path({ + style: { + lineWidth: 0.5, + stroke: '#54BECC', + d: 'M 0,40 C 5.5555555555555545,40,22.222222222222218,44.44444444444445,33.33333333333333,40 C 44.444444444444436,35.55555555555556,55.55555555555554,14.66666666666667,66.66666666666666,13.333333333333336 C 77.77777777777777,12.000000000000002,88.88888888888887,32,100,32 C 111.11111111111113,32,122.22222222222221,14.66666666666667,133.33333333333331,13.333333333333336 C 144.44444444444443,12.000000000000002,155.55555555555557,24,166.66666666666669,24 C 177.7777777777778,24,188.8888888888889,11.111111111111114,200,13.333333333333336 C 211.1111111111111,15.555555555555557,222.22222222222226,35.111111111111114,233.33333333333334,37.333333333333336 C 244.44444444444443,39.55555555555555,255.55555555555551,31.22222222222223,266.66666666666663,26.66666666666667 C 277.77777777777777,22.111111111111114,294.4444444444444,12.777777777777779,300,10', + transform: 'translate(100, 100)', + }, +}); + +canvas.addEventListener(CanvasEvent.READY, () => { + canvas.appendChild(line1); + canvas.appendChild(line2); + canvas.appendChild(line3); + canvas.appendChild(line4); + canvas.appendChild(path); +}); + +// 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/shape/text/demo/meta.json b/site/examples/shape/text/demo/meta.json index 65eb4bcc2..4eed97f41 100644 --- a/site/examples/shape/text/demo/meta.json +++ b/site/examples/shape/text/demo/meta.json @@ -28,6 +28,13 @@ }, "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*VAQWQbMdQkQAAAAAAAAAAAAADmJ7AQ/original" }, + { + "filename": "text-billboard.js", + "title": { + "zh": "文本公告牌效果", + "en": "Text Billboard" + } + }, { "filename": "web-font-loader.js", "title": { diff --git a/site/examples/shape/text/demo/text-baseline.js b/site/examples/shape/text/demo/text-baseline.js index ad0542778..8bd9f88e1 100644 --- a/site/examples/shape/text/demo/text-baseline.js +++ b/site/examples/shape/text/demo/text-baseline.js @@ -40,12 +40,12 @@ const text1 = new Text({ x: 10, y: 300, fontFamily: 'PingFang SC', - text: 'gah', + text: 'gah国', textBaseline: 'alphabetic', - fontSize: 50, + fontSize: 24, fill: '#1890FF', - stroke: '#F04864', - lineWidth: 5, + // stroke: '#F04864', + // lineWidth: 5, }, }); const html1 = new HTML({ @@ -136,20 +136,20 @@ const bounds4 = new Rect({ }); canvas.addEventListener(CanvasEvent.READY, () => { - canvas.appendChild(text1); canvas.appendChild(bounds1); + canvas.appendChild(text1); canvas.appendChild(html1); - canvas.appendChild(text2); canvas.appendChild(bounds2); + canvas.appendChild(text2); canvas.appendChild(html2); - canvas.appendChild(text3); canvas.appendChild(bounds3); + canvas.appendChild(text3); canvas.appendChild(html3); - canvas.appendChild(text4); canvas.appendChild(bounds4); + canvas.appendChild(text4); canvas.appendChild(html4); canvas.appendChild(line); @@ -231,3 +231,13 @@ rendererFolder canvas.setRenderer(renderer); }); rendererFolder.open(); + +const textFolder = gui.addFolder('text'); +const textConfig = { + fontSize: 24, +}; +textFolder.add(textConfig, 'fontSize', 10, 100).onChange((fontSize) => { + [text1, text2, text3, text4].forEach((text) => { + text.attr('fontSize', fontSize); + }); +}); diff --git a/site/examples/shape/text/demo/text-billboard.js b/site/examples/shape/text/demo/text-billboard.js new file mode 100644 index 000000000..5b3b085ca --- /dev/null +++ b/site/examples/shape/text/demo/text-billboard.js @@ -0,0 +1,241 @@ +import { runtime, Canvas, CanvasEvent, Rect, Text, Line, HTML } from '@antv/g'; +import { Renderer as WebGLRenderer } from '@antv/g-webgl'; +import { Plugin } from '@antv/g-plugin-control'; +import * as lil from 'lil-gui'; +import Stats from 'stats.js'; + +runtime.enableCSSParsing = false; + +// create a renderer +const webglRenderer = new WebGLRenderer(); +webglRenderer.registerPlugin(new Plugin()); + +// create a canvas +const canvas = new Canvas({ + container: 'container', + width: 600, + height: 500, + renderer: webglRenderer, +}); + +// create a line of text +const text1 = new Text({ + style: { + x: 10, + y: 300, + fontFamily: 'PingFang SC', + text: 'gah', + textBaseline: 'alphabetic', + fontSize: 50, + fill: '#1890FF', + stroke: '#F04864', + lineWidth: 5, + isBillboard: true, + }, +}); +// const html1 = new HTML({ +// style: { +// x: 10, +// y: 200, +// width: 100, +// height: 30, +// innerHTML: 'alphabetic', +// }, +// }); + +const text2 = text1.cloneNode(); +text2.style.x = 110; +text2.style.textBaseline = 'top'; +// const html2 = new HTML({ +// style: { +// x: 110, +// y: 200, +// width: 100, +// height: 30, +// innerHTML: 'top', +// }, +// }); + +const text3 = text1.cloneNode(); +text3.style.x = 210; +text3.style.textBaseline = 'middle'; +// const html3 = new HTML({ +// style: { +// x: 210, +// y: 200, +// width: 100, +// height: 30, +// innerHTML: 'middle', +// }, +// }); + +const text4 = text1.cloneNode(); +text4.style.x = 310; +text4.style.textBaseline = 'bottom'; +// const html4 = new HTML({ +// style: { +// x: 310, +// y: 200, +// width: 100, +// height: 30, +// innerHTML: 'bottom', +// }, +// }); + +// baseline +const line = new Line({ + style: { + x1: 0, + y1: 300, + z1: 0, + x2: 600, + y2: 300, + z2: 0, + stroke: 'black', + strokeWidth: 2, + isBillboard: true, + }, +}); + +// display bounds +const bounds1 = new Rect({ + style: { + stroke: 'black', + lineWidth: 2, + isBillboard: true, + }, +}); +const bounds2 = new Rect({ + style: { + stroke: 'black', + lineWidth: 2, + isBillboard: true, + }, +}); +const bounds3 = new Rect({ + style: { + stroke: 'black', + lineWidth: 2, + isBillboard: true, + }, +}); +const bounds4 = new Rect({ + style: { + stroke: 'black', + lineWidth: 2, + isBillboard: true, + }, +}); + +canvas.addEventListener(CanvasEvent.READY, () => { + canvas.appendChild(text1); + canvas.appendChild(bounds1); + // canvas.appendChild(html1); + + canvas.appendChild(text2); + canvas.appendChild(bounds2); + // canvas.appendChild(html2); + + canvas.appendChild(text3); + canvas.appendChild(bounds3); + // canvas.appendChild(html3); + + canvas.appendChild(text4); + canvas.appendChild(bounds4); + // canvas.appendChild(html4); + + canvas.appendChild(line); +}); + +// 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(); + } + + const bounding1 = text1.getBounds(); + if (bounding1) { + const { center, halfExtents } = bounding1; + bounds1.attr('width', halfExtents[0] * 2); + bounds1.attr('height', halfExtents[1] * 2); + bounds1.setPosition( + center[0] - halfExtents[0], + center[1] - halfExtents[1], + 0, + ); + } + + const bounding2 = text2.getBounds(); + if (bounding2) { + const { center, halfExtents } = bounding2; + bounds2.attr('width', halfExtents[0] * 2); + bounds2.attr('height', halfExtents[1] * 2); + bounds2.setPosition( + center[0] - halfExtents[0], + center[1] - halfExtents[1], + 0, + ); + } + const bounding3 = text3.getBounds(); + if (bounding3) { + const { center, halfExtents } = bounding3; + bounds3.attr('width', halfExtents[0] * 2); + bounds3.attr('height', halfExtents[1] * 2); + bounds3.setPosition( + center[0] - halfExtents[0], + center[1] - halfExtents[1], + 0, + ); + } + const bounding4 = text4.getBounds(); + if (bounding4) { + const { center, halfExtents } = bounding4; + bounds4.attr('width', halfExtents[0] * 2); + bounds4.attr('height', halfExtents[1] * 2); + bounds4.setPosition( + center[0] - halfExtents[0], + center[1] - halfExtents[1], + 0, + ); + } +}); + +// 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();