Skip to content

Commit

Permalink
feat: allow changing DPR at runtime #1143
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoiver committed Sep 28, 2022
1 parent eb45a78 commit 1b954b7
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 32 deletions.
20 changes: 14 additions & 6 deletions packages/g-canvas/src/Canvas2DContextService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { CanvasLike, DataURLOptions } from '@antv/g-lite';
import { RenderingContext, RenderReason } from '@antv/g-lite';
import {
CanvasConfig,
ContextService,
Expand All @@ -19,10 +20,13 @@ export class Canvas2DContextService implements ContextService<CanvasRenderingCon
constructor(
@inject(CanvasConfig)
private canvasConfig: CanvasConfig,

@inject(RenderingContext)
private renderingContext: RenderingContext,
) {}

async init() {
const { container, canvas, devicePixelRatio } = this.canvasConfig;
const { container, canvas } = this.canvasConfig;

if (canvas) {
this.$canvas = canvas;
Expand All @@ -49,11 +53,6 @@ export class Canvas2DContextService implements ContextService<CanvasRenderingCon
}

this.context = this.$canvas.getContext('2d');
// use user-defined dpr first
let dpr = devicePixelRatio || (isBrowser && window.devicePixelRatio) || 1;
dpr = dpr >= 1 ? Math.ceil(dpr) : 1;
this.dpr = dpr;

this.resize(this.canvasConfig.width, this.canvasConfig.height);
}

Expand Down Expand Up @@ -85,6 +84,13 @@ export class Canvas2DContextService implements ContextService<CanvasRenderingCon
}

resize(width: number, height: number) {
const { devicePixelRatio } = this.canvasConfig;

// use user-defined dpr first
let dpr = devicePixelRatio || (isBrowser && window.devicePixelRatio) || 1;
dpr = dpr >= 1 ? Math.ceil(dpr) : 1;
this.dpr = dpr;

if (this.$canvas) {
// set canvas width & height
this.$canvas.width = this.dpr * width;
Expand All @@ -98,6 +104,8 @@ export class Canvas2DContextService implements ContextService<CanvasRenderingCon
// @see https://www.html5rocks.com/en/tutorials/canvas/hidpi/
// this.context.scale(dpr, dpr);
}

this.renderingContext.renderReasons.add(RenderReason.CAMERA_CHANGED);
}

applyCursorStyle(cursor: string) {
Expand Down
2 changes: 1 addition & 1 deletion packages/g-lite/src/css/cssom/CSSGradientValue.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CSSKeywordValue } from './CSSKeywordValue';
import type { CSSKeywordValue } from './CSSKeywordValue';
import type { CSSUnitValue } from './CSSNumericValue';
import { CSSStyleValue, CSSStyleValueType } from './CSSStyleValue';
import type { Nested, ParenLess } from './types';
Expand Down
5 changes: 3 additions & 2 deletions packages/g-lite/src/css/parser/gradient.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { isNil, isString, memoize } from '@antv/util';
import type { AngularNode, ColorStop, DirectionalNode, PositionNode } from '../../utils';
import { colorStopToString, parseGradient as parse } from '../../utils';
import { CSSKeywordValue, CSSUnitValue, LinearColorStop, Odeg, RadialGradient } from '../cssom';
import type { CSSKeywordValue, CSSUnitValue, LinearColorStop, RadialGradient } from '../cssom';
import { Odeg } from '../cssom';
import { CSSGradientValue, GradientType } from '../cssom';
import { getOrCreateKeyword, getOrCreateUnitValue } from '../CSSStyleValuePool';
import { Pattern } from './color';
import type { Pattern } from './color';

const regexLG = /^l\s*\(\s*([\d.]+)\s*\)\s*(.*)/i;
const regexRG = /^r\s*\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*\)\s*(.*)/i;
Expand Down
4 changes: 4 additions & 0 deletions packages/g-lite/src/dom/Element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import { MutationEvent } from './MutationEvent';
import { Node } from './Node';

let entityCounter = 0;
export function resetEntityCounter() {
entityCounter = 0;
}

// let this.sceneGraphService: SceneGraphService;
const childInsertedEvent = new CustomEvent(ElementEvent.CHILD_INSERTED, {
child: null,
Expand Down
5 changes: 3 additions & 2 deletions packages/g-lottie-player/src/LottieAnimation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { BaseStyleProps, Canvas, DisplayObject, PointLike, Rectangle } from '@antv/g-lite';
import { definedProps, Ellipse, Group, Rect, Path, Shape } from '@antv/g-lite';
import type { PathArray } from '@antv/util';
import { mat4, quat, vec3 } from 'gl-matrix';
import type {
CustomElementOption,
KeyframeAnimation,
Expand Down Expand Up @@ -219,6 +218,7 @@ export class LottieAnimation {
);

if (existedKeyframe) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { offset, easing: e = 'linear', ...rest } = currentKeyframe;

// merge interpolated properties
Expand All @@ -236,7 +236,8 @@ export class LottieAnimation {

// console.log(mergedKeyframesOptions);

const animations = mergedKeyframesOptions.map(([formattedKeyframes, options]) => {
// TODO: return animations
mergedKeyframesOptions.map(([formattedKeyframes, options]) => {
// format interpolated properties, e.g. scaleX -> transform
this.formatKeyframes(formattedKeyframes, child);
return child.animate(formattedKeyframes, options);
Expand Down
4 changes: 2 additions & 2 deletions packages/g-plugin-canvas-renderer/src/CanvasRendererPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,6 @@ export class CanvasRendererPlugin implements RenderingPlugin {
const { width, height } = this.canvasConfig;
const context = this.contextService.getContext();
this.clearRect(context, 0, 0, width * dpr, height * dpr);

mat4.fromScaling(this.dprMatrix, vec3.fromValues(dpr, dpr, 1));
});

renderingService.hooks.destroy.tap(CanvasRendererPlugin.tag, () => {
Expand Down Expand Up @@ -193,6 +191,8 @@ export class CanvasRendererPlugin implements RenderingPlugin {
renderingService.hooks.endFrame.tap(CanvasRendererPlugin.tag, () => {
const context = this.contextService.getContext();
// clear & clip dirty rectangle
const dpr = this.contextService.getDPR();
mat4.fromScaling(this.dprMatrix, vec3.fromValues(dpr, dpr, 1));
mat4.multiply(this.vpMatrix, this.dprMatrix, this.camera.getOrthoMatrix());

if (this.clearFullScreen) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {
import type {
ICamera,
CSSGradientValue,
DataURLOptions,
Expand All @@ -10,8 +10,8 @@ import {
RadialGradient,
RenderingPlugin,
RenderingService,
UnitType,
} from '@antv/g-lite';
import { UnitType } from '@antv/g-lite';
import {
CanvasConfig,
computeLinearGradient,
Expand Down
3 changes: 2 additions & 1 deletion packages/g-plugin-image-loader/src/ImagePool.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { LinearGradient, Pattern, RadialGradient, UnitType } from '@antv/g-lite';
import type { LinearGradient, Pattern, RadialGradient } from '@antv/g-lite';
import { UnitType } from '@antv/g-lite';
import {
CanvasConfig,
computeLinearGradient,
Expand Down
7 changes: 5 additions & 2 deletions packages/g-svg/src/SVGContextService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { DataURLOptions } from '@antv/g-lite';
import { isBrowser } from '@antv/g-lite';
import { CanvasConfig, ContextService, inject, singleton } from '@antv/g-lite';
import { createSVGElement } from '@antv/g-plugin-svg-renderer';
import { isString } from '@antv/util';
Expand All @@ -15,7 +16,7 @@ export class SVGContextService implements ContextService<SVGElement> {
) {}

async init() {
const { container, document: doc } = this.canvasConfig;
const { container, document: doc, devicePixelRatio } = this.canvasConfig;

// create container
this.$container = isString(container) ? (doc || document).getElementById(container) : container;
Expand All @@ -32,7 +33,8 @@ export class SVGContextService implements ContextService<SVGElement> {
this.$namespace = $namespace;
}

let dpr = window.devicePixelRatio || 1;
// use user-defined dpr first
let dpr = devicePixelRatio || (isBrowser && window.devicePixelRatio) || 1;
dpr = dpr >= 1 ? Math.ceil(dpr) : 1;
this.dpr = dpr;
}
Expand Down Expand Up @@ -62,6 +64,7 @@ export class SVGContextService implements ContextService<SVGElement> {
}

resize(width: number, height: number) {
// SVG should ignore DPR
if (this.$namespace) {
this.$namespace.setAttribute('width', `${width}`);
this.$namespace.setAttribute('height', `${height}`);
Expand Down
13 changes: 8 additions & 5 deletions packages/g-webgl/src/WebGLContextService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class WebGLContextService implements ContextService<WebGLRenderingContext
) {}

async init() {
const { container, canvas, devicePixelRatio } = this.canvasConfig;
const { container, canvas } = this.canvasConfig;

if (canvas) {
this.$canvas = canvas;
Expand All @@ -51,10 +51,7 @@ export class WebGLContextService implements ContextService<WebGLRenderingContext
}
}

// use user-defined dpr first
let dpr = devicePixelRatio || (isBrowser && window.devicePixelRatio) || 1;
dpr = dpr >= 1 ? Math.ceil(dpr) : 1;
this.dpr = dpr;
this.resize(this.canvasConfig.width, this.canvasConfig.height);
}

getDomElement() {
Expand Down Expand Up @@ -83,6 +80,12 @@ export class WebGLContextService implements ContextService<WebGLRenderingContext
}

resize(width: number, height: number) {
// use user-defined dpr first
const { devicePixelRatio } = this.canvasConfig;
let dpr = devicePixelRatio || (isBrowser && window.devicePixelRatio) || 1;
dpr = dpr >= 1 ? Math.ceil(dpr) : 1;
this.dpr = dpr;

if (this.$canvas) {
const dpr = this.getDPR();

Expand Down
13 changes: 8 additions & 5 deletions packages/g-webgpu/src/WebGPUContextService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class WebGPUContextService implements ContextService<GPUCanvasContext> {
) {}

async init() {
const { container, canvas, devicePixelRatio } = this.canvasConfig;
const { container, canvas } = this.canvasConfig;

if (canvas) {
this.$canvas = canvas;
Expand All @@ -51,10 +51,7 @@ export class WebGPUContextService implements ContextService<GPUCanvasContext> {
}
}

// use user-defined dpr first
let dpr = devicePixelRatio || (isBrowser && window.devicePixelRatio) || 1;
dpr = dpr >= 1 ? Math.ceil(dpr) : 1;
this.dpr = dpr;
this.resize(this.canvasConfig.width, this.canvasConfig.height);
}

getDomElement() {
Expand All @@ -81,6 +78,12 @@ export class WebGPUContextService implements ContextService<GPUCanvasContext> {
}

resize(width: number, height: number) {
// use user-defined dpr first
const { devicePixelRatio } = this.canvasConfig;
let dpr = devicePixelRatio || (isBrowser && window.devicePixelRatio) || 1;
dpr = dpr >= 1 ? Math.ceil(dpr) : 1;
this.dpr = dpr;

if (this.$canvas) {
const dpr = this.getDPR();

Expand Down
16 changes: 15 additions & 1 deletion packages/g/src/__tests__/dom/element.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Element, Node } from '@antv/g';
import { Element, Node, resetEntityCounter } from '@antv/g';
import chai, { expect } from 'chai';
// @ts-ignore
import chaiAlmost from 'chai-almost';
Expand All @@ -9,6 +9,20 @@ chai.use(chaiAlmost());
chai.use(sinonChai);

describe('DOM Element API', () => {
it('should reset EntityCounter', () => {
resetEntityCounter();
let group1 = new Element();
let group2 = new Element();
expect(group1.entity).to.eqls(0);
expect(group2.entity).to.eqls(1);

resetEntityCounter();
group1 = new Element();
group2 = new Element();
expect(group1.entity).to.eqls(0);
expect(group2.entity).to.eqls(1);
});

it('should appendChild with before & after correctly', () => {
const group1 = new Element();
const group2 = new Element();
Expand Down
21 changes: 18 additions & 3 deletions packages/site/examples/canvas/demo/resize.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Canvas, CanvasEvent, Circle } from '@antv/g';
import { Renderer as CanvasRenderer } from '@antv/g-canvas';
import { Renderer as SVGRenderer } from '@antv/g-svg';
import { Renderer as WebGLRenderer } from '@antv/g-webgl';
import { Renderer as CanvaskitRenderer } from '@antv/g-canvaskit';
import * as lil from 'lil-gui';
import React, { useEffect } from 'react';
import ReactDOM from 'react-dom';
Expand Down Expand Up @@ -32,6 +33,12 @@ const App = function MultiWorld() {
const svgRenderer2 = new SVGRenderer();
const webglRenderer1 = new WebGLRenderer();
const webglRenderer2 = new WebGLRenderer();
const canvaskitRenderer1 = new CanvaskitRenderer({
wasmDir: '/',
});
const canvaskitRenderer2 = new CanvaskitRenderer({
wasmDir: '/',
});

// create a canvas
canvas1 = new Canvas({
Expand Down Expand Up @@ -91,25 +98,33 @@ const App = function MultiWorld() {
const rendererFolder = gui.addFolder('renderer');
const rendererConfig = {
renderer: 'canvas',
devicePixelRatio: window.devicePixelRatio,
};
rendererFolder
.add(rendererConfig, 'renderer', ['canvas', 'webgl', 'svg'])
.add(rendererConfig, 'renderer', ['canvas', 'webgl', 'svg', 'canvaskit'])
.onChange((renderer) => {
canvas1.setRenderer(
renderer === 'canvas'
? canvasRenderer1
: renderer === 'webgl'
? webglRenderer1
: svgRenderer1,
: renderer === 'svg'
? svgRenderer1
: canvaskitRenderer1,
);
canvas2.setRenderer(
renderer === 'canvas'
? canvasRenderer2
: renderer === 'webgl'
? webglRenderer2
: svgRenderer2,
: renderer === 'svg'
? svgRenderer2
: canvaskitRenderer2,
);
});
rendererFolder.add(rendererConfig, 'devicePixelRatio', 0.5, 5).onChange((dpr) => {
canvas1.getConfig().devicePixelRatio = dpr;
});
rendererFolder.open();
});

Expand Down

0 comments on commit 1b954b7

Please sign in to comment.