Skip to content

Commit

Permalink
fix: path should downgrade to line and support billboard effect (#1469)
Browse files Browse the repository at this point in the history
* fix: polyfill for performance.now

* chore: commit changeset

* fix: path should downgrade to line and support billboard effect #1443

* fix: remove redundant m commands when parsing path #1447

* fix: removing redundant m command should account for prev z command

* chore: commit changeset

* chore: use get-pixels loading local image instead of fetching in ssr #1471
  • Loading branch information
xiaoiver authored Aug 11, 2023
1 parent 9f11a3a commit eb61cba
Show file tree
Hide file tree
Showing 15 changed files with 368 additions and 38 deletions.
5 changes: 5 additions & 0 deletions .changeset/early-trainers-deny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@antv/g-lite': patch
---

Add polyfill for performance.now.
6 changes: 6 additions & 0 deletions .changeset/odd-starfishes-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@antv/g-plugin-device-renderer': patch
'@antv/g-lite': patch
---

Remove redundant m command when parsing path.
37 changes: 15 additions & 22 deletions __tests__/integration/__node__tests__/webgl/image.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const fs = require('fs');
const { createCanvas, Image: CanvasImage, loadImage } = require('canvas');
const getPixels = require('get-pixels');
const { createCanvas } = require('canvas');
const { Image, Canvas, Rectangle } = require('@antv/g');
const { Renderer } = require('@antv/g-webgl');
const { createPNGFromRawdata, sleep, diff } = require('../../util');
Expand Down Expand Up @@ -43,10 +44,6 @@ const canvas = new Canvas({
canvas: mockCanvas, // use headless-gl
renderer,
offscreenCanvas: offscreenNodeCanvas,
createImage: () => {
const image = new CanvasImage();
return image;
},
});

const RESULT_IMAGE = '/image.png';
Expand All @@ -65,7 +62,19 @@ describe('Render <Image> with g-webgl', () => {
it('should render image on server-side correctly.', async () => {
await canvas.ready;

const src = await loadImage(__dirname + '/antv.png');
// Load local image instead of fetching remote URL.
// @see https://github.com/stackgl/headless-gl/pull/53/files#diff-55563b6c0b90b80aed19c83df1c51e80fd45d2fbdad6cc047ee86e98f65da3e9R83
const src = await new Promise((resolve, reject) => {
getPixels(__dirname + '/antv.png', function (err, image) {
if (err) {
reject('Bad image path');
} else {
image.width = image.shape[0];
image.height = image.shape[1];
resolve(image);
}
});
});

// URL src
const image = new Image({
Expand All @@ -77,22 +86,6 @@ describe('Render <Image> with g-webgl', () => {
});
canvas.appendChild(image);

// <canvas> src
const nodeCanvasSrc = createCanvas(50, 50);
const context = nodeCanvasSrc.getContext('2d');
context.fillStyle = 'red';
context.fillRect(0, 0, 50, 50);
const image2 = new Image({
style: {
x: 100,
y: 100,
width: 100,
height: 100,
src: nodeCanvasSrc,
},
});
canvas.appendChild(image2);

await sleep(200);

const pixels = new Uint8Array(width * height * 4);
Expand Down
Binary file modified __tests__/integration/__node__tests__/webgl/snapshots/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 55 additions & 0 deletions __tests__/unit/css/parser/path.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,59 @@ describe('Property Path', () => {

mergePaths(path1, path2);
});

it('should remove redundant M commands correctly.', () => {
let parsed = parsePath('M 0 0 M 0 0 M 0 0 L 100 100');
expect(parsed.absolutePath).toStrictEqual([
['M', 0, 0],
['L', 100, 100],
]);

parsed = parsePath('M 0 0 L 100 100 Z M 0 0 L 0 0');
expect(parsed.absolutePath).toStrictEqual([
['M', 0, 0],
['L', 100, 100],
['Z'],
['M', 0, 0],
['L', 0, 0],
]);

parsed = parsePath('M 0 0 M 0 0 M 0 0 L 100 100 M 100 100 L 200 200');
expect(parsed.absolutePath).toStrictEqual([
['M', 0, 0],
['L', 100, 100],
['L', 200, 200],
]);

parsed = parsePath('M 0 0 C 50 0 100 0 100 100 M 100 100 L 200 200');
expect(parsed.absolutePath).toStrictEqual([
['M', 0, 0],
['C', 50, 0, 100, 0, 100, 100],
['L', 200, 200],
]);

parsed = parsePath('M 0 0 Q 50 0 100 100 M 100 100 L 200 200');
expect(parsed.absolutePath).toStrictEqual([
['M', 0, 0],
['Q', 50, 0, 100, 100],
['L', 200, 200],
]);

parsed = parsePath(
'M 0 0 A 50 0 0 0 0 100 100 M 100 100 M 100 100 M 100 100 L 200 200',
);
expect(parsed.absolutePath).toStrictEqual([
['M', 0, 0],
['A', 50, 0, 0, 0, 0, 100, 100],
['L', 200, 200],
]);

parsed = parsePath('M 0 0 Q 50 0 100 100 M 200 100 L 200 200');
expect(parsed.absolutePath).toStrictEqual([
['M', 0, 0],
['Q', 50, 0, 100, 100],
['M', 200, 100],
['L', 200, 200],
]);
});
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"eslint-plugin-jest": "24.3.6",
"git-contributor": "~1.0.11",
"gl": "^6.0.2",
"get-pixels": "3.3.3",
"hammerjs": "^2.0.8",
"husky": "^7.0.4",
"is-ci": "2.0.0",
Expand Down
3 changes: 3 additions & 0 deletions packages/g-lite/src/css/parser/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
getPathBBox,
hasArcOrBezier,
path2Segments,
removeRedundantMCommand,
} from '../../utils/path';

const internalParsePath = (path: string | PathArray) => {
Expand Down Expand Up @@ -47,6 +48,8 @@ const internalParsePath = (path: string | PathArray) => {
console.error(`[g]: Invalid SVG Path definition: ${path}`);
}

removeRedundantMCommand(absolutePath);

const hasArc = hasArcOrBezier(absolutePath);

const { polygons, polylines } = extractPolygons(absolutePath);
Expand Down
2 changes: 2 additions & 0 deletions packages/g-lite/src/display-objects/Polygon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface PolygonStyleProps extends BaseStyleProps {
*/
markerEndOffset?: number;
isClosed?: boolean;
isBillboard?: boolean;
}
export interface ParsedPolygonStyleProps extends ParsedBaseStyleProps {
points: {
Expand All @@ -41,6 +42,7 @@ export interface ParsedPolygonStyleProps extends ParsedBaseStyleProps {
markerStartOffset?: number;
markerEndOffset?: number;
isClosed?: boolean;
isBillboard?: boolean;
}

export class Polygon extends DisplayObject<
Expand Down
2 changes: 2 additions & 0 deletions packages/g-lite/src/display-objects/Polyline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface PolylineStyleProps extends BaseStyleProps {
* offset relative to original position
*/
markerEndOffset?: number;
isBillboard?: boolean;
}
export interface ParsedPolylineStyleProps extends ParsedBaseStyleProps {
points: {
Expand All @@ -43,6 +44,7 @@ export interface ParsedPolylineStyleProps extends ParsedBaseStyleProps {
markerEnd?: DisplayObject | null;
markerStartOffset?: number;
markerEndOffset?: number;
isBillboard?: boolean;
}

/**
Expand Down
29 changes: 29 additions & 0 deletions packages/g-lite/src/utils/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,35 @@ export function getOrCalculatePathTotalLength(path: Path) {
return path.parsedStyle.path.totalLength;
}

export function removeRedundantMCommand(path: AbsoluteArray) {
for (let i = 0; i < path.length; i++) {
const prevSegment = path[i - 1];
const segment = path[i];
const cmd = segment[0];
if (cmd === 'M') {
if (prevSegment) {
const prevCmd = prevSegment[0];
const srcPoint = [segment[1], segment[2]];
let destPoint: [number, number];

if (prevCmd === 'L' || prevCmd === 'M') {
destPoint = [prevSegment[1], prevSegment[2]];
} else if (prevCmd === 'C' || prevCmd === 'A' || prevCmd === 'Q') {
destPoint = [
prevSegment[prevSegment.length - 2] as number,
prevSegment[prevSegment.length - 1] as number,
];
}

if (destPoint && isSamePoint(srcPoint, destPoint)) {
path.splice(i, 1);
i--;
}
}
}
}
}

export function hasArcOrBezier(path: AbsoluteArray) {
let hasArc = false;
const count = path.length;
Expand Down
12 changes: 8 additions & 4 deletions packages/g-plugin-device-renderer/src/drawcalls/InstancedLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export class InstancedLineDrawcall extends Instanced {
markerEnd,
markerStartOffset,
markerEndOffset,
isBillboard,
} = (object as Polyline).parsedStyle;
parsedLineStyleProps = {
x1: points[0][0],
Expand All @@ -155,7 +156,7 @@ export class InstancedLineDrawcall extends Instanced {
lineCap,
lineDash,
lineDashOffset,
isBillboard: true,
isBillboard,
markerStart,
markerEnd,
markerStartOffset,
Expand All @@ -174,6 +175,7 @@ export class InstancedLineDrawcall extends Instanced {
markerEnd,
markerStartOffset,
markerEndOffset,
isBillboard,
} = (object as Path).parsedStyle;
let mSegmentCount = 0;
let mCommandIndex = 0;
Expand All @@ -199,7 +201,7 @@ export class InstancedLineDrawcall extends Instanced {
lineCap,
lineDash,
lineDashOffset,
isBillboard: false,
isBillboard,
markerStart,
markerEnd,
markerStartOffset,
Expand Down Expand Up @@ -359,6 +361,7 @@ export class InstancedLineDrawcall extends Instanced {
markerEnd,
markerStartOffset,
markerEndOffset,
isBillboard,
} = (object as Polyline).parsedStyle;
parsedLineStyleProps = {
x1: points[0][0],
Expand All @@ -370,7 +373,7 @@ export class InstancedLineDrawcall extends Instanced {
defX,
defY,
lineCap,
isBillboard: true,
isBillboard,
markerStart,
markerEnd,
markerStartOffset,
Expand All @@ -386,6 +389,7 @@ export class InstancedLineDrawcall extends Instanced {
markerEnd,
markerStartOffset,
markerEndOffset,
isBillboard,
} = (object as Path).parsedStyle;
parsedLineStyleProps = {
x1: absolutePath[0][1],
Expand All @@ -397,7 +401,7 @@ export class InstancedLineDrawcall extends Instanced {
defX,
defY,
lineCap,
isBillboard: true,
isBillboard,
markerStart,
markerEnd,
markerStartOffset,
Expand Down
Loading

0 comments on commit eb61cba

Please sign in to comment.