|
13 | 13 | import type { CellPlus, TrialPlus } from '@/plugins/types/client' |
14 | 14 | import { getColumnLabel, getRowLabel } from '@/plugins/util' |
15 | 15 |
|
16 | | - import canvasSize from 'canvas-size' |
17 | 16 | import { useI18n } from 'vue-i18n' |
18 | 17 |
|
19 | 18 | const canvas = useTemplateRef('canvas') |
|
40 | 39 | function init () { |
41 | 40 | const canv = canvas.value |
42 | 41 | 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() |
53 | 43 | } |
54 | 44 | } |
55 | 45 |
|
56 | | - async function plot (width: number, height: number) { |
| 46 | + async function plot () { |
57 | 47 | const trialData = await getTrialData(compProps.trial.localId || '') |
58 | 48 |
|
59 | 49 | ctx = canvas.value?.getContext('2d', { alpha: false }) |
|
103 | 93 | columnTextWidth = Math.ceil(columnTextWidth) |
104 | 94 | textWidth = Math.max(textWidth, columnTextWidth) |
105 | 95 |
|
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 |
129 | 136 | } |
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' |
134 | 154 | } |
135 | 155 |
|
136 | 156 | function plotCells (ctx: CanvasRenderingContext2D, trialData: { [key: string]: CellPlus }) { |
|
200 | 220 | } |
201 | 221 |
|
202 | 222 | ctx.strokeRect(0, 0, config.totalWidth + config.paddingLeft - 1, config.totalHeight + config.paddingTop - 1) |
| 223 | +
|
| 224 | + loading.value = false |
203 | 225 | } |
204 | 226 |
|
205 | 227 | onMounted(() => { |
|
0 commit comments