💥 A flexible rendering engine for visualization.
Full Changelog: https://github.com/antvis/G/compare/@antv/[email protected]...@antv/[email protected]
The relative renderer and plugins should also be updated, eg.
transform
attributeIn previous designs, many of the initial properties of the shapes will affect the Transform
and the mat4
transform matrix behind it, for example:
cx/cy
in Circle / Ellipsex/y
in Rect / Image / Group / CustomElementd
in Pathx1/y1/x2/y2
in Linepoints
in Polyline / PolygonIn fact, the transform matrix should only be controlled by the transform
attribute, which leads to
transform
are computing the initial transform matrix, with unnecessary performance overhead and GC timetransform
sources. e.g. #1413 #1624<group>
doesn't have an x/y
attribute), it needs additional operations.So here's the breaking change looks like:
const circle = new Circle({ style: { cx: 100, cy: 100 } });
// before
circle.getPosition(); // [100, 100] `cx/cy` affect the transform matrix, whoops!!!
// after
circle.getPosition(); // [0, 0]
// Only transform attribute will affect RTS matrix.
circle.style.transform = 'translate(100, 100)';
circle.getPosition(); // [100, 100]
Here's an example from G2, for a Path
with the following attributes:
Path({
d: 'M -134.98699951171875,-100.01200103759766....',
transform: 'translate(304, 210)'
})
Now the transform
property can be visualized from the SVG dom:
We can create a following scenegraph Rect(parent) -> Rect(child)
like this:
const parent = new Rect({
style: {
x: 100,
y: 100,
width: 200,
height: 200,
fill: '#1890FF',
},
});
const child = new Rect({
style: {
x: 0,
y: 0,
width: 100,
height: 100,
fill: 'red',
}
});
parent.appendChild(child);
We should see the following result at [email protected]
, the red child start drawing itself from parent's x/y
:
But now since x/y
won't affect the parent's transform, the origin of local transform is still [0, 0]
:
Of course we can set the parent's transform
and reset its x/y
to [0, 0]
, at this point the effect is the same as before:
const parent = new Rect({
style: {
x: 0,
y: 0,
width: 200,
height: 200,
fill: '#1890FF',
transform: 'translate(100, 100)'
},
});
Scenegraph should only pass transform
from top to bottom.
Now we can implement the official SVG transform-origin
example:
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform-origin
Code: https://github.com/antvis/G/blob/%40antv/g%406.0.0/__tests__/demos/2d/transform-origin.ts
x/y
attribute is removed from Group and CustomElementNative SVG <group>
doesn't have an x/y
attribute. Transformations applied to the <grroup>
element are performed on its child elements.
// before
group.style.x = 100;
group.style.y = 100;
// after
group.style.transform = 'translate(100, 100)';
anchor
attribute is removed// before
rect.style.width = 100;
rect.style.height = 100;
rect.style.anchor = '0.5 0.5';
// after
rect.style.transform = 'translate(-50, -50)';
clipPath
share the coordinates with its targetNow the clipPath and its target share the same local coordinates, which can solve some confusing problems before:
const clipPath = new Circle({
style: {
cx: 100,
cy: 100,
r: 50,
},
});
const rect = new Rect({
style: {
x: 100
y: 100,
width: 100,
height: 100,
clipPath,
}
});
d
instead of path
in Path.src
instead of img
in Image.lineWidth
instead of strokeWidth
lineDash
instead of strokeDasharray
textAlign
instead of textAnchor
transformOrigin
in Circle / Ellipse is no more center
You should set manually like this if you want to scale/rotate around the center:
const circle = new Circle({ style: { cx: 10, cy: 10 } });
circle.style.transformOrigin = 'center';
circle.style.transformOrigin = '10 10'; // faster because it don't need to calculate bounds.
get/setClip
from DisplayObject
// before
const clipPath = circle.getClip();
circle.setClip(clipPath);
// after
const clipPath = circle.style.clipPath;
circle.style.clipPath = clipPath;
enableCSSParsing
is disabled by defaultWhich means you cannot use value with unit by default unless enable it.
runtime.enableCSSParsing = true;
circle.style.r = '3em';
enableAttributeDashCased
is disabled by defaultThe built-in attributes can be accessed only when enableAttributeDashCased` is enabled.
runtime.enableAttributeDashCased = true;
circle.setAttribute('line-width', '2');
The online benchmarks: https://observablehq.com/d/d54e30062ec837a5
~2x perf boost compared with 5.x.
Polyline
We found the process of parse points
for Polyline
is very time-consuming. The following image shows the processing time from G2.
10397c19: Support shadowRoot when picking.
Updated dependencies [10397c19]
1d25bf84: ClipPath should be copied first before calculate intersection bounds.
Updated dependencies [1d25bf84]
Disable memoize during interpolation to avoid OOM.
You can also register custom easing function via EasingFunctions
like this:
import { EasingFunctions } from '@antv/g';
// Register easing function.
EasingFunctions['my-easing'] = (t: number) => t;
circle.animate([{ opacity: 0 }, { opacity: 1 }], {
duration: 500,
easing: 'my-easing', // Use it by name.
});
You can find more easing functions on: https://easings.net/
isBillboard
enabled and fill
should be used correctly.willReadFrequently: true
should be passed in when creating offscreen canvas so that the browser won't throw warning.When keepAspectRatio
enabled, either width
or height
can be omitted and the missing one can be inferred according to raw image's aspect. In the following example, height
will be calculated automatically after the Image being loaded.
new Image({
style: {
src: 'http://',
keepAspectRatio: true,
width: 100
}
})
But since the image loading process is in an async way, if we try to get bounds immediately, we'll get an empty bounds:
const image = new Image({
style: {
src: 'http://',
keepAspectRatio: true,
width: 100
}
});
image.getBounds(); // empty