diff --git a/src/main.js b/src/main.js index 4316e3c..68f0a45 100644 --- a/src/main.js +++ b/src/main.js @@ -41,6 +41,7 @@ import { rgbToHsv, multiplyMatrices, growBoundingBox, + createMissingTexturePattern, } from "./utils.js"; import { backgroundColor, @@ -2940,7 +2941,13 @@ class BaseShape { if (this.filled) { ctx.beginPath(); 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; } else { ctx.fillStyle = this.fillStyle; @@ -3162,12 +3169,20 @@ class Shape extends BaseShape { this.inProgress = true; } 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( json.startx, json.starty, { fillStyle: json.fillStyle, - fillImage: json.fillImage, + fillImage: fillImage, strokeStyle: json.strokeStyle, lineWidth: json.lineWidth, fillShape: json.filled, @@ -3199,7 +3214,11 @@ class Shape extends BaseShape { json.startx = this.startx; json.starty = this.starty; json.fillStyle = this.fillStyle; - json.fillImage = this.fillImage; + if (this.fillImage instanceof Element) { + json.fillImage = { + src: this.fillImage.src + } + } json.strokeStyle = this.fillStyle; json.lineWidth = this.lineWidth; json.filled = this.filled; diff --git a/src/utils.js b/src/utils.js index 59318df..d0c996c 100644 --- a/src/utils.js +++ b/src/utils.js @@ -461,6 +461,32 @@ function drawCheckerboardBackground(ctx, x, y, width, height, squareSize) { 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) { // Step 1: Convert hex to RGB let r = parseInt(hex.substring(1, 3), 16) / 255; @@ -919,6 +945,7 @@ export { rgbToHex, rgbToHsv, drawCheckerboardBackground, + createMissingTexturePattern, clamp, signedAngleBetweenVectors, rotateAroundPoint,