perf: 子元素渲染性能

This commit is contained in:
unanmed 2025-01-12 12:03:53 +08:00
parent ba30d111a5
commit 7d8cbac246
6 changed files with 30 additions and 46 deletions

View File

@ -107,5 +107,5 @@ export function buildFont(
weight: number = 500, weight: number = 500,
italic: boolean = false italic: boolean = false
) { ) {
return `${italic ? 'italic ' : ''}${weight} ${size}px ${family}`; return `${italic ? 'italic ' : ''}${weight} ${size}px "${family}"`;
} }

View File

@ -36,13 +36,9 @@ export class Container<E extends EContainerEvent = EContainerEvent>
canvas: MotaOffscreenCanvas2D, canvas: MotaOffscreenCanvas2D,
transform: Transform transform: Transform
): void { ): void {
const { ctx } = canvas;
this.sortedChildren.forEach(v => { this.sortedChildren.forEach(v => {
if (v.hidden) return; if (v.hidden) return;
ctx.save();
v.renderContent(canvas, transform); v.renderContent(canvas, transform);
ctx.restore();
}); });
} }

View File

@ -140,8 +140,6 @@ interface IRenderVueSupport {
} }
export interface ERenderItemEvent { export interface ERenderItemEvent {
beforeUpdate: [item?: RenderItem];
afterUpdate: [item?: RenderItem];
beforeRender: [transform: Transform]; beforeRender: [transform: Transform];
afterRender: [transform: Transform]; afterRender: [transform: Transform];
destroy: []; destroy: [];
@ -344,7 +342,7 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
canvas.ctx.translate(ax, ay); canvas.ctx.translate(ax, ay);
this.render(canvas, tran); this.render(canvas, tran);
} }
canvas.ctx.restore(); ctx.restore();
this.emit('afterRender', transform); this.emit('afterRender', transform);
} }
@ -389,6 +387,7 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
* 使 * 使
*/ */
getAbsolutePosition(): LocArr { getAbsolutePosition(): LocArr {
if (this.type === 'absolute') return [0, 0];
const { x, y } = this.transform; const { x, y } = this.transform;
if (!this.parent) return [x, y]; if (!this.parent) return [x, y];
else { else {
@ -400,13 +399,15 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
setAnchor(x: number, y: number): void { setAnchor(x: number, y: number): void {
this.anchorX = x; this.anchorX = x;
this.anchorY = y; this.anchorY = y;
this.update();
} }
update(item: RenderItem<any> = this, force: boolean = false): void { update(item: RenderItem<any> = this): void {
if ((this.needUpdate || this.hidden) && !force) return; if (this.needUpdate) return;
this.needUpdate = true; this.needUpdate = true;
this.cacheDirty = true; this.cacheDirty = true;
this.parent?.update(item, force); if (this.hidden) return;
this.parent?.update(item);
} }
setHD(hd: boolean): void { setHD(hd: boolean): void {
@ -475,7 +476,7 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
hide() { hide() {
if (this.hidden) return; if (this.hidden) return;
this.hidden = true; this.hidden = true;
this.update(this, true); this.update(this);
} }
/** /**
@ -484,13 +485,13 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
show() { show() {
if (!this.hidden) return; if (!this.hidden) return;
this.hidden = false; this.hidden = false;
this.refreshAllChildren(true); this.refreshAllChildren();
} }
/** /**
* *
*/ */
refreshAllChildren(force: boolean = false) { refreshAllChildren() {
if (this.children.size > 0) { if (this.children.size > 0) {
const stack: RenderItem[] = [this]; const stack: RenderItem[] = [this];
while (stack.length > 0) { while (stack.length > 0) {
@ -500,7 +501,7 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
item.children.forEach(v => stack.push(v)); item.children.forEach(v => stack.push(v));
} }
} }
this.update(this, force); this.update(this);
} }
/** /**
@ -523,6 +524,7 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
/** /**
* *
* @returns
*/ */
remove(): boolean { remove(): boolean {
if (!this.parent) return false; if (!this.parent) return false;

View File

@ -2,20 +2,10 @@ import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
import { Container, EContainerEvent } from '../container'; import { Container, EContainerEvent } from '../container';
import { Sprite } from '../sprite'; import { Sprite } from '../sprite';
import { TimingFn } from 'mutate-animate'; import { TimingFn } from 'mutate-animate';
import { import { IAnimateFrame, renderEmits, RenderItem } from '../item';
ERenderItemEvent,
IAnimateFrame,
renderEmits,
RenderItem
} from '../item';
import { logger } from '@/core/common/logger'; import { logger } from '@/core/common/logger';
import { RenderableData, texture } from '../cache'; import { RenderableData, texture } from '../cache';
import { import { BlockCacher, CanvasCacheItem, ICanvasCacheItem } from './block';
BlockCacher,
CanvasCacheItem,
IBlockCacheable,
ICanvasCacheItem
} from './block';
import { Transform } from '../transform'; import { Transform } from '../transform';
import { LayerFloorBinder, LayerGroupFloorBinder } from './floor'; import { LayerFloorBinder, LayerGroupFloorBinder } from './floor';
import { RenderAdapter } from '../adapter'; import { RenderAdapter } from '../adapter';
@ -148,13 +138,9 @@ export class LayerGroup
} }
protected render(canvas: MotaOffscreenCanvas2D): void { protected render(canvas: MotaOffscreenCanvas2D): void {
const { ctx } = canvas;
this.sortedChildren.forEach(v => { this.sortedChildren.forEach(v => {
if (v.hidden) return; if (v.hidden) return;
ctx.save();
v.renderContent(canvas, this.camera); v.renderContent(canvas, this.camera);
ctx.restore();
}); });
} }
@ -362,13 +348,14 @@ export class LayerGroup
if (!this.assertType(nextValue, 'number', key)) return; if (!this.assertType(nextValue, 'number', key)) return;
this.setBlockSize(nextValue); this.setBlockSize(nextValue);
return; return;
case 'floorId': case 'floorId': {
if (!this.assertType(nextValue, 'number', key)) return; if (!this.assertType(nextValue, 'number', key)) return;
const binder = this.getExtends('floor-binder'); const binder = this.getExtends('floor-binder');
if (binder instanceof LayerGroupFloorBinder) { if (binder instanceof LayerGroupFloorBinder) {
binder.bindFloor(nextValue); binder.bindFloor(nextValue);
} }
return; return;
}
case 'camera': case 'camera':
if (!this.assertType(nextValue, Camera, key)) return; if (!this.assertType(nextValue, Camera, key)) return;
this.camera = nextValue; this.camera = nextValue;
@ -1376,7 +1363,7 @@ export class Layer extends Container<ELayerEvent> {
// 删除原始位置的图块 // 删除原始位置的图块
this.putRenderData([0], 1, fx, fy); this.putRenderData([0], 1, fx, fy);
let nowZ = fy; const nowZ = fy;
const startTime = Date.now(); const startTime = Date.now();
return new Promise<void>(resolve => { return new Promise<void>(resolve => {
this.delegateTicker( this.delegateTicker(
@ -1423,7 +1410,7 @@ export class Layer extends Container<ELayerEvent> {
time: number, time: number,
relative: boolean = true relative: boolean = true
) { ) {
let nowZ = y; const nowZ = y;
const startTime = Date.now(); const startTime = Date.now();
return new Promise<void>(resolve => { return new Promise<void>(resolve => {
this.delegateTicker( this.delegateTicker(
@ -1459,7 +1446,7 @@ export class Layer extends Container<ELayerEvent> {
parentComponent?: ComponentInternalInstance | null parentComponent?: ComponentInternalInstance | null
): void { ): void {
switch (key) { switch (key) {
case 'layer': case 'layer': {
if (!this.assertType(nextValue, 'string', key)) return; if (!this.assertType(nextValue, 'string', key)) return;
const parent = this.parent; const parent = this.parent;
if (parent instanceof LayerGroup) { if (parent instanceof LayerGroup) {
@ -1471,6 +1458,7 @@ export class Layer extends Container<ELayerEvent> {
} }
this.update(); this.update();
return; return;
}
case 'cellSize': case 'cellSize':
if (!this.assertType(nextValue, 'number', key)) return; if (!this.assertType(nextValue, 'number', key)) return;
this.setCellSize(nextValue); this.setCellSize(nextValue);

View File

@ -31,21 +31,19 @@ export class MotaRenderer extends Container {
MotaRenderer.list.set(id, this); MotaRenderer.list.set(id, this);
} }
update(item: RenderItem = this) { update(_item: RenderItem = this) {
if (this.needUpdate || this.hidden) return; if (this.needUpdate || this.hidden) return;
this.needUpdate = true; this.needUpdate = true;
this.requestRenderFrame(() => { this.requestRenderFrame(() => {
this.refresh(item); this.refresh();
}); });
} }
protected refresh(item: RenderItem = this): void { protected refresh(): void {
if (!this.needUpdate) return; if (!this.needUpdate) return;
this.needUpdate = false; this.needUpdate = false;
this.emit('beforeUpdate', item);
this.target.clear(); this.target.clear();
this.renderContent(this.target, Transform.identity); this.renderContent(this.target, Transform.identity);
this.emit('afterUpdate', item);
} }
/** /**

View File

@ -1,8 +1,8 @@
import { Ticker, TimingFn } from 'mutate-animate'; import { TimingFn } from 'mutate-animate';
import { RenderAdapter } from './adapter'; import { RenderAdapter } from './adapter';
import { FloorViewport } from './preset/viewport'; import { FloorViewport } from './preset/viewport';
import { JSX } from 'vue/jsx-runtime'; import { JSX } from 'vue/jsx-runtime';
import { Component, DefineComponent, DefineSetupFnComponent } from 'vue'; import { DefineComponent, DefineSetupFnComponent } from 'vue';
export type Props< export type Props<
T extends T extends