Last active
August 20, 2023 17:12
-
-
Save noih/023d57ba27cc856273c261c5a079f3c7 to your computer and use it in GitHub Desktop.
PixiJS v7 - Prevent text flickering after scaling and achieve smoother rendering using batch updates
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* PixiJS v7 - Prevent text flickering after scaling and achieve smoother rendering using batch updates. | |
* | |
* @version 2 | |
* @author noih.dev | |
* @since 2023-08-21 | |
* @link https://codesandbox.io/s/batch-update-text-7qxktt?file=/src/index.mjs:0-3081 | |
*/ | |
import * as PIXI from 'pixi.js' | |
import { Viewport } from 'pixi-viewport' | |
import { Random } from 'random-js' | |
import Stats from 'stats.js' | |
const BatchSize = 150 | |
const TextCount = 1000 | |
const texts = [] | |
let accumulator = 0 | |
let lastScaled = 1 | |
let isZooming = false | |
const app = new PIXI.Application({ | |
width: window.innerWidth, | |
height: window.innerHeight, | |
antialias: true, | |
autoDensity: true, | |
autoStart: false, | |
resolution: window.devicePixelRatio || 1, | |
backgroundColor: '0x383838', | |
resizeTo: window | |
}) | |
document.body.appendChild(app.view) | |
app.ticker.stop() | |
const viewport = new Viewport({ | |
screenWidth: window.innerWidth, | |
screenHeight: window.innerHeight, | |
worldWidth: 7000, // approximate | |
worldHeight: 7000, | |
divWheel: app.view, | |
ticker: app.ticker, | |
passiveWheel: false, | |
noTicker: true, | |
events: app.renderer.events | |
}) | |
const container = new PIXI.Container() | |
const rnd = new Random() | |
const graphic = new PIXI.Graphics() | |
const style = new PIXI.TextStyle({ | |
fontSize: 14, | |
fill: 0xff0000, | |
lineJoin: 'round', | |
stroke: '#000000', | |
// fontWeight: 'bold', | |
// strokeThickness: 1 | |
}) | |
// init | |
for (let i = 0; i < TextCount; i += 1) { | |
const t = new PIXI.Text(`測試測試測試\n測試測試\n${rnd.string(8)}`, style) | |
graphic.clear() | |
.beginTextureFill({ texture: t.texture }) | |
.drawRect(0, 0, t.width, t.height) | |
.endFill() | |
const s = new PIXI.Sprite(app.renderer.generateTexture(graphic)) | |
s.position.set((i % 40) * (t.width + 10), ~~(i / 40) * (t.height + 10)) | |
s.roundPixels = true | |
s.cullable = true | |
texts.push([t, graphic, s]) | |
container.addChild(s) | |
} | |
viewport.addChild(container) | |
app.stage.addChild(viewport) | |
viewport | |
.drag() | |
.wheel({ smooth: false, interrupt: true }) | |
const update = () => { | |
if (isZooming || viewport.scaled === lastScaled) { | |
return | |
} | |
for (let i = accumulator; i < Math.min(accumulator + BatchSize, texts.length); i += 1) { | |
const [t, g, s] = texts[i] | |
t.style.fontSize = 14 * viewport.scaled | |
g.clear() | |
.beginTextureFill({ texture: t.texture }) | |
.drawRect(0, 0, t.width, t.height) | |
.endFill() | |
s.texture.destroy() // destrpy previous | |
s.texture = app.renderer.generateTexture(g) | |
s.scale.set(1 / viewport.scaled) | |
} | |
accumulator += BatchSize | |
if (accumulator >= TextCount) { | |
lastScaled = viewport.scaled | |
} | |
} | |
viewport.on('zoomed', () => { isZooming = true }) | |
viewport.on('zoomed-end',() => { | |
isZooming = false | |
accumulator = 0 | |
}) | |
// fps | |
const stats = new Stats() | |
stats.showPanel(0) | |
document.body.appendChild(stats.dom) | |
let prev = performance.now() | |
const loop = () => { | |
const now = performance.now() | |
const elapsedMS = now - prev | |
prev = now | |
app.renderer.render(app.stage) | |
viewport.update(elapsedMS * (60 / 1000)) | |
update() | |
stats.update() | |
requestAnimationFrame(loop) | |
} | |
requestAnimationFrame(loop) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment