From 96c8c0f3e3aa2db2160153051b713b26f0464e1e Mon Sep 17 00:00:00 2001 From: jinzisen Date: Fri, 9 Jan 2026 18:23:20 +0800 Subject: [PATCH 1/3] feat(dpr): able to update dpr by resize --- src/PainterBase.ts | 2 +- src/canvas/Layer.ts | 24 ++++++++++++++++++++++-- src/canvas/Painter.ts | 14 ++++++++++---- src/zrender.ts | 3 ++- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/PainterBase.ts b/src/PainterBase.ts index fa42c37ad..68a936c83 100644 --- a/src/PainterBase.ts +++ b/src/PainterBase.ts @@ -19,7 +19,7 @@ export interface PainterBase { // constructor(dom: HTMLElement, storage: Storage, opts: PainterOption, id: number): void - resize(width?: number | string, height?: number | string): void + resize(width?: number | string, height?: number | string, devicePixelRatio?: number): void refresh(): void clear(): void diff --git a/src/canvas/Layer.ts b/src/canvas/Layer.ts index c887d884b..7e6447282 100644 --- a/src/canvas/Layer.ts +++ b/src/canvas/Layer.ts @@ -354,8 +354,28 @@ export default class Layer extends Eventful { return (this._paintRects || []).slice(); } - resize(width: number, height: number) { - const dpr = this.dpr; + /** + * Update dpr and keep context markers in sync. + * Returns true if dpr changed. + */ + updateDpr(dpr?: number): boolean { + if (dpr != null && dpr !== this.dpr) { + this.dpr = dpr; + // Keep a custom dpr marker in sync for downstream brush logic. + if (this.ctx) { + (this.ctx as ZRCanvasRenderingContext).dpr = dpr; + } + if (this.ctxBack) { + (this.ctxBack as ZRCanvasRenderingContext).dpr = dpr; + } + return true; + } + return false; + } + + resize(width: number, height: number, dpr?: number) { + this.updateDpr(dpr); + dpr = this.dpr; const dom = this.dom; const domStyle = dom.style; diff --git a/src/canvas/Painter.ts b/src/canvas/Painter.ts index 568885692..f3a11ba6f 100644 --- a/src/canvas/Painter.ts +++ b/src/canvas/Painter.ts @@ -838,8 +838,14 @@ export default class CanvasPainter implements PainterBase { */ resize( width?: number | string, - height?: number | string + height?: number | string, + devicePixelRatio?: number ) { + const dprChanged = devicePixelRatio != null && devicePixelRatio !== this.dpr; + if (dprChanged) { + this.dpr = devicePixelRatio; + } + if (!this._domRoot.style) { // Maybe in node or worker if (width == null || height == null) { return; @@ -848,7 +854,7 @@ export default class CanvasPainter implements PainterBase { this._width = width as number; this._height = height as number; - this.getLayer(CANVAS_ZLEVEL).resize(width as number, height as number); + this.getLayer(CANVAS_ZLEVEL).resize(width as number, height as number, this.dpr); } else { const domRoot = this._domRoot; @@ -867,13 +873,13 @@ export default class CanvasPainter implements PainterBase { domRoot.style.display = ''; // 优化没有实际改变的resize - if (this._width !== width || height !== this._height) { + if (this._width !== width || height !== this._height || dprChanged) { domRoot.style.width = width + 'px'; domRoot.style.height = height + 'px'; for (let id in this._layers) { if (this._layers.hasOwnProperty(id)) { - this._layers[id].resize(width, height); + this._layers[id].resize(width, height, this.dpr); } } diff --git a/src/zrender.ts b/src/zrender.ts index f2a382376..c6555626d 100644 --- a/src/zrender.ts +++ b/src/zrender.ts @@ -338,12 +338,13 @@ class ZRender { resize(opts?: { width?: number| string height?: number | string + devicePixelRatio?: number }) { if (this._disposed) { return; } opts = opts || {}; - this.painter.resize(opts.width, opts.height); + this.painter.resize(opts.width, opts.height, opts.devicePixelRatio); this.handler.resize(); } From 5a52347e793a2eeffcc9eaed5dd4538087755eac Mon Sep 17 00:00:00 2001 From: jinzisen Date: Fri, 30 Jan 2026 17:33:34 +0800 Subject: [PATCH 2/3] get default dpr when canvas resize --- src/canvas/Painter.ts | 13 ++++++++++--- src/config.ts | 22 ++++++++++++---------- src/core/PathProxy.ts | 2 +- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/canvas/Painter.ts b/src/canvas/Painter.ts index f3a11ba6f..86f662ea3 100644 --- a/src/canvas/Painter.ts +++ b/src/canvas/Painter.ts @@ -1,4 +1,4 @@ -import {devicePixelRatio} from '../config'; +import { devicePixelRatio, getDevicePixelRatio } from '../config'; import * as util from '../core/util'; import Layer, { LayerConfig } from './Layer'; import requestAnimationFrame from '../animation/requestAnimationFrame'; @@ -835,15 +835,22 @@ export default class CanvasPainter implements PainterBase { /** * 区域大小变化后重绘 + * @param width 宽度 + * @param height 高度 + * @param devicePixelRatio 设备像素比,如果未指定,则自动获取当前设备像素比 */ resize( width?: number | string, height?: number | string, devicePixelRatio?: number ) { - const dprChanged = devicePixelRatio != null && devicePixelRatio !== this.dpr; + const newDpr = devicePixelRatio != null + ? devicePixelRatio + : getDevicePixelRatio(); + + const dprChanged = newDpr !== this.dpr; if (dprChanged) { - this.dpr = devicePixelRatio; + this.dpr = newDpr; } if (!this._domRoot.style) { // Maybe in node or worker diff --git a/src/config.ts b/src/config.ts index fe7528abe..347521152 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,14 +1,16 @@ import env from './core/env'; -let dpr = 1; - -// If in browser environment -if (env.hasGlobalWindow) { - dpr = Math.max( - window.devicePixelRatio - || (window.screen && (window.screen as any).deviceXDPI / (window.screen as any).logicalXDPI) - || 1, 1 - ); +export function getDevicePixelRatio(): number { + let dpr = 1; + + // If in browser environment + if (env.hasGlobalWindow) { + dpr = window.devicePixelRatio + || (window.screen && (window.screen as any).deviceXDPI / (window.screen as any).logicalXDPI) + || 1; + } + + return dpr; } /** @@ -19,7 +21,7 @@ if (env.hasGlobalWindow) { export const debugMode = 0; // retina 屏幕优化 -export const devicePixelRatio = dpr; +export const devicePixelRatio = getDevicePixelRatio(); /** diff --git a/src/core/PathProxy.ts b/src/core/PathProxy.ts index a6af1151c..1139df5c9 100644 --- a/src/core/PathProxy.ts +++ b/src/core/PathProxy.ts @@ -9,7 +9,6 @@ import * as vec2 from './vector'; import BoundingRect from './BoundingRect'; -import {devicePixelRatio as dpr} from '../config'; import { fromLine, fromCubic, fromQuadratic, fromArc } from './bbox'; import { cubicLength, cubicSubdivide, quadraticLength, quadraticSubdivide } from './curve'; @@ -177,6 +176,7 @@ export default class PathProxy { // Compat. Previously there is no segmentIgnoreThreshold. segmentIgnoreThreshold = segmentIgnoreThreshold || 0; if (segmentIgnoreThreshold > 0) { + const dpr = this.dpr || 1; this._ux = mathAbs(segmentIgnoreThreshold / dpr / sx) || 0; this._uy = mathAbs(segmentIgnoreThreshold / dpr / sy) || 0; } From b143ab682209cb633c82c1c4d197983e5dcff685 Mon Sep 17 00:00:00 2001 From: jinzisen Date: Mon, 2 Feb 2026 11:27:08 +0800 Subject: [PATCH 3/3] fix: cr --- src/canvas/Layer.ts | 3 +-- src/canvas/Painter.ts | 9 +++------ src/config.ts | 4 ---- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/canvas/Layer.ts b/src/canvas/Layer.ts index 7e6447282..1aab0b595 100644 --- a/src/canvas/Layer.ts +++ b/src/canvas/Layer.ts @@ -1,5 +1,4 @@ import * as util from '../core/util'; -import {devicePixelRatio} from '../config'; import { ImagePatternObject } from '../graphic/Pattern'; import CanvasPainter from './Painter'; import { GradientObject, InnerGradientObject } from '../graphic/Gradient'; @@ -108,7 +107,7 @@ export default class Layer extends Eventful { super(); let dom; - dpr = dpr || devicePixelRatio; + dpr = dpr || 1; if (typeof id === 'string') { dom = createDom(id, painter, dpr); } diff --git a/src/canvas/Painter.ts b/src/canvas/Painter.ts index 86f662ea3..34e97d749 100644 --- a/src/canvas/Painter.ts +++ b/src/canvas/Painter.ts @@ -1,4 +1,4 @@ -import { devicePixelRatio, getDevicePixelRatio } from '../config'; +import { getDevicePixelRatio } from '../config'; import * as util from '../core/util'; import Layer, { LayerConfig } from './Layer'; import requestAnimationFrame from '../animation/requestAnimationFrame'; @@ -122,7 +122,7 @@ export default class CanvasPainter implements PainterBase { /** * @type {number} */ - this.dpr = opts.devicePixelRatio || devicePixelRatio; + this.dpr = opts.devicePixelRatio || getDevicePixelRatio(); /** * @type {boolean} * @private @@ -175,7 +175,6 @@ export default class CanvasPainter implements PainterBase { // TODO sting? height = opts.height as number; } - this.dpr = opts.devicePixelRatio || 1; // Use canvas width and height directly rootCanvas.width = width * this.dpr; @@ -844,9 +843,7 @@ export default class CanvasPainter implements PainterBase { height?: number | string, devicePixelRatio?: number ) { - const newDpr = devicePixelRatio != null - ? devicePixelRatio - : getDevicePixelRatio(); + const newDpr = devicePixelRatio || getDevicePixelRatio(); const dprChanged = newDpr !== this.dpr; if (dprChanged) { diff --git a/src/config.ts b/src/config.ts index 347521152..d86628526 100644 --- a/src/config.ts +++ b/src/config.ts @@ -20,10 +20,6 @@ export function getDevicePixelRatio(): number { */ export const debugMode = 0; -// retina 屏幕优化 -export const devicePixelRatio = getDevicePixelRatio(); - - /** * Determine when to turn on dark mode based on the luminance of backgroundColor */