Skip to content

Commit c030098

Browse files
- CHG: Replaced canvas sizing library with plain js to improve memory performance.
1 parent f9dacc7 commit c030098

3 files changed

Lines changed: 61 additions & 47 deletions

File tree

package-lock.json

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
"@vueuse/components": "^13.9.0",
1919
"@vueuse/core": "^13.9.0",
2020
"axios": "^1.12.2",
21-
"canvas-size": "^2.0.0",
2221
"compressorjs": "^1.2.1",
2322
"d3-dsv": "^3.0.1",
2423
"file-saver": "^2.0.5",

src/components/data/PrintCanvas.vue

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import type { CellPlus, TrialPlus } from '@/plugins/types/client'
1414
import { getColumnLabel, getRowLabel } from '@/plugins/util'
1515
16-
import canvasSize from 'canvas-size'
1716
import { useI18n } from 'vue-i18n'
1817
1918
const canvas = useTemplateRef('canvas')
@@ -40,20 +39,11 @@
4039
function init () {
4140
const canv = canvas.value
4241
if (canv) {
43-
canvasSize.maxArea({
44-
max: 20_000,
45-
min: 1,
46-
step: 100,
47-
useWorker: true,
48-
usePromise: true,
49-
}).then(result => {
50-
loading.value = false
51-
plot(result.width, result.height)
52-
})
42+
plot()
5343
}
5444
}
5545
56-
async function plot (width: number, height: number) {
46+
async function plot () {
5747
const trialData = await getTrialData(compProps.trial.localId || '')
5848
5949
ctx = canvas.value?.getContext('2d', { alpha: false })
@@ -103,34 +93,64 @@
10393
columnTextWidth = Math.ceil(columnTextWidth)
10494
textWidth = Math.max(textWidth, columnTextWidth)
10595
106-
if (((textWidth + config.padding) * compProps.trial.layout.columns < width) && ((textHeight + config.padding) * compProps.trial.layout.rows) < height) {
107-
// Easy case, everything fits perfectly within the max size of the canvas
108-
config.totalWidth = ((textWidth + config.padding) * compProps.trial.layout.columns)
109-
config.totalHeight = ((textHeight + config.padding) * compProps.trial.layout.rows)
110-
config.cellWidth = config.totalWidth / compProps.trial.layout.columns
111-
config.cellHeight = config.totalHeight / compProps.trial.layout.rows
112-
config.paddingLeft = rowTextWidth + config.padding
113-
config.paddingTop = config.cellHeight
114-
115-
canvass.width = config.totalWidth + config.paddingLeft
116-
canvass.height = config.totalHeight + config.paddingTop
117-
canvass.style.width = `${config.totalWidth + config.paddingLeft}px`
118-
canvass.style.height = `${config.totalHeight + config.paddingTop}px`
119-
120-
nextTick(() => {
121-
ctx = canvas.value?.getContext('2d', { alpha: false })
122-
123-
if (ctx) {
124-
ctx.textBaseline = 'middle'
125-
ctx.textAlign = 'center'
126-
ctx.font = '14px sans-serif'
127-
128-
plotCells(ctx, trialData)
96+
config.totalWidth = ((textWidth + config.padding) * compProps.trial.layout.columns)
97+
config.totalHeight = ((textHeight + config.padding) * compProps.trial.layout.rows)
98+
config.cellWidth = config.totalWidth / compProps.trial.layout.columns
99+
config.cellHeight = config.totalHeight / compProps.trial.layout.rows
100+
config.paddingLeft = rowTextWidth + config.padding
101+
config.paddingTop = config.cellHeight
102+
103+
const canvasWidth = config.totalWidth + config.paddingLeft
104+
const canvasHeight = config.totalHeight + config.paddingTop
105+
106+
canvass.width = canvasWidth
107+
canvass.height = canvasHeight
108+
canvass.style.width = `${canvasWidth}px`
109+
canvass.style.height = `${canvasHeight}px`
110+
111+
nextTick(() => {
112+
// 1. Check if the browser downsized it immediately (common in iOS)
113+
if (canvass.width !== canvasWidth || canvass.height !== canvasHeight) {
114+
setError()
115+
return
116+
}
117+
118+
ctx = canvas.value?.getContext('2d')
119+
120+
if (!ctx) {
121+
setError()
122+
return
123+
}
124+
125+
try {
126+
// 2. Try to draw and read a single pixel.
127+
// If the canvas is over the limit, this usually throws an error
128+
// or returns an empty/transparent pixel where it shouldn't.
129+
ctx.fillRect(canvasWidth - 1, canvasHeight - 1, 1, 1)
130+
const data = ctx.getImageData(canvasWidth - 1, canvasHeight - 1, 1, 1).data
131+
132+
// Check if the fill actually worked (alpha should be 255)
133+
if (data[3] !== 255) {
134+
setError()
135+
return
129136
}
130-
})
131-
} else {
132-
errorMessage.value = 'errorMessagePrintCanvasTooBig'
133-
}
137+
138+
ctx.textBaseline = 'middle'
139+
ctx.textAlign = 'center'
140+
ctx.font = '14px sans-serif'
141+
142+
plotCells(ctx, trialData)
143+
} catch {
144+
// 3. If the browser hits a hardware limit, getImageData often throws.
145+
setError()
146+
return
147+
}
148+
})
149+
}
150+
151+
function setError () {
152+
loading.value = false
153+
errorMessage.value = 'errorMessagePrintCanvasTooBig'
134154
}
135155
136156
function plotCells (ctx: CanvasRenderingContext2D, trialData: { [key: string]: CellPlus }) {
@@ -200,6 +220,8 @@
200220
}
201221
202222
ctx.strokeRect(0, 0, config.totalWidth + config.paddingLeft - 1, config.totalHeight + config.paddingTop - 1)
223+
224+
loading.value = false
203225
}
204226
205227
onMounted(() => {

0 commit comments

Comments
 (0)