diff --git a/.changeset/big-roses-appear.md b/.changeset/big-roses-appear.md new file mode 100644 index 000000000..d87f549ea --- /dev/null +++ b/.changeset/big-roses-appear.md @@ -0,0 +1,7 @@ +--- +'@antv/g-plugin-device-renderer': patch +'@antv/g-shader-components': patch +'@antv/g-lite': patch +--- + +Support size attenuation. diff --git a/.changeset/lemon-coins-sell.md b/.changeset/lemon-coins-sell.md new file mode 100644 index 000000000..defe19094 --- /dev/null +++ b/.changeset/lemon-coins-sell.md @@ -0,0 +1,7 @@ +--- +'@antv/g-plugin-device-renderer': patch +'@antv/g-shader-components': patch +'@antv/g-lite': patch +--- + +Polyline should support 3D points. diff --git a/.changeset/stupid-avocados-report.md b/.changeset/stupid-avocados-report.md new file mode 100644 index 000000000..a3810a99f --- /dev/null +++ b/.changeset/stupid-avocados-report.md @@ -0,0 +1,7 @@ +--- +'@antv/g-plugin-device-renderer': patch +'@antv/g-shader-components': patch +'@antv/g-lite': patch +--- + +Support rotation when applying billboard effect. diff --git a/packages/g-lite/src/css/properties/CSSPropertyPoints.ts b/packages/g-lite/src/css/properties/CSSPropertyPoints.ts index 33fe469c2..f7d60e1f8 100644 --- a/packages/g-lite/src/css/properties/CSSPropertyPoints.ts +++ b/packages/g-lite/src/css/properties/CSSPropertyPoints.ts @@ -9,12 +9,12 @@ export class CSSPropertyPoints Partial< CSSProperty< { - points: [number, number][]; + points: [number, number, number?][]; totalLength: number; segments: [number, number][]; }, { - points: [number, number][]; + points: [number, number, number?][]; totalLength: number; segments: [number, number][]; } diff --git a/packages/g-lite/src/display-objects/Image.ts b/packages/g-lite/src/display-objects/Image.ts index cbfa088e0..3fff9cb55 100644 --- a/packages/g-lite/src/display-objects/Image.ts +++ b/packages/g-lite/src/display-objects/Image.ts @@ -13,6 +13,8 @@ export interface ImageStyleProps extends BaseStyleProps { width?: number | string; height?: number | string; isBillboard?: boolean; + billboardRotation?: number; + isSizeAttenuation?: boolean; } export interface ParsedImageStyleProps extends ParsedBaseStyleProps { x: number; @@ -23,6 +25,8 @@ export interface ParsedImageStyleProps extends ParsedBaseStyleProps { width?: number; height?: number; isBillboard?: boolean; + billboardRotation?: number; + isSizeAttenuation?: boolean; } export class Image extends DisplayObject< ImageStyleProps, diff --git a/packages/g-lite/src/display-objects/Polygon.ts b/packages/g-lite/src/display-objects/Polygon.ts index 2fe1d0bd6..667b90f24 100644 --- a/packages/g-lite/src/display-objects/Polygon.ts +++ b/packages/g-lite/src/display-objects/Polygon.ts @@ -5,7 +5,7 @@ import { Shape } from '../types'; import { DisplayObject, isDisplayObject } from './DisplayObject'; export interface PolygonStyleProps extends BaseStyleProps { - points: [number, number][]; + points: [number, number, number?][]; /** * marker will be positioned at the first point */ @@ -31,7 +31,7 @@ export interface PolygonStyleProps extends BaseStyleProps { } export interface ParsedPolygonStyleProps extends ParsedBaseStyleProps { points: { - points: [number, number][]; + points: [number, number, number?][]; segments: [number, number][]; totalLength: number; }; diff --git a/packages/g-lite/src/display-objects/Polyline.ts b/packages/g-lite/src/display-objects/Polyline.ts index ea002dfda..201c4e952 100644 --- a/packages/g-lite/src/display-objects/Polyline.ts +++ b/packages/g-lite/src/display-objects/Polyline.ts @@ -9,7 +9,7 @@ import type { DisplayObject } from './DisplayObject'; import { Polygon } from './Polygon'; export interface PolylineStyleProps extends BaseStyleProps { - points: [number, number][]; + points: [number, number, number?][]; /** * marker will be positioned at the first point */ @@ -34,7 +34,7 @@ export interface PolylineStyleProps extends BaseStyleProps { } export interface ParsedPolylineStyleProps extends ParsedBaseStyleProps { points: { - points: [number, number][]; + points: [number, number, number?][]; segments: [number, number][]; totalLength: number; }; diff --git a/packages/g-lite/src/display-objects/Text.ts b/packages/g-lite/src/display-objects/Text.ts index d27716ec1..ecdcfbb94 100644 --- a/packages/g-lite/src/display-objects/Text.ts +++ b/packages/g-lite/src/display-objects/Text.ts @@ -23,10 +23,15 @@ export interface TextStyleProps extends BaseStyleProps { */ isBillboard?: boolean; + /** + * The rotation of the billboard in radians. + */ + billboardRotation?: number; + /** * Whether the size of the sprite is attenuated by the camera depth. (Perspective camera only.) */ - sizeAttenuation?: boolean; + isSizeAttenuation?: boolean; text: number | string; @@ -194,7 +199,8 @@ export interface ParsedTextStyleProps extends ParsedBaseStyleProps { y: number; z?: number; isBillboard?: boolean; - sizeAttenuation?: boolean; + billboardRotation?: number; + isSizeAttenuation?: boolean; text: string; textAlign?: 'start' | 'center' | 'middle' | 'end' | 'left' | 'right'; textBaseline?: @@ -268,8 +274,6 @@ export class Text extends DisplayObject { leading: 0, dx: '', dy: '', - isBillboard: false, - sizeAttenuation: true, ...style, } : { @@ -295,8 +299,6 @@ export class Text extends DisplayObject { leading: 0, dx: 0, dy: 0, - isBillboard: false, - sizeAttenuation: true, }, ...rest, }); diff --git a/packages/g-lite/src/utils/path.ts b/packages/g-lite/src/utils/path.ts index d3f6cb2ca..86cca1e18 100644 --- a/packages/g-lite/src/utils/path.ts +++ b/packages/g-lite/src/utils/path.ts @@ -786,7 +786,7 @@ function ellipseToCommands( } function polygonToCommands( - points: [number, number][], + points: [number, number, number?][], closed: boolean, ): AbsoluteArray { const result = points.map((point, i) => { diff --git a/packages/g-plugin-device-renderer/src/drawcalls/Image.ts b/packages/g-plugin-device-renderer/src/drawcalls/Image.ts index 610c0963c..227871af0 100644 --- a/packages/g-plugin-device-renderer/src/drawcalls/Image.ts +++ b/packages/g-plugin-device-renderer/src/drawcalls/Image.ts @@ -7,6 +7,15 @@ import { import { Format, VertexBufferFrequency } from '../platform'; import frag from '../shader/image.frag'; import vert from '../shader/image.vert'; +import { enumToObject } from '../utils'; + +enum ImageVertexAttributeBufferIndex { + PACKED_STYLE = VertexAttributeBufferIndex.POSITION + 1, +} + +enum ImageVertexAttributeLocation { + PACKED_STYLE3 = VertexAttributeLocation.MAX, +} export class ImageDrawcall extends Instanced { shouldMerge(object: DisplayObject, index: number) { @@ -29,6 +38,7 @@ export class ImageDrawcall extends Instanced { this.material.defines = { ...this.material.defines, + ...enumToObject(ImageVertexAttributeLocation), }; this.material.vertexShader = vert; @@ -45,27 +55,54 @@ export class ImageDrawcall extends Instanced { super.createGeometry(objects); const instanced: number[] = []; + const packedStyle: number[] = []; objects.forEach((object, i) => { const image = object as ImageShape; - const { width, height, z, isBillboard } = image.parsedStyle; - instanced.push(width, height, z, isBillboard ? 1 : 0); + const { + width, + height, + isBillboard, + billboardRotation, + isSizeAttenuation, + } = image.parsedStyle; + instanced.push(width, height); + packedStyle.push( + isBillboard ? 1 : 0, + billboardRotation ?? 0, + isSizeAttenuation ? 1 : 0, + 0, + ); }); this.geometry.setIndexBuffer(new Uint32Array([0, 2, 1, 0, 3, 2])); this.geometry.vertexCount = 6; this.geometry.setVertexBuffer({ bufferIndex: VertexAttributeBufferIndex.POSITION, - byteStride: 4 * 4, + byteStride: 4 * 2, frequency: VertexBufferFrequency.PerInstance, attributes: [ { - format: Format.F32_RGBA, + format: Format.F32_RG, bufferByteOffset: 4 * 0, location: VertexAttributeLocation.POSITION, }, ], data: new Float32Array(instanced), }); + this.geometry.setVertexBuffer({ + bufferIndex: ImageVertexAttributeBufferIndex.PACKED_STYLE, + byteStride: 4 * 4, + frequency: VertexBufferFrequency.PerInstance, + attributes: [ + { + format: Format.F32_RGBA, + bufferByteOffset: 4 * 0, + location: ImageVertexAttributeLocation.PACKED_STYLE3, + divisor: 1, + }, + ], + data: new Float32Array(packedStyle), + }); this.geometry.setVertexBuffer({ bufferIndex: VertexAttributeBufferIndex.UV, byteStride: 4 * 2, @@ -91,17 +128,12 @@ export class ImageDrawcall extends Instanced { this.updateBatchedAttribute(objects, startIndex, name, value); - if ( - name === 'width' || - name === 'height' || - name === 'z' || - name === 'isBillboard' - ) { + if (name === 'width' || name === 'height' || name === 'z') { const packed: number[] = []; objects.forEach((object) => { const image = object as ImageShape; - const { width, height, z, isBillboard } = image.parsedStyle; - packed.push(width, height, z, isBillboard ? 1 : 0); + const { width, height } = image.parsedStyle; + packed.push(width, height); }); this.geometry.updateVertexBuffer( @@ -110,6 +142,30 @@ export class ImageDrawcall extends Instanced { startIndex, new Uint8Array(new Float32Array(packed).buffer), ); + } else if ( + name === 'isBillboard' || + name === 'billboardRotation' || + name === 'isSizeAttenuation' + ) { + const packed: number[] = []; + objects.forEach((object) => { + const image = object as ImageShape; + const { isBillboard, billboardRotation, isSizeAttenuation } = + image.parsedStyle; + packed.push( + isBillboard ? 1 : 0, + billboardRotation ?? 0, + isSizeAttenuation ? 1 : 0, + 0, + ); + }); + + this.geometry.updateVertexBuffer( + ImageVertexAttributeBufferIndex.PACKED_STYLE, + ImageVertexAttributeLocation.PACKED_STYLE3, + startIndex, + new Uint8Array(new Float32Array(packed).buffer), + ); } else if (name === 'img') { const map = this.texturePool.getOrCreateTexture( this.context.device, diff --git a/packages/g-plugin-device-renderer/src/drawcalls/InstancedFill.ts b/packages/g-plugin-device-renderer/src/drawcalls/InstancedFill.ts index 2686eb902..18c3194a5 100644 --- a/packages/g-plugin-device-renderer/src/drawcalls/InstancedFill.ts +++ b/packages/g-plugin-device-renderer/src/drawcalls/InstancedFill.ts @@ -114,11 +114,11 @@ export class InstancedFillDrawcall extends Instanced { this.geometry.setVertexBuffer({ bufferIndex: VertexAttributeBufferIndex.POSITION, - byteStride: 4 * 2, + byteStride: 4 * 3, frequency: VertexBufferFrequency.PerVertex, attributes: [ { - format: Format.F32_RG, + format: Format.F32_RGB, bufferByteOffset: 4 * 0, location: VertexAttributeLocation.POSITION, }, diff --git a/packages/g-plugin-device-renderer/src/drawcalls/InstancedPath.ts b/packages/g-plugin-device-renderer/src/drawcalls/InstancedPath.ts index 8def9c4ae..f03477774 100644 --- a/packages/g-plugin-device-renderer/src/drawcalls/InstancedPath.ts +++ b/packages/g-plugin-device-renderer/src/drawcalls/InstancedPath.ts @@ -138,7 +138,6 @@ export class InstancedPathDrawcall extends Instanced { this.material.defines = { ...this.material.defines, ...enumToObject(LineVertexAttributeLocation), - INSTANCED: true, }; } @@ -175,7 +174,7 @@ export class InstancedPathDrawcall extends Instanced { // Can't use interleaved buffer here, we should spread them like: // | prev - pointA - pointB - next |. This will allocate ~4x buffer memory space. - for (let i = 0; i < pBuffer.length - 3 * 3; i += 3) { + for (let i = 0; i < pBuffer.length - 3 * 4; i += 4) { pointsBuffer.push( pBuffer[i], pBuffer[i + 1], @@ -189,6 +188,10 @@ export class InstancedPathDrawcall extends Instanced { pBuffer[i + 9], pBuffer[i + 10], pBuffer[i + 11], + pBuffer[i + 12], + pBuffer[i + 13], + pBuffer[i + 14], + pBuffer[i + 15], ); } @@ -217,36 +220,36 @@ export class InstancedPathDrawcall extends Instanced { if (pointsBuffer.length) { this.geometry.setVertexBuffer({ bufferIndex: LineVertexAttributeBufferIndex.PACKED, - byteStride: 4 * (3 + 3 + 3 + 3), + byteStride: 4 * (4 + 4 + 4 + 4), frequency: VertexBufferFrequency.PerInstance, attributes: [ { - format: Format.F32_RG, + format: Format.F32_RGB, bufferByteOffset: 4 * 0, location: LineVertexAttributeLocation.PREV, divisor: 1, }, { - format: Format.F32_RG, - bufferByteOffset: 4 * 3, + format: Format.F32_RGB, + bufferByteOffset: 4 * 4, location: LineVertexAttributeLocation.POINT1, divisor: 1, }, { format: Format.F32_R, - bufferByteOffset: 4 * 5, + bufferByteOffset: 4 * 7, location: LineVertexAttributeLocation.VERTEX_JOINT, divisor: 1, }, { - format: Format.F32_RG, - bufferByteOffset: 4 * 6, + format: Format.F32_RGB, + bufferByteOffset: 4 * 8, location: LineVertexAttributeLocation.POINT2, divisor: 1, }, { - format: Format.F32_RG, - bufferByteOffset: 4 * 9, + format: Format.F32_RGB, + bufferByteOffset: 4 * 12, location: LineVertexAttributeLocation.NEXT, divisor: 1, }, @@ -359,7 +362,7 @@ export class InstancedPathDrawcall extends Instanced { // Can't use interleaved buffer here, we should spread them like: // | prev - pointA - pointB - next |. This will allocate ~4x buffer memory space. - for (let i = 0; i < pBuffer.length - 3 * 3; i += 3) { + for (let i = 0; i < pBuffer.length - 3 * 4; i += 4) { pointsBuffer.push( pBuffer[i], pBuffer[i + 1], @@ -373,6 +376,10 @@ export class InstancedPathDrawcall extends Instanced { pBuffer[i + 9], pBuffer[i + 10], pBuffer[i + 11], + pBuffer[i + 12], + pBuffer[i + 13], + pBuffer[i + 14], + pBuffer[i + 15], ); } @@ -435,8 +442,8 @@ export enum JOINT_TYPE { CAP_BUTT2 = 4 << 5, } -const stridePoints = 2; -const strideFloats = 3; +const stridePoints = 3; +const strideFloats = 4; export function updateBuffer( object: DisplayObject, @@ -496,7 +503,7 @@ export function updateBuffer( offsetY = endOffsetY; } - prev.push(cur[0] - defX + offsetX, cur[1] - defY + offsetY); + prev.push(cur[0] - defX + offsetX, cur[1] - defY + offsetY, cur[2] || 0); return prev; }, [] as number[]); @@ -504,7 +511,7 @@ export function updateBuffer( if (object.nodeName === Shape.POLYGON) { if (needEarcut) { // use earcut for triangulation - triangles = earcut(points[0], [], 2); + triangles = earcut(points[0], [], 3); return { pointsBuffer: points[0], travelBuffer: [], @@ -512,13 +519,15 @@ export function updateBuffer( instancedCount: Math.round(points[0].length / stridePoints), }; } else { - points[0].push(points[0][0], points[0][1]); + points[0].push(points[0][0], points[0][1], points[0][2] || 0); points[0].push( ...addTailSegment( points[0][0], points[0][1], - points[0][2], + points[0][2] || 0, points[0][3], + points[0][4], + points[0][5] || 0, ), ); } @@ -600,20 +609,23 @@ export function updateBuffer( points[mCommandsNum].push( params[0] - defX + startOffsetX, params[1] - defY + startOffsetY, + 0, params[0] - defX, params[1] - defY, + 0, ); } else { - points[mCommandsNum].push(params[0] - defX, params[1] - defY); + points[mCommandsNum].push(params[0] - defX, params[1] - defY, 0); } } else if (command === 'L') { if (useEndOffset) { points[mCommandsNum].push( params[0] - defX + endOffsetX, params[1] - defY + endOffsetY, + 0, ); } else { - points[mCommandsNum].push(params[0] - defX, params[1] - defY); + points[mCommandsNum].push(params[0] - defX, params[1] - defY, 0); } } else if (command === 'Q') { quadCurveTo( @@ -628,6 +640,7 @@ export function updateBuffer( points[mCommandsNum].push( params[2] - defX + endOffsetX, params[3] - defY + endOffsetY, + 0, ); } } else if (command === 'A') { @@ -664,6 +677,7 @@ export function updateBuffer( points[mCommandsNum].push( params[5] - defX + endOffsetX, params[6] - defY + endOffsetY, + 0, ); } } else if (command === 'C') { @@ -681,6 +695,7 @@ export function updateBuffer( points[mCommandsNum].push( params[4] - defX + endOffsetX, params[5] - defY + endOffsetY, + 0, ); } } else if ( @@ -702,6 +717,7 @@ export function updateBuffer( points[mCommandsNum].push( points[mCommandsNum][startPointIndex], points[mCommandsNum][startPointIndex + 1], + 0, ); } @@ -711,6 +727,8 @@ export function updateBuffer( points[mCommandsNum][startPointIndex + 1], points[mCommandsNum][startPointIndex + 2], points[mCommandsNum][startPointIndex + 3], + points[mCommandsNum][startPointIndex + 4], + points[mCommandsNum][startPointIndex + 5], ), ); } @@ -719,7 +737,7 @@ export function updateBuffer( if (needEarcut) { const pointsBuffer = points[subPathIndex]; // use earcut for triangulation - triangles = earcut(pointsBuffer, [], 2); + triangles = earcut(pointsBuffer, [], 3); return { pointsBuffer, travelBuffer: [], @@ -755,8 +773,9 @@ export function updateBuffer( // 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), + Math.pow(points[i] - points[i - stridePoints], 2) + + Math.pow(points[i + 1] - points[i + 1 - stridePoints], 2) + + Math.pow(points[i + 2] - points[i + 2 - stridePoints], 2), ); } travelBuffer.push(dist); @@ -766,6 +785,7 @@ export function updateBuffer( pointsBuffer[j++] = points[i]; pointsBuffer[j++] = points[i + 1]; + pointsBuffer[j++] = points[i + 2] || 0; pointsBuffer[j] = jointType; if (i == 0 && capType !== JOINT_TYPE.CAP_ROUND) { pointsBuffer[j] += capType; @@ -777,15 +797,18 @@ export function updateBuffer( } j++; } - pointsBuffer[j++] = points[points.length - 4]; - pointsBuffer[j++] = points[points.length - 3]; + pointsBuffer[j++] = points[points.length - 6]; + pointsBuffer[j++] = points[points.length - 5]; + pointsBuffer[j++] = points[points.length - 4] || 0; pointsBuffer[j++] = 0; pointsBuffer[0] = points[0]; pointsBuffer[1] = points[1]; - pointsBuffer[2] = 0; - pointsBuffer[3] = points[2]; + pointsBuffer[2] = points[2] || 0; + pointsBuffer[3] = 0; pointsBuffer[4] = points[3]; - pointsBuffer[5] = capType === JOINT_TYPE.CAP_ROUND ? capType : 0; + pointsBuffer[5] = points[4]; + pointsBuffer[6] = points[5] || 0; + pointsBuffer[7] = capType === JOINT_TYPE.CAP_ROUND ? capType : 0; const instancedCount = Math.round(points.length / stridePoints); @@ -837,10 +860,12 @@ function getCapType(lineCap: CanvasLineCap) { function addTailSegment( x1: number, y1: number, + z1: number, x2: number = x1, y2: number = y1, + z2: number = z1, ) { - const vec = [x2 - x1, y2 - y1]; + const vec = [x2 - x1, y2 - y1, z2 - z1]; const length = 0.01; - return [x1 + vec[0] * length, y1 + vec[1] * length]; + return [x1 + vec[0] * length, y1 + vec[1] * length, z1 + vec[2] * length]; } diff --git a/packages/g-plugin-device-renderer/src/drawcalls/SDF.ts b/packages/g-plugin-device-renderer/src/drawcalls/SDF.ts index b84358f10..4bfecaa80 100644 --- a/packages/g-plugin-device-renderer/src/drawcalls/SDF.ts +++ b/packages/g-plugin-device-renderer/src/drawcalls/SDF.ts @@ -213,15 +213,4 @@ export class SDFDrawcall extends Instanced { const hasStrokeOpacity = strokeOpacity < 1; return !hasStroke || (hasStroke && (hasLineDash || hasStrokeOpacity)); } - - private needDrawStrokeSeparately(parsedStyle: ParsedBaseStyleProps) { - const { stroke, lineDash, lineWidth, strokeOpacity } = parsedStyle; - const hasStroke = stroke && !(stroke as CSSRGB).isNone; - const hasLineDash = - lineDash && - lineDash.length && - lineDash.every((item: number) => item !== 0); - const hasStrokeOpacity = strokeOpacity < 1; - return hasStroke && lineWidth > 0 && (hasLineDash || hasStrokeOpacity); - } } diff --git a/packages/g-plugin-device-renderer/src/drawcalls/Text.ts b/packages/g-plugin-device-renderer/src/drawcalls/Text.ts index 7dc540661..26a1e9d0f 100644 --- a/packages/g-plugin-device-renderer/src/drawcalls/Text.ts +++ b/packages/g-plugin-device-renderer/src/drawcalls/Text.ts @@ -348,7 +348,9 @@ export class TextDrawcall extends Instanced { name === 'lineWidth' || name === 'visibility' || name === 'pointerEvents' || - name === 'isBillboard' + name === 'isBillboard' || + name === 'billboardRotation' || + name === 'isSizeAttenuation' ) { const vertice = this.geometry.vertices[ TextVertexAttributeBufferIndex.INSTANCED @@ -369,7 +371,8 @@ export class TextDrawcall extends Instanced { lineWidth, visibility, isBillboard, - sizeAttenuation, + billboardRotation, + isSizeAttenuation, } = object.parsedStyle as ParsedTextStyleProps; let fillColor: Tuple4Number = [0, 0, 0, 0]; if (isCSSRGB(fill)) { @@ -430,8 +433,8 @@ export class TextDrawcall extends Instanced { sliced[i + 23] = lineWidth; sliced[i + 24] = visibility === 'visible' ? 1 : 0; sliced[i + 25] = isBillboard ? 1 : 0; - sliced[i + 26] = sizeAttenuation ? 1 : 0; - sliced[i + 27] = 0; + sliced[i + 26] = isSizeAttenuation ? 1 : 0; + sliced[i + 27] = billboardRotation ?? 0; sliced[i + 28] = encodedPickingColor[0]; sliced[i + 29] = encodedPickingColor[1]; sliced[i + 30] = encodedPickingColor[2]; @@ -479,7 +482,8 @@ export class TextDrawcall extends Instanced { lineWidth, visibility, isBillboard, - sizeAttenuation, + billboardRotation, + isSizeAttenuation, } = object.parsedStyle as ParsedTextStyleProps; let fillColor: Tuple4Number = [0, 0, 0, 0]; if (isCSSRGB(fill)) { @@ -541,8 +545,8 @@ export class TextDrawcall extends Instanced { lineWidth, visibility === 'visible' ? 1 : 0, isBillboard ? 1 : 0, - sizeAttenuation ? 1 : 0, - 0, + isSizeAttenuation ? 1 : 0, + billboardRotation ?? 0, ...encodedPickingColor, object.sortable.renderOrder * RENDER_ORDER_SCALE, ]; diff --git a/packages/g-plugin-device-renderer/src/shader/image.vert b/packages/g-plugin-device-renderer/src/shader/image.vert index ccd3697ad..102ddfe7b 100644 --- a/packages/g-plugin-device-renderer/src/shader/image.vert +++ b/packages/g-plugin-device-renderer/src/shader/image.vert @@ -1,28 +1,26 @@ #pragma glslify: import('@antv/g-shader-components/scene.both.glsl') #pragma glslify: import('@antv/g-shader-components/batch.declaration.vert') #pragma glslify: project = require('@antv/g-shader-components/project.vert') +#pragma glslify: billboard = require('@antv/g-shader-components/billboard.vert') -layout(location = POSITION) in vec4 a_Size; +layout(location = POSITION) in vec2 a_Size; +layout(location = PACKED_STYLE3) in vec4 a_StylePacked3; #ifdef USE_UV layout(location = UV) in vec2 a_Uv; out vec2 v_Uv; #endif -bool isPerspectiveMatrix(mat4 m) { - return m[ 2 ][ 3 ] == - 1.0; -} - void main() { #pragma glslify: import('@antv/g-shader-components/batch.vert') - vec2 offset = (a_Uv - u_Anchor.xy) * a_Size.xy; - - bool isPerspective = isPerspectiveMatrix(u_ProjectionMatrix); + vec2 offset = (a_Uv - u_Anchor.xy) * a_Size; - bool isBillboard = a_Size.w > 0.5; + bool isBillboard = a_StylePacked3.x > 0.5; if (isBillboard) { - #pragma glslify: import('@antv/g-shader-components/billboard.vert') + float rotation = a_StylePacked3.y; + bool isSizeAttenuation = a_StylePacked3.z > 0.5; + gl_Position = billboard(offset, rotation, isSizeAttenuation, u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); } else { gl_Position = project(vec4(offset, u_ZIndex, 1.0), u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); } diff --git a/packages/g-plugin-device-renderer/src/shader/line.frag b/packages/g-plugin-device-renderer/src/shader/line.frag index 9f2e40f9d..e36d6d9f6 100644 --- a/packages/g-plugin-device-renderer/src/shader/line.frag +++ b/packages/g-plugin-device-renderer/src/shader/line.frag @@ -1,11 +1,7 @@ #pragma glslify: import('@antv/g-shader-components/scene.both.glsl') -#ifdef INSTANCED - #pragma glslify: import('@antv/g-shader-components/batch.declaration.frag') - in vec4 v_Dash; -#else - #pragma glslify: import('@antv/g-shader-components/line.both.glsl') -#endif +#pragma glslify: import('@antv/g-shader-components/batch.declaration.frag') +in vec4 v_Dash; in vec4 v_Distance; in vec4 v_Arc; @@ -16,13 +12,7 @@ in float v_ScalingFactor; out vec4 outputColor; void main(){ - #ifdef INSTANCED - #pragma glslify: import('@antv/g-shader-components/batch.frag') - #else - if (u_Visible < 0.5) { - discard; - } - #endif + #pragma glslify: import('@antv/g-shader-components/batch.frag') float alpha = 1.0; float lineWidth = v_Distance.w; @@ -65,11 +55,9 @@ void main(){ alpha *= max(min(v_Distance.z + 0.5, 1.0), 0.0); } - #ifdef INSTANCED - float u_Dash = v_Dash.x; - float u_Gap = v_Dash.y; - float u_DashOffset = v_Dash.z; - #endif + float u_Dash = v_Dash.x; + float u_Gap = v_Dash.y; + float u_DashOffset = v_Dash.z; if (u_Dash + u_Gap > 1.0) { float travel = mod(v_Travel + u_Gap * v_ScalingFactor * 0.5 + u_DashOffset, u_Dash * v_ScalingFactor + u_Gap * v_ScalingFactor) - (u_Gap * v_ScalingFactor * 0.5); float left = max(travel - 0.5, -0.5); @@ -78,11 +66,7 @@ void main(){ } if (u_IsPicking > 0.5) { - #ifdef INSTANCED - vec3 pickingColor = u_PickingColor; - #else - vec3 pickingColor = u_PickingColor / 255.0; - #endif + vec3 pickingColor = u_PickingColor; if (pickingColor.x == 0.0 && pickingColor.y == 0.0 && pickingColor.z == 0.0) { discard; } diff --git a/packages/g-plugin-device-renderer/src/shader/line.vert b/packages/g-plugin-device-renderer/src/shader/line.vert index 02507160f..836ddca5e 100644 --- a/packages/g-plugin-device-renderer/src/shader/line.vert +++ b/packages/g-plugin-device-renderer/src/shader/line.vert @@ -1,23 +1,18 @@ #pragma glslify: import('@antv/g-shader-components/scene.both.glsl') -#ifdef INSTANCED - #pragma glslify: import('@antv/g-shader-components/batch.declaration.vert') -#else - #pragma glslify: import('@antv/g-shader-components/line.both.glsl') -#endif +#pragma glslify: import('@antv/g-shader-components/batch.declaration.vert') +#pragma glslify: project = require('@antv/g-shader-components/project.vert') -layout(location = PREV) in vec2 a_Prev; -layout(location = POINT1) in vec2 a_Point1; -layout(location = POINT2) in vec2 a_Point2; -layout(location = NEXT) in vec2 a_Next; +layout(location = PREV) in vec3 a_Prev; +layout(location = POINT1) in vec3 a_Point1; +layout(location = POINT2) in vec3 a_Point2; +layout(location = NEXT) in vec3 a_Next; layout(location = VERTEX_JOINT) in float a_VertexJoint; layout(location = VERTEX_NUM) in float a_VertexNum; layout(location = TRAVEL) in float a_Travel; -#ifdef INSTANCED - layout(location = DASH) in vec4 a_Dash; - out vec4 v_Dash; -#endif +layout(location = DASH) in vec4 a_Dash; +out vec4 v_Dash; const float FILL = 1.0; const float BEVEL = 4.0; @@ -32,12 +27,10 @@ const float CAP_SQUARE = 2.0; const float CAP_ROUND = 3.0; const float CAP_BUTT2 = 4.0; -#ifdef INSTANCED - const float u_Expand = 1.0; - const float u_MiterLimit = 5.0; - const float u_ScaleMode = 1.0; - const float u_Alignment = 0.5; -#endif +const float u_Expand = 1.0; +const float u_MiterLimit = 5.0; +const float u_ScaleMode = 1.0; +const float u_Alignment = 0.5; out vec4 v_Distance; out vec4 v_Arc; @@ -65,14 +58,32 @@ vec2 doBisect( return dy * bisect; } +vec2 project2ScreenSpace(vec3 pos, mat4 u_ModelMatrix) { + vec4 clip = project(vec4(pos, 1.0), u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); + return u_Viewport * (0.5 * clip.xy / clip.w + 0.5); +} + void main() { - #ifdef INSTANCED - #pragma glslify: import('@antv/g-shader-components/batch.vert') - v_Dash = a_Dash; - #endif + #pragma glslify: import('@antv/g-shader-components/batch.vert') + v_Dash = a_Dash; + + vec2 pointA; + vec2 pointB; + vec4 clip0; + vec4 clip1; - vec2 pointA = (u_ModelMatrix * vec4(a_Point1, 0., 1.0)).xy; - vec2 pointB = (u_ModelMatrix * vec4(a_Point2, 0., 1.0)).xy; + float isBillboard = a_Dash.w; + if (isBillboard > 0.5) { + // clip space + clip0 = project(vec4(a_Point1, 1.0), u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); + clip1 = project(vec4(a_Point2, 1.0), u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); + // screen space + pointA = project2ScreenSpace(a_Point1, u_ModelMatrix); + pointB = project2ScreenSpace(a_Point2, u_ModelMatrix); + } else { + pointA = (u_ModelMatrix * vec4(a_Point1, 1.0)).xy; + pointB = (u_ModelMatrix * vec4(a_Point2, 1.0)).xy; + } vec2 xBasis = pointB - pointA; float len = length(xBasis); @@ -125,12 +136,22 @@ void main() { float flag = 0.0; float sign2 = 1.0; if (a_VertexNum < 0.5 || a_VertexNum > 2.5 && a_VertexNum < 3.5) { - next = (u_ModelMatrix * vec4(a_Prev, 0.0, 1.0)).xy; + if (isBillboard > 0.5) { + next = project2ScreenSpace(a_Prev, u_ModelMatrix); + } else { + next = (u_ModelMatrix * vec4(a_Prev, 1.0)).xy; + } + base = pointA; flag = type - floor(type / 2.0) * 2.0; sign2 = -1.0; } else { - next = (u_ModelMatrix * vec4(a_Next, 0.0, 1.0)).xy; + if (isBillboard > 0.5) { + next = project2ScreenSpace(a_Next, u_ModelMatrix); + } else { + next = (u_ModelMatrix * vec4(a_Next, 1.0)).xy; + } + base = pointB; if (type >= MITER && type < MITER + 3.5) { flag = step(MITER + 1.5, type); @@ -335,5 +356,10 @@ void main() { v_ScalingFactor = sqrt(u_ModelMatrix[0][0] * u_ModelMatrix[0][0] + u_ModelMatrix[0][1] * u_ModelMatrix[0][1] + u_ModelMatrix[0][2] * u_ModelMatrix[0][2]); - gl_Position = u_ProjectionMatrix * u_ViewMatrix * vec4(pos, u_ZIndex, 1.0); + if (isBillboard > 0.5) { + vec4 clip = mix(clip0, clip1, 0.5); + gl_Position = vec4(clip.w * (2.0 * pos / u_Viewport - 1.0), clip.z, clip.w); + } else { + gl_Position = u_ProjectionMatrix * u_ViewMatrix * vec4(pos, u_ZIndex, 1.0); + } } \ 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 0d92a2bfe..7a7f21046 100644 --- a/packages/g-plugin-device-renderer/src/shader/mesh.vert +++ b/packages/g-plugin-device-renderer/src/shader/mesh.vert @@ -3,7 +3,7 @@ #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; +layout(location = POSITION) in vec3 a_Position; #ifdef USE_UV layout(location = UV) in vec2 a_Uv; out vec2 v_Uv; @@ -13,5 +13,5 @@ void main() { #pragma glslify: import('@antv/g-shader-components/batch.vert') #pragma glslify: import('@antv/g-shader-components/uv.vert') - gl_Position = project(vec4(a_Position, u_ZIndex, 1.0), u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); + gl_Position = project(vec4(a_Position.xy, 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/sdf.vert b/packages/g-plugin-device-renderer/src/shader/sdf.vert index d09eadf94..6ffbe991c 100644 --- a/packages/g-plugin-device-renderer/src/shader/sdf.vert +++ b/packages/g-plugin-device-renderer/src/shader/sdf.vert @@ -2,6 +2,7 @@ #pragma glslify: import('@antv/g-shader-components/batch.declaration.vert') #pragma glslify: project = require('@antv/g-shader-components/project.vert') +#pragma glslify: billboard = require('@antv/g-shader-components/billboard.vert') layout(location = POSITION) in vec2 a_Extrude; // shape, radius, omitStroke, isBillboard @@ -34,7 +35,9 @@ void main() { bool isBillboard = a_StylePacked3.w > 0.5; if (isBillboard) { - #pragma glslify: import('@antv/g-shader-components/billboard.vert') + float rotation = 0.0; + bool isSizeAttenuation = false; + gl_Position = billboard(offset, rotation, isSizeAttenuation, u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); } else { gl_Position = project(vec4(offset, u_ZIndex, 1.0), u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); } diff --git a/packages/g-plugin-device-renderer/src/shader/text.vert b/packages/g-plugin-device-renderer/src/shader/text.vert index 42b02b94e..a833c93bb 100644 --- a/packages/g-plugin-device-renderer/src/shader/text.vert +++ b/packages/g-plugin-device-renderer/src/shader/text.vert @@ -3,6 +3,7 @@ #pragma glslify: import('@antv/g-shader-components/text.both.glsl') #pragma glslify: project = require('@antv/g-shader-components/project.vert') +#pragma glslify: billboard = require('@antv/g-shader-components/billboard.vert') layout(location = TEX) in vec2 a_Tex; layout(location = OFFSET) in vec2 a_Offset; @@ -10,23 +11,20 @@ layout(location = OFFSET) in vec2 a_Offset; out vec2 v_Uv; out float v_GammaScale; -bool isPerspectiveMatrix(mat4 m) { - return m[ 2 ][ 3 ] == - 1.0; -} - void main() { #pragma glslify: import('@antv/g-shader-components/batch.vert') v_Uv = a_Tex / u_SDFMapSize; float fontScale = u_FontSize / 24.; - bool isBillboard = a_StylePacked2.y > 0.5; - float sizeAttenuation = a_StylePacked2.z; vec2 bufferOffset = vec2(0.7, 2.0); vec2 offset = a_Offset * fontScale + bufferOffset; + bool isBillboard = a_StylePacked2.y > 0.5; if (isBillboard) { - #pragma glslify: import('@antv/g-shader-components/billboard.vert') + float rotation = a_StylePacked2.w; + bool isSizeAttenuation = a_StylePacked2.z > 0.5; + gl_Position = billboard(offset, rotation, isSizeAttenuation, u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); v_GammaScale = 1.0; } else { gl_Position = project(vec4((a_Offset) * fontScale + bufferOffset, u_ZIndex, 1.0), u_ProjectionMatrix, u_ViewMatrix, u_ModelMatrix); diff --git a/packages/g-plugin-device-renderer/src/utils/sample.ts b/packages/g-plugin-device-renderer/src/utils/sample.ts index 268c59775..3d521c5ed 100644 --- a/packages/g-plugin-device-renderer/src/utils/sample.ts +++ b/packages/g-plugin-device-renderer/src/utils/sample.ts @@ -13,8 +13,8 @@ export function quadCurveTo( points: number[], segmentNum?: number, ) { - const fromX = points[points.length - 2]; - const fromY = points[points.length - 1]; + const fromX = points[points.length - 3]; + const fromY = points[points.length - 3]; const n = segmentNum ?? @@ -36,6 +36,7 @@ export function quadCurveTo( points.push( xa + (cpX + (toX - cpX) * j - xa) * j, ya + (cpY + (toY - cpY) * j - ya) * j, + 0, ); } } @@ -50,10 +51,10 @@ export function bezierCurveTo( points: number[], segmentNum?: number, ): void { - const fromX = points[points.length - 2]; - const fromY = points[points.length - 1]; + const fromX = points[points.length - 3]; + const fromY = points[points.length - 2]; - points.length -= 2; + points.length -= 3; const n = segmentNum ?? @@ -70,7 +71,7 @@ export function bezierCurveTo( let t2 = 0; let t3 = 0; - points.push(fromX, fromY); + points.push(fromX, fromY, 0); for (let i = 1, j = 0; i <= n; ++i) { j = i / n; @@ -85,6 +86,7 @@ export function bezierCurveTo( points.push( dt3 * fromX + 3 * dt2 * j * cpX + 3 * dt * t2 * cpX2 + t3 * toX, dt3 * fromY + 3 * dt2 * j * cpY + 3 * dt * t2 * cpY2 + t3 * toY, + 0, ); } } diff --git a/packages/g-shader-components/billboard.vert b/packages/g-shader-components/billboard.vert index 68fe8d8d5..cbf773a6e 100644 --- a/packages/g-shader-components/billboard.vert +++ b/packages/g-shader-components/billboard.vert @@ -1,20 +1,27 @@ -vec4 mvPosition = u_ViewMatrix * u_ModelMatrix * vec4(0.0, 0.0, u_ZIndex, 1.0); -vec2 scale; -scale.x = length(vec3(u_ModelMatrix[0][0], u_ModelMatrix[0][1], u_ModelMatrix[0][2])); -scale.y = length(vec3(u_ModelMatrix[1][0], u_ModelMatrix[1][1], u_ModelMatrix[1][2])); +bool isPerspectiveMatrix(mat4 m) { + return m[2][3] == -1.0; +} -// if (sizeAttenuation < 0.5) { -// bool isPerspective = isPerspectiveMatrix( u_ProjectionMatrix ); -// if ( isPerspective ) scale *= - mvPosition.z; -// } +vec4 billboard(vec2 offset, float rotation, bool isSizeAttenuation, mat4 pm, mat4 vm, mat4 mm) { + vec4 mvPosition = vm * mm * vec4(0.0, 0.0, 0.0, 1.0); + vec2 scale; + scale.x = length(vec3(mm[0][0], mm[0][1], mm[0][2])); + scale.y = length(vec3(mm[1][0], mm[1][1], mm[1][2])); -vec2 alignedPosition = offset * scale; + if (isSizeAttenuation) { + bool isPerspective = isPerspectiveMatrix(pm); + if (isPerspective) { + scale *= -mvPosition.z / 250.0; + } + } -float rotation = 0.0; -vec2 rotatedPosition; -rotatedPosition.x = cos(rotation) * alignedPosition.x - sin(rotation) * alignedPosition.y; -rotatedPosition.y = sin(rotation) * alignedPosition.x + cos(rotation) * alignedPosition.y; + vec2 alignedPosition = offset * scale; + vec2 rotatedPosition; + rotatedPosition.x = cos(rotation) * alignedPosition.x - sin(rotation) * alignedPosition.y; + rotatedPosition.y = sin(rotation) * alignedPosition.x + cos(rotation) * alignedPosition.y; -mvPosition.xy += rotatedPosition; + mvPosition.xy += rotatedPosition; + return pm * mvPosition; +} -gl_Position = u_ProjectionMatrix * mvPosition; \ No newline at end of file +#pragma glslify: export(billboard) \ No newline at end of file diff --git a/site/docs/api/basic/circle.en.md b/site/docs/api/basic/circle.en.md index a77737ad0..1ec8e94df 100644 --- a/site/docs/api/basic/circle.en.md +++ b/site/docs/api/basic/circle.en.md @@ -5,7 +5,7 @@ order: 2 You can refer to the [\](https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/circle) element of SVG. -The following [example](/en/examples/shape#circle) draws a circle with a center of `[100, 100]` and a radius of `100`. +The following [example](/en/examples/shape/circle/#circle) draws a circle with a center of `[100, 100]` and a radius of `100`. ```js const circle = new Circle({ @@ -35,7 +35,7 @@ The default value is `center`. For details, see [DisplayObject's transformOrigin The x-axis coordinates of the center of the circle in the local coordinate system. -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cx +[https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cx](https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cx) | [Initial value](/en/api/css/css-properties-values-api#initial-value) | Applicable elements | [Inheritable](/en/api/css/inheritance) | Animatable | [Computed value](/en/api/css/css-properties-values-api#computed-value) | | -------------------------------------------------------------------- | ------------------- | -------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------- | @@ -45,7 +45,7 @@ https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cx The y-axis coordinates of the center of the circle in the local coordinate system. -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cy +[https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cy](https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cy) | [Initial value](/en/api/css/css-properties-values-api#initial-value) | Applicable elements | [Inheritable](/en/api/css/inheritance) | Animatable | [Computed value](/en/api/css/css-properties-values-api#computed-value) | | -------------------------------------------------------------------- | ------------------- | -------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------- | @@ -55,7 +55,7 @@ https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cy The radius of the circle. -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/r +[https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/r](https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/r) | [Initial value](/en/api/css/css-properties-values-api#initial-value) | Applicable elements | [Inheritable](/en/api/css/inheritance) | Animatable | [Computed value](/en/api/css/css-properties-values-api#computed-value) | | -------------------------------------------------------------------- | ------------------- | -------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------- | diff --git a/site/docs/api/basic/circle.zh.md b/site/docs/api/basic/circle.zh.md index ad112a5cd..d135aa63a 100644 --- a/site/docs/api/basic/circle.zh.md +++ b/site/docs/api/basic/circle.zh.md @@ -5,7 +5,7 @@ order: 2 可以参考 SVG 的 [\](https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/circle) 元素。 -如下 [示例](/zh/examples/shape#circle) 绘制了一个圆心在 `[100, 100]`,半径为 `100` 的圆: +如下 [示例](/zh/examples/shape/circle/#circle) 绘制了一个圆心在 `[100, 100]`,半径为 `100` 的圆: ```js const circle = new Circle({ @@ -35,7 +35,7 @@ const circle = new Circle({ 圆心在局部坐标系下的 x 轴坐标。 -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cx + | [初始值](/zh/api/css/css-properties-values-api#initial-value) | 适用元素 | [是否可继承](/zh/api/css/inheritance) | 是否支持动画 | [计算值](/zh/api/css/css-properties-values-api#computed-value) | | ------------------------------------------------------------- | -------- | ------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------- | @@ -45,7 +45,7 @@ https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cx 圆心在局部坐标系下的 y 轴坐标。 -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cy + | [初始值](/zh/api/css/css-properties-values-api#initial-value) | 适用元素 | [是否可继承](/zh/api/css/inheritance) | 是否支持动画 | [计算值](/zh/api/css/css-properties-values-api#computed-value) | | ------------------------------------------------------------- | -------- | ------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------- | @@ -55,7 +55,7 @@ https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cy 圆的半径。 -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/r + | [初始值](/zh/api/css/css-properties-values-api#initial-value) | 适用元素 | [是否可继承](/zh/api/css/inheritance) | 是否支持动画 | [计算值](/zh/api/css/css-properties-values-api#computed-value) | | ------------------------------------------------------------- | -------- | ------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------- | diff --git a/site/docs/api/basic/ellipse.en.md b/site/docs/api/basic/ellipse.en.md index 3d4cb1be4..8390485e4 100644 --- a/site/docs/api/basic/ellipse.en.md +++ b/site/docs/api/basic/ellipse.en.md @@ -5,7 +5,7 @@ order: 3 You can refer to the [\](https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/ellipse) element of SVG. -The following [example](/en/examples/shape#ellipse) draws an ellipse with a center of `[100, 100]` and a radius of `100`. +The following [example](/en/examples/shape/ellipse/#ellipse) draws an ellipse with a center of `[100, 100]` and a radius of `100`. ```js const ellipse = new Ellipse({ @@ -36,7 +36,7 @@ The default value is `center`. For details, see [DisplayObject's transformOrigin The x-axis coordinates of the center of the circle in the local coordinate system. -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cx + | [Initial value](/en/api/css/css-properties-values-api#initial-value) | Applicable elements | [Inheritable](/en/api/css/inheritance) | Animatable | [Computed value](/en/api/css/css-properties-values-api#computed-value) | | -------------------------------------------------------------------- | ------------------- | -------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------- | @@ -46,7 +46,7 @@ https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cx The y-axis coordinates of the center of the circle in the local coordinate system. -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cy + | [Initial value](/en/api/css/css-properties-values-api#initial-value) | Applicable elements | [Inheritable](/en/api/css/inheritance) | Animatable | [Computed value](/en/api/css/css-properties-values-api#computed-value) | | -------------------------------------------------------------------- | ------------------- | -------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------- | @@ -56,7 +56,7 @@ https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cy Horizontal radius of the ellipse -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/rx + | [Initial value](/en/api/css/css-properties-values-api#initial-value) | Applicable elements | [Inheritable](/en/api/css/inheritance) | Animatable | [Computed value](/en/api/css/css-properties-values-api#computed-value) | | -------------------------------------------------------------------- | ------------------- | -------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------- | @@ -66,7 +66,7 @@ https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/rx The vertical radius of the ellipse -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/ry + | [Initial value](/en/api/css/css-properties-values-api#initial-value) | Applicable elements | [Inheritable](/en/api/css/inheritance) | Animatable | [Computed value](/en/api/css/css-properties-values-api#computed-value) | | -------------------------------------------------------------------- | ------------------- | -------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------- | diff --git a/site/docs/api/basic/ellipse.zh.md b/site/docs/api/basic/ellipse.zh.md index 49e7757c5..6b9e1efa2 100644 --- a/site/docs/api/basic/ellipse.zh.md +++ b/site/docs/api/basic/ellipse.zh.md @@ -5,7 +5,7 @@ order: 3 可以参考 SVG 的 [\](https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/ellipse) 元素。 -如下 [示例](/zh/examples/shape#ellipse) 绘制了一个圆心在 `[100, 100]`,半径为 `100` 的椭圆: +如下 [示例](/zh/examples/shape/ellipse/#ellipse) 绘制了一个圆心在 `[100, 100]`,半径为 `100` 的椭圆: ```js const ellipse = new Ellipse({ @@ -36,7 +36,7 @@ const ellipse = new Ellipse({ 圆心在局部坐标系下的 x 轴坐标。 -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cx + | [初始值](/zh/api/css/css-properties-values-api#initial-value) | 适用元素 | [是否可继承](/zh/api/css/inheritance) | 是否支持动画 | [计算值](/zh/api/css/css-properties-values-api#computed-value) | | ------------------------------------------------------------- | -------- | ------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------- | @@ -46,7 +46,7 @@ https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cx 圆心在局部坐标系下的 y 轴坐标。 -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cy + | [初始值](/zh/api/css/css-properties-values-api#initial-value) | 适用元素 | [是否可继承](/zh/api/css/inheritance) | 是否支持动画 | [计算值](/zh/api/css/css-properties-values-api#computed-value) | | ------------------------------------------------------------- | -------- | ------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------- | @@ -56,7 +56,7 @@ https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/cy 椭圆的水平半径 -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/rx + | [初始值](/zh/api/css/css-properties-values-api#initial-value) | 适用元素 | [是否可继承](/zh/api/css/inheritance) | 是否支持动画 | [计算值](/zh/api/css/css-properties-values-api#computed-value) | | ------------------------------------------------------------- | -------- | ------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------- | @@ -66,7 +66,7 @@ https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/rx 椭圆的垂直半径 -https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/ry + | [初始值](/zh/api/css/css-properties-values-api#initial-value) | 适用元素 | [是否可继承](/zh/api/css/inheritance) | 是否支持动画 | [计算值](/zh/api/css/css-properties-values-api#computed-value) | | ------------------------------------------------------------- | -------- | ------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------- | diff --git a/site/docs/api/basic/html.en.md b/site/docs/api/basic/html.en.md index 5b0a2339e..d4c75fe5d 100644 --- a/site/docs/api/basic/html.en.md +++ b/site/docs/api/basic/html.en.md @@ -6,7 +6,7 @@ order: 9 Sometimes we need to add some HUDs to the canvas, e.g. Tooltip. In this case, the HTML + CSS presentation has the following advantages over using basic graphics. - Many native HTML components are difficult to draw, such as some input components: ``, `` `