Handle missing textures better (and export them properly)

This commit is contained in:
Skyler Lehmkuhl 2025-01-13 17:34:16 -05:00
parent 47d54d6e26
commit 74809acd2d
2 changed files with 49 additions and 3 deletions

View File

@ -41,6 +41,7 @@ import {
rgbToHsv, rgbToHsv,
multiplyMatrices, multiplyMatrices,
growBoundingBox, growBoundingBox,
createMissingTexturePattern,
} from "./utils.js"; } from "./utils.js";
import { import {
backgroundColor, backgroundColor,
@ -2940,7 +2941,13 @@ class BaseShape {
if (this.filled) { if (this.filled) {
ctx.beginPath(); ctx.beginPath();
if (this.fillImage) { if (this.fillImage) {
let pat = ctx.createPattern(this.fillImage, "no-repeat"); let pat;
if (this.fillImage instanceof Element ||
Object.keys(this.fillImage).length !== 0) {
pat = ctx.createPattern(this.fillImage, "no-repeat");
} else {
pat = createMissingTexturePattern(ctx)
}
ctx.fillStyle = pat; ctx.fillStyle = pat;
} else { } else {
ctx.fillStyle = this.fillStyle; ctx.fillStyle = this.fillStyle;
@ -3162,12 +3169,20 @@ class Shape extends BaseShape {
this.inProgress = true; this.inProgress = true;
} }
static fromJSON(json) { static fromJSON(json) {
let fillImage = undefined;
if (json.fillImage && Object.keys(json.fillImage).length !== 0) {
let img = new Image();
img.src = json.fillImage.src
fillImage = img
} else {
fillImage = {}
}
const shape = new Shape( const shape = new Shape(
json.startx, json.startx,
json.starty, json.starty,
{ {
fillStyle: json.fillStyle, fillStyle: json.fillStyle,
fillImage: json.fillImage, fillImage: fillImage,
strokeStyle: json.strokeStyle, strokeStyle: json.strokeStyle,
lineWidth: json.lineWidth, lineWidth: json.lineWidth,
fillShape: json.filled, fillShape: json.filled,
@ -3199,7 +3214,11 @@ class Shape extends BaseShape {
json.startx = this.startx; json.startx = this.startx;
json.starty = this.starty; json.starty = this.starty;
json.fillStyle = this.fillStyle; json.fillStyle = this.fillStyle;
json.fillImage = this.fillImage; if (this.fillImage instanceof Element) {
json.fillImage = {
src: this.fillImage.src
}
}
json.strokeStyle = this.fillStyle; json.strokeStyle = this.fillStyle;
json.lineWidth = this.lineWidth; json.lineWidth = this.lineWidth;
json.filled = this.filled; json.filled = this.filled;

View File

@ -461,6 +461,32 @@ function drawCheckerboardBackground(ctx, x, y, width, height, squareSize) {
ctx.fillRect(x, y, width, height); ctx.fillRect(x, y, width, height);
} }
const missingTexturePatternCache = new Map();
function createMissingTexturePattern(ctx) {
// Return cached pattern if it exists
if (missingTexturePatternCache.has(ctx)) return missingTexturePatternCache.get(ctx);
// Create an offscreen canvas for the checkerboard pattern
const size = 16;
const patternCanvas = document.createElement('canvas');
patternCanvas.width = patternCanvas.height = size * 2;
const patternCtx = patternCanvas.getContext('2d');
// Draw the magenta and black checkerboard pattern
for (let y = 0; y < 2; y++) {
for (let x = 0; x < 2; x++) {
patternCtx.fillStyle = (x + y) % 2 === 0 ? 'magenta' : 'black';
patternCtx.fillRect(x * size, y * size, size, size);
}
}
// Cache and return the pattern
const pattern = ctx.createPattern(patternCanvas, 'repeat');
missingTexturePatternCache.set(ctx, pattern);
return pattern;
}
function hexToHsl(hex) { function hexToHsl(hex) {
// Step 1: Convert hex to RGB // Step 1: Convert hex to RGB
let r = parseInt(hex.substring(1, 3), 16) / 255; let r = parseInt(hex.substring(1, 3), 16) / 255;
@ -919,6 +945,7 @@ export {
rgbToHex, rgbToHex,
rgbToHsv, rgbToHsv,
drawCheckerboardBackground, drawCheckerboardBackground,
createMissingTexturePattern,
clamp, clamp,
signedAngleBetweenVectors, signedAngleBetweenVectors,
rotateAroundPoint, rotateAroundPoint,