使用Rough.js作为Konva渲染器

时间:2019-05-20 06:24:55

标签: javascript canvas konvajs

尝试使用Rough.js渲染konva Stage的一部分,但没有成功。 Rough使用对画布的引用进行绘制,但是konva层上的getCanvas()和toCanvas()似乎都无法解决问题。想法?

// Combined code
const cstage = new Konva.Stage({
   container: 'roughAndKonva',
   width: 200,
   height: 200
});
const clayer = new Konva.Layer();
var konvaCanvas = clayer.getCanvas()
const crc = rough.canvas(konvaCanvas);
crc.rectangle(50, 50, 100, 100);
cstage.add(clayer);

在这里拨弄:https://jsfiddle.net/qwLmb9ge/1/

3 个答案:

答案 0 :(得分:1)

一般而言,您可能会在lib之间遇到一些干扰,例如通过清除另一方输出的内容来进行意外重绘。

您可能要考虑有2个单独的,堆叠的画布,一个用于Rough,一个用于Konva,这样它们就可以显示单个画布的外观,但对于每个库,请保留画布管理员的位置。如果要在z轴上重叠两个库中的对象,则可能无法实现。

还请注意,Konva每层使用一个画布。

回到您的问题,查看Rough.js处的示例信息,似乎它想要一个简单的画布DOM元素,如其示例所示:

const rc = rough.canvas(document.getElementById('canvas'));

以获取您要定位的画布实例。由于Konva使用标准的HTML canvas元素,因此可以使用在页面上下文中起作用的任何选择器机制来获取画布。在您的小提琴中使用

<div id="roughAndKonva"></div>
在浏览器中生成的

(可以通过浏览器开发工具查看)

<div id="roughAndKonva">
  <div class="konvajs-content" role="presentation" style="...">
    <canvas style="...">
    </canvas>
  </div>
</div>

因此,您可以通过合适的元素选择器访问此canvas元素。如果您使用的是jquery,则以下内容将为您提供Konva使用的canvas元素。

var konvaCanvas = $('#roughAndKonva> div> canvas')[0];

您还可以使用普通JS选择画布。

我如下修改了您的代码(组合代码部分)

const stage = new Konva.Stage({
   container: 'container',
   width: 200,
   height: 200
});

const layer = new Konva.Layer();
stage.add(layer);

const rect = new Konva.Rect({
   x : 50, y : 50, width: 100, height: 100,
   fill: 'black',
   draggable: true
});

layer.add(rect).draw();


// Rough.js sample code
const rc = rough.canvas(document.getElementById('canvas'));
rc.rectangle(50, 50, 100, 100);


// Combined code  MODS HERE !
const cstage = new Konva.Stage({
   container: 'roughAndKonva',
   width: 200,
   height: 200
});
const clayer = new Konva.Layer();
const rect2 = new Konva.Rect({
   x : 40, y : 40, width: 100, height: 100,
   fill: 'red',
   draggable: true
});
clayer.add(rect2).draw();
cstage.add(clayer).draw()

var konvaCanvas = $('#roughAndKonva>div>canvas')[0]
const crc = rough.canvas(konvaCanvas);
crc.rectangle(50, 50, 100, 100);

哪个会生成组合画布的输出,如下所示,这是我想在注意到我故意抵消Konva rect以强调两者均存在之后的结果。

enter image description here

答案 1 :(得分:1)

我使用了上面Vanquished Wombat的答案作为开始,但是在重新绘制场景时遇到了一些问题,因为随后绘制的新矩形将被删除。

通过在SVG上绘制粗矩形来解决此问题,然后将SVG转换为和可以添加到Konva的图像。这使它紧密地适合Konva JS例程,包括重绘。

// Background box
  const svg = $('<svg xmlns="http://www.w3.org/2000/svg"></svg>')[0];
  svg.setAttribute("height", startWidth);
  svg.setAttribute("width", startHeight);
  const rc = rough.svg(svg);
  svg.appendChild(rc.rectangle(0, 0, startWidth, startHeight, {roughness: 0.3, strokeWidth: 2}));
  svgToImg(svg).then(background => {
    const bgImage = new Konva.Image({
        x: 0,
        y: 0,
        image: background,
        name: 'depLine',
        width: background.width,
        height: background.height
      });
    board.add(bgImage);
    board.draw();
  });

svgToImg函数:

// Promise to convert SVG to Image
function svgToImg(svg) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    const svgBlob = new Blob([svg.outerHTML], {type:'image/svg+xml'});
    const url = DOMURL.createObjectURL(svgBlob);
    img.onload = function() {
        DOMURL.revokeObjectURL(url);
        resolve(this);
    };
    img.onerror = reject
    img.src = url;
  });
}

答案 2 :(得分:0)

我遇到了类似的问题,因此决定尝试使这两个库相互配合。

首先,Konva提供了一个Shape类来创建自定义形状。它具有sceneFunc()方法,可用于绘制粗糙的形状。这是官方文档中的示例:

const customShape = new Konva.Shape({
  x: 5,
  y: 10,
  fill: 'red',
  // a Konva.Canvas renderer is passed into the sceneFunc function
  sceneFunc (context, shape) {
    context.beginPath();
    context.moveTo(200, 50);
    context.lineTo(420, 80);
    context.quadraticCurveTo(300, 100, 260, 170);
    context.closePath();
    // Konva specific method
    context.fillStrokeShape(shape);
  }
});

无论如何,您现在都需要创建一个粗糙画布的实例,因此它将知道我们正在画布上绘图:

const roughCanvas = rough.canvas(document.querySelector(`.${SHAPES_LAYER_CLS}`));

此实例将在sceneFunc()内部使用。 下一个问题是,您需要使用提供的上下文(sceneFunc的第一个参数),而rough.js不提供使用该上下文进行绘制的API,但是您可以做一些不同的事情:

  1. 使用generator API创建可绘制对象
  2. 使用code from the rough.js library,它可以根据来自可绘制对象的指令来创建形状并在提供的上下文上进行绘制(我将此代码保留在rawService中)
  3. sceneFunc()将被konva调用,因此您可以缓存可绘制对象并使用它,以免在每个渲染器上生成新形状。
const roughShape = new Konva.Shape({
    x: this.props.x || 0,
    y: this.props.y || 0,
    width: this.props.width || 0,
    height: this.props.height || 0,
    stroke: '#000000',
    strokeWidth: this.props.strokeWidth,
    fill: 'transparent',
    draggable: true,
    sceneFunc: (context, shape) => {
        if (isSelected()) {
            lastDrawable = roughCanvas.generator.rectangle(
                0,
                0,
                shape.getWidth(),
                shape.getHeight(),
                {
                    roughness: ROUGHNESS,
                    stroke: '#000000',
                },
            );
        }
        roughService.draw(context, lastDrawable);
        context.fillStrokeShape(shape);
    }
});

希望如此。这是我的用法的链接-RoughRect.ts