(text, maxWidth, scale)
| 258 | } |
| 259 | |
| 260 | function wrapLabelText(text, maxWidth, scale) { |
| 261 | const words = String(text).toUpperCase().replace(/\s+/g, " ").trim().split(" ").filter(Boolean); |
| 262 | const lines = []; |
| 263 | let current = ""; |
| 264 | for (const word of words) { |
| 265 | const candidate = current ? `${current} ${word}` : word; |
| 266 | if (!current || textPixelWidth(candidate, scale) <= maxWidth) { |
| 267 | current = candidate; |
| 268 | } else { |
| 269 | lines.push(current); |
| 270 | current = word; |
| 271 | } |
| 272 | } |
| 273 | if (current) lines.push(current); |
| 274 | if (!lines.length) lines.push(""); |
| 275 | |
| 276 | let truncated = lines.length > 2; |
| 277 | const visible = lines.slice(0, 2); |
| 278 | for (let index = 0; index < visible.length; index += 1) { |
| 279 | if (textPixelWidth(visible[index], scale) <= maxWidth) continue; |
| 280 | truncated = true; |
| 281 | while (visible[index] && textPixelWidth(`${visible[index]}...`, scale) > maxWidth) { |
| 282 | visible[index] = visible[index].slice(0, -1).trimEnd(); |
| 283 | } |
| 284 | visible[index] = `${visible[index]}...`; |
| 285 | } |
| 286 | if (truncated) { |
| 287 | let last = visible[visible.length - 1] || ""; |
| 288 | while (last && textPixelWidth(`${last}...`, scale) > maxWidth) { |
| 289 | last = last.slice(0, -1).trimEnd(); |
| 290 | } |
| 291 | visible[visible.length - 1] = `${last}...`; |
| 292 | } |
| 293 | return { lines: visible, truncated }; |
| 294 | } |
| 295 | |
| 296 | function setPixel(rgba, width, x, y, color) { |
| 297 | const index = (y * width + x) * 4; |
no test coverage detected