0

We're using react-konva, which renders a <Stage> component that manages an underlying canvas/context.

We want to use canvas2svg with it, which is basically a wrapper around a canvas context that tracks all draws to the canvas and maintains an svg representation for when you're ready to access it. It doesn't modify the canvas api, so in theory, Konva would be unaffected in that its canvas draw calls would be the same - they'd just need to be on the context generated by canvas2svg, rather than the one konva automatically generates.

We're looking for something like this, but it doesn't seem to exist. Are there any ways we could use a ref or otherwise hack Konva into using a C2S context? Or maybe we're missing a built-in property.

var c2sContext = new C2S(500,500);

<Stage context={c2sContext}>
Max Hudson
  • 9,961
  • 14
  • 57
  • 107
  • Konva is open source so you could make a fork and add what you require. Konva currently does not allow setting the canvas element directly - you give the stage an existing div selector and Konva sets up the canvases that it needs (one per Konva.Layer). You probably want to be looking at the layer.ts code to find where the canvas element is created and add your intervention there somehow. – Vanquished Wombat Apr 13 '22 at 14:40
  • Fair enough - forking's always an option - may do that if the answer truly is there's no way to access that canvas ref and swap it without forking. But looking at the repo may reveal how to access it once you have a ref – Max Hudson Apr 13 '22 at 17:55

1 Answers1

1

canvas2svg doesn't actually work alongside a normal rendered canvas (it's an alternative to one - for example, the arc() method just renders to svg, not svg + canvas), so you need to replace the render context with a c2s instance, call render so the methods like arc() get called, and then set it back.

You can use a ref on the konva Layer and run code like the following on a button press:

setTimeout(() => {
  var oldContext = this.layerRef.canvas.context._context;

  var c2s = this.layerRef.canvas.context._context = C2S({...this.state.containerSize, ctx: oldContext});

  this.forceUpdate();

  setTimeout(() => {
    console.log(c2s.getSerializedSvg());

    this.layerRef.canvas.context._context = oldContext;

    this.forceUpdate();
  })
}, 5000);

Two possible solutions that skirt around the need for canvas2svg:

  1. Generating an SVG string manually without rendering svg elements
  2. Rendering svg elements rather than canvas elements, and converting the dom to an html string

Obviously #2 has performance issues and #1 requires messier code - and #2 still requires some additional code/messiness, but both are good options to be aware of.

Max Hudson
  • 9,961
  • 14
  • 57
  • 107