Skip to content

Commit

Permalink
feat: add cache for drag
Browse files Browse the repository at this point in the history
  • Loading branch information
nonzzz committed Jan 13, 2025
1 parent e5ccf2d commit 3a31c03
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 15 deletions.
72 changes: 57 additions & 15 deletions src/primitives/component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { Box, Schedule } from '../etoile'
/* eslint-disable no-use-before-define */
import { Bitmap, Box, Canvas, Schedule } from '../etoile'
import type { Render, RenderViewportOptions } from '../etoile'
import type { DOMEventDefinition } from '../etoile/native/dom'
import { log } from '../etoile/native/log'
import { Matrix2D } from '../etoile/native/matrix'
import { createRoundBlock, createTitleText } from '../shared'
import type { RenderDecorator, Series } from './decorator'
import type { ExposedEventMethods, InternalEventDefinition } from './event'
Expand All @@ -15,15 +18,15 @@ export interface TreemapOptions {
data: Module[]
}

export type Using = 'decorator'
export type UseKind = 'decorator'

export interface App {
init: (el: HTMLElement) => void
dispose: () => void
setOptions: (options: TreemapOptions) => void
resize: () => void
// eslint-disable-next-line no-use-before-define
use: (using: Using, register: (app: TreemapLayout) => void) => void

use: (using: UseKind, register: (app: TreemapLayout) => void) => void
zoom: (id: string) => void
}

Expand All @@ -40,7 +43,7 @@ interface OptimalFontOptions {
* This interface isn't stable it might be remove at next few versions.
* If you want set custom decorator pls see 'presetDecorator' for details.
*/
// eslint-disable-next-line no-use-before-define

export type unstable_use = (app: TreemapLayout) => void

export function evaluateOptimalFontSize(
Expand Down Expand Up @@ -132,7 +135,7 @@ export class TreemapLayout extends Schedule<InternalEventDefinition> {
fontsCaches: Record<string, number>
ellispsisWidthCache: Record<string, number>
highlight: Highlight

renderCache: RenderCache
constructor(...args: ConstructorParameters<typeof Schedule>) {
super(...args)
this.data = []
Expand All @@ -143,6 +146,7 @@ export class TreemapLayout extends Schedule<InternalEventDefinition> {
this.fontsCaches = Object.create(null) as Record<string, number>
this.ellispsisWidthCache = Object.create(null) as Record<string, number>
this.highlight = new Highlight(this.to, { width: this.render.options.width, height: this.render.options.height })
this.renderCache = new RenderCache(this.render.options)
}

drawBackgroundNode(node: LayoutModule) {
Expand Down Expand Up @@ -197,18 +201,25 @@ export class TreemapLayout extends Schedule<InternalEventDefinition> {
reset(refresh = false) {
this.remove(this.bgBox, this.fgBox)
this.bgBox.destory()
for (const node of this.layoutNodes) {
this.drawBackgroundNode(node)
}
if (!this.fgBox.elements.length || refresh) {
this.render.ctx.textBaseline = 'middle'

if (this.renderCache.state) {
this.fgBox.destory()
this.bgBox.add(new Bitmap({ bitmap: this.renderCache.canvas }))
} else {
for (const node of this.layoutNodes) {
this.drawForegroundNode(node)
this.drawBackgroundNode(node)
}
if (!this.fgBox.elements.length || refresh) {
this.render.ctx.textBaseline = 'middle'
this.fgBox.destory()
for (const node of this.layoutNodes) {
this.drawForegroundNode(node)
}
} else {
this.fgBox = this.fgBox.clone()
}
} else {
this.fgBox = this.fgBox.clone()
}

this.add(this.bgBox, this.fgBox)
}

Expand Down Expand Up @@ -284,7 +295,7 @@ export function createTreemap() {
resize()
}

function use(key: Using, register: (decorator: TreemapLayout) => void) {
function use(key: UseKind, register: (decorator: TreemapLayout) => void) {
switch (key) {
case 'decorator':
uses.push((treemap: TreemapLayout) => register(treemap))
Expand All @@ -306,3 +317,34 @@ export function createTreemap() {
}

export type TreemapInstanceAPI = TreemapLayout['api']

// The following is my opinionated.
// For better performance, we desgin a cache system to store the render result.
// two step
// 1. draw current canvas into a cache canvas (offscreen canvas)
// 2. draw cache canvas into current canvas (note we should respect the dpi)
export class RenderCache extends Canvas {
key: string
private $memory: boolean
constructor(opts: RenderViewportOptions) {
super(opts)
this.key = 'render-cache'
this.$memory = false
}
get state() {
return this.$memory
}
flush(render: Render, matrix: Matrix2D) {
// this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
const { devicePixelRatio, width, height } = render.options
const w = width / devicePixelRatio
const h = height / devicePixelRatio
// applyCanvasTransform(this.ctx, matrix, devicePixelRatio)
this.ctx.drawImage(render.canvas, 0, 0, w, h)
this.$memory = true
}
destroy() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
this.$memory = false
}
}
6 changes: 6 additions & 0 deletions src/primitives/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ export class TreemapEvent extends DOMEvent {
this.state.dragX = metadata.native.offsetX
this.state.dragY = metadata.native.offsetY
this.state.forceDestroy = false
if (!ctx.treemap.renderCache.state) {
ctx.treemap.renderCache.flush(ctx.treemap.render, this.matrix)
}
}

private onmouseup(ctx: TreemapEventContext) {
Expand All @@ -265,6 +268,9 @@ export class TreemapEvent extends DOMEvent {
}

private onwheel(ctx: TreemapEventContext, metadata: DOMEventMetadata<'wheel'>) {
if (ctx.treemap.renderCache.state) {
ctx.treemap.renderCache.destroy()
}
const { native } = metadata
const { treemap } = ctx
// @ts-expect-error safe
Expand Down

0 comments on commit 3a31c03

Please sign in to comment.