Используйте Rough.js в качестве рендерера Konva

Попытка использовать Rough.js для рендеринга частей сцены konva, но безуспешно. Rough использует ссылку на холст для рисования, но ни getCanvas(), ни toCanvas() на слое konva, похоже, не помогают. Идеи?

// 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/

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
448
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Как правило, вы можете столкнуться с некоторыми помехами между библиотеками, например. неожиданные перерисовки, когда один очищает вывод содержимого другим.

Вы можете захотеть иметь 2 отдельных сложенных холста, один для Rough и один для Konva, чтобы они создавали вид единого холста, но сохраняли администрирование холста отдельно для каждой библиотеки. Это может оказаться невозможным, если вы хотите перекрыть объекты из двух библиотек по оси Z.

Также обратите внимание, что Konva использует холст для каждого слоя.

Возвращаясь к вашему вопросу, глядя на образец информации в Rough.js, кажется, что ему нужен простой элемент холста DOM, как в их примере:

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

чтобы получить экземпляр холста, на который вы хотите настроить таргетинг. Так как Konva использует стандартный элемент холста HTML, вы можете использовать любой механизм выбора, который работает в контексте вашей страницы, чтобы получить холст. В своей скрипке вы используете

<div id = "roughAndKonva"></div>

который создается в браузере (можно увидеть с помощью инструментов разработчика браузера)

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

Поэтому вы можете получить доступ к этому элементу холста через подходящий селектор элементов. Если вы используете jquery, то следующее даст вам элемент холста, который использует Konva.

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, чтобы подчеркнуть, что оба присутствуют.

Большое спасибо, я не знал, что мне нужно вернуться в DOM и получить его таким образом.

Setomidor 20.05.2019 11:30

Действительно, вы можете - Konva и подобные библиотеки действуют как прокси, чтобы предоставить дополнительные возможности по сравнению со стандартным элементом холста HTML5, который всегда должен быть там. Библиотека обычно внедряет то, что она намеревается сделать какой-то частной оболочкой, как это делает Konva, но вы всегда можете взломать инспектор DOM в своем браузере, чтобы увидеть, как он устроен, а затем сформулировать селектор в соответствии с моим примером .

Vanquished Wombat 20.05.2019 11:55
Ответ принят как подходящий

Я использовал ответ 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;
  });
}

У меня была аналогичная проблема, и я решил попробовать заставить обе библиотеки работать друг с другом.

Во-первых, Konva предоставляет класс Форма для создания пользовательских фигур. У него есть метод 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. Используйте API генератора для создания рисуемого объекта
  2. Используйте код из библиотеки rough.js, который может создавать форму на основе инструкций из рисуемого объекта и рисовать в предоставленном контексте (я храню этот код в roughService)
  3. Конва будет часто вызывать sceneFunc(), поэтому вы можете кэшировать рисуемый объект и использовать его, чтобы не генерировать новую форму при каждом рендере.
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

Другие вопросы по теме