flbulgarelli / headbreaker

:jigsaw: :exploding_head: Jigsaw puzzles framework for JavaScript
https://flbulgarelli.github.io/headbreaker/
ISC License
139 stars 46 forks source link

image metadata in autogenerate function fails #66

Closed albert-estradera closed 1 year ago

albert-estradera commented 1 year ago

if you generate a piece with image in metadata with sketchPiece function not fails and show the image, but if the structure is in autogenerate function fails.

Example that works:

labels.sketchPiece({ structure: { right: headbreaker.Tab }, metadata: { id: 'tree-kanji2', color: '#23599E', strokeColor: '#18396B', image: {content: document.querySelector("#resumenf"), offset: {x:2, y:1}, scale: 1 } } });

Example that fails:

labels.autogenerate({ horizontalPiecesCount: 3, verticalPiecesCount: 3, metadata: [ {color: '#6F04C7', image: {content: document.querySelector("#resumenf"), offset: {x:21, y:1}, scale: 1 } }, {color: '#0498D1'}, {color: '#16BA0D'}, {color: '#000000'}, {color: '#6F04C7'}, {color: '#0498D1'}, {color: '#16BA0D'}, {color: '#000000'}, {color: '#6F04C7'}, ] });

thanks

albert-estradera commented 1 year ago

this is the error:

Uncaught TypeError: Failed to execute 'createPattern' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLCanvasElement or HTMLImageElement or HTMLVideoElement or ImageBitmap or OffscreenCanvas or SVGImageElement or VideoFrame)'. at headbreaker.../node_modules/konva/lib/Shape.js.Shape.__getFillPattern (Shape.js:112:1) at headbreaker.../node_modules/konva/lib/Node.js.Node._getCache (Node.js:118:1) at headbreaker.../node_modules/konva/lib/Shape.js.Shape._getFillPattern (Shape.js:107:1) at headbreaker.../node_modules/konva/lib/Context.js.SceneContext._fillPattern (Context.js:382:1) at headbreaker.../node_modules/konva/lib/Context.js.SceneContext._fill (Context.js:424:1) at headbreaker.../node_modules/konva/lib/Context.js.Context.fillShape (Context.js:82:1) at headbreaker.../node_modules/konva/lib/Context.js.Context.fillStrokeShape (Context.js:95:1) at headbreaker.../node_modules/konva/lib/shapes/Line.js.Line._sceneFunc (Line.js:71:1) at headbreaker.../node_modules/konva/lib/Shape.js.Shape.drawScene (Shape.js:355:1) at Container.js:246:1

and if debug you can see that in the metadata the content in image object is empty

flbulgarelli commented 1 year ago

:wave: Hi @albert-estradera!

Although the way it is failing is - admittedly - not nice at all, headbreaker is not designed for that use case at all: you should either sketch pieces individually, passing an image to each of them, or set a per-canvas image and then autogenerate the pieces. Passing individual images to each piece may be tricky, since you should take care that all images actually match.

In other words, I think passing an image to autogenerate's metadata should throw a validation error, and it might do in the future.

That said, if you really want to do something like this, you can override the headbreaker.Metadata.copy, which is the indirect culprit of your exception. Something like this:

headbreaker.Metadata.__copy__ = headbreaker.Metadata.copy
headbreaker.Metadata.copy = function(it) {
  const dup = this.__copy__(it);
  dup.image = it.image;
  return dup;
}

By doing that you will be actually able to use separate images in each piece:

image

let xul = new Image();
xul.src = 'static/xul.jpg';
xul.onload = () => {

  const autogen = new headbreaker.Canvas('autogen-canvas', {
    width: 800, height: 650,
    pieceSize: 100, proximity: 20,
    borderFill: 10, strokeWidth: 1.5,
    lineSoftness: 0.18,
  });

  autogen.autogenerate({
    horizontalPiecesCount: 2,
    verticalPiecesCount: 2,
    metadata: [
      { image: { content: xul, offset: { x: 10, y: 10 }, scale: 0.12 } },
      { image: { content: xul, offset: { x: 10, y: 10 }, scale: 0.12 } },
      { image: { content: xul, offset: { x: 10, y: 10 }, scale: 0.12 } },
      { color: '#37AB8C' }
    ]
  });
  autogen.draw();
}

However, you should do at your own risk, since as previously said, this framework is not designed to work like that. In other words, overriding copy to achieve that goal should be considered just a hack, since - at least by now - this method is exposed to allow more efficient copy strategies, not to alter the copy semantics.