TL; DR - мы создали веб-приложение для редактирования рукописных диаграмм на основе облачной технологии MyScript и фреймворка Vue.js.
Как вы можете написать диаграмму в браузере, предварительно просмотреть ее и использовать с любым конструктором презентаций?
Это то, что мы будем строить в этой статье, используя MyScriptJS и фреймворк Vue.js.
Проверьте веб-приложение в Интернете или найдите исходный код в нашем репозитории GitHub.
Возможности веб-приложения
Прежде чем мы начнем углубляться в детали, вот функции, которые будут интегрированы.
Как вы, возможно, видели в демонстрации, приложение позволяет использовать существующую диаграмму, чтобы показать вам некоторые возможности распознавания, или начать все заново с пустым холстом.
В режиме редактирования предлагается несколько вариантов:
MyScriptJS, интерфейсный фреймворк для распознавания рукописного текста
Распознавание обеспечивается MyScript Interactive Ink SDK, также называемым iink SDK, который представляет собой кроссплатформенный инструментарий разработки, предоставляемый MyScript.
Поскольку это будет веб-приложение, мы будем использовать библиотеку Javascript MyScriptJS, которая использует MyScript Cloud для распознавания рукописного ввода в Интернете. Вы можете найти полное руководство о том, как эта архитектура работает на веб-сайте разработчика MyScript, но вот краткое объяснение.
MyScriptJS используется для захвата штрихов из любого браузера с помощью пера, стилуса или мыши. Он также будет управлять информацией о рендеринге (используя svg или холст), когда пользователь пишет в редакторе. Используя REST или WebSockets, MyScriptJS будет управлять соединением между клиентом и сервером и отправлять захваченные штрихи, а также другие параметры (цвет, толщину, инструкции по отмене / повторению и т. Д.). Затем сервер обработает рукописный ввод и предоставит клиенту всю необходимую информацию, такую как: распознанный текст, математика, формы и т. Д. В различных форматах в зависимости от выбранного типа содержимого.
В случае использования нашего веб-приложения мы используем то, что мы называем пакетным режимом (с использованием REST). Это означает, что мы отправляем штрихи не постепенно, а за один раз, когда пользователь просит об этом. Это также означает, что все функции интерактивности недоступны в пакетном режиме (но скоро будут использоваться веб-сокеты). Для полного использования функций, предлагаемых iink SDK, вы можете проверить наше приложение для заметок Nebo.
Структура и ресурсы проекта
Для создания этого веб-приложения мы решили использовать фреймворк Vue.js. В этой статье предполагается, что вы знакомы с ней или, по крайней мере, имеете представление о прогрессивном фреймворке JavaScript.
Состав
Мы начали использовать шаблон vue-webpack-markerplate, который обеспечивает полнофункциональную настройку webpack для создания приложения Vue и позволяет быстро начать работу, не задумываясь о конфигурации. Шаблон предоставляет различные функции для разработки и сборки.
Вы можете найти полную документацию о шаблоне, а также подробное объяснение структуры проекта.
Мы будем говорить здесь только о структуре исходных папок.
src/
- основной кодcomponents/
- Компоненты Vuerouter/
- маршруты Vueutils/
- файлы JavaScriptevent-bus.js
- используется для связи между компонентамиApp.vue
- точка входа в приложениеmain.js
- точка входа в сборку
Компоненты Vue
Давайте поговорим немного о компонентах Vue. Мы разделили папку компонентов на три подпапки для трех основных частей приложения:
start-page/
- целевая страница, которую пользователи увидят в первую очередь (кроме мобильных устройств из-за ограничения скорости реакции).edit-page/
- страница редактирования, это будет основная область, где пользователь будет иметь доступ к редактированию диаграммыheader/
- заголовок, который будет на обеих страницах
Ядро приложения будет находиться в папке edit-page
.
Разработка проекта
Интегрируйте MyScriptJS в компонент редактора
В этой части мы сосредоточимся на том, как интегрировать MyScriptJS и связывать события, чтобы создать то, что мы называем нашим компонентом редактора.
Шаблон
<template>
<div :style="{display: displayStyle}" class="editor" @pointerdown="pointerDown" @loaded="loaded" @changed="changed($event)" @exported="exported($event)" touch-action="none" ref="editor">
</div>
</template>
Шаблон редактора представляет собой единый блок div с четырьмя слушателями событий:
- Pointerdown, будет срабатывать каждый раз, когда указатель становится активным
- Загружен, будет запущен, когда редактор будет готов и полностью загружен.
- Изменено, будет срабатывать каждый раз при изменении содержимого и содержать полезную информацию о возможностях редактора (можно очистить, можно повторить и т. д.)
- Экспортировано, будет запускаться для каждого нового экспорта и будет содержать экспортированные данные (svg и pptx для нашего варианта использования диаграммы).
События загружено, изменено и экспортировано запускаются непосредственно из MyScriptJS.
Мы также используем директивы :ref
, поскольку нам нужен элемент dom для инициализации редактора с помощью MyScriptJS.
Импортировать
import * as FileSaver from 'file-saver';
import MyScript from 'myscript/dist/myscript.esm';
import EventBus from '../../event-bus';
import { attach, detach } from '../../utils/custom_grabber';
Основным импортом здесь является MyScriptJS, который доступен как модуль ES6, что упрощает импорт. Мы также импортируем FileSaver для быстрого сохранения в pptx, нашу шину событий для связи между компонентами и двумя функциями, attach и detach, которые представляют собой «настраиваемый граббер для редактор".
Управляйте событиями редактора
Поскольку мы размещали слушателей событий с помощью директив Vue, мы полагались на методы, определенные в части методы компонента Vue.
Для событий pointerdown мы хотим создать событие, чтобы другие компоненты знали, что в редакторе был запущен указатель вниз. Подробнее о взаимодействии компонентов мы поговорим ниже.
pointerDown() { EventBus.$emit('pointerDown'); }
Для загруженных событий мы хотим проверить, решил ли пользователь импортировать диаграмму или начал новую. Если diagramData
существует, мы импортируем его, используя метод reDraw
редактора.
loaded() {
if (this.diagramData) {
this.editor.reDraw(this.diagramData.rawStrokes, this.diagramData.strokeGroups);
}
}
Для измененных событий мы будем генерировать событие changed
с объектом в качестве полезной нагрузки, содержащим начальное событие, а также указание на то, может ли редактор очистить или нет (используя количество штрихов в модели редактора).
changed(event) {
EventBus.$emit('changed',
{ event, canClear: this.editor.model.rawStrokes.length > 0, });
}
Экспортированные события немного сложнее. Мы по-прежнему хотим генерировать событие для других компонентов с объектом в качестве полезной нагрузки, содержащим как экспорт (здесь в формате svg и pptx), так и ширину и высоту клиента (полезно для превью svg). Вторая часть используется для сохранения экспорта в формате pptx, если требуется сохранение. Если пользователь нажимает кнопку «Сохранить» перед запросом предварительного просмотра, мы выполним экспорт перед сохранением диаграммы.
exported(event) {
this.exports = event.detail.exports;
EventBus.$emit('exported', { exports: event.detail.exports, clientWidth: this.clientWidth, clientHeight: this.clientHeight, });
if (this.exports && this.exports.pptx && this.saveRequested) {
const blob = new Blob([this.exports.pptx], { type: 'application/vnd.openxmlformats-officedocument.presentationml.presentation' });
FileSaver.saveAs(blob, 'myscript-diagram.pptx'); this.saveRequested = false;
}
}
Управляйте связью с другими компонентами
Мы используем шину событий для обеспечения связи между компонентами. Мы всегда будем прикреплять слушателей к смонтированным вариантам.
Слушатели отмены / повтора / очистки используются для вызова соответствующих методов редактора и генерируются другими компонентами (например, при нажатии кнопки отмены):
EventBus.$on('undo', () => { this.editor.undo(); });
Мы не будем подробно объяснять каждого слушателя, поскольку код в этой части не требует пояснений, но мы сосредоточимся на событиях preview
, save
и thicknessUpdate
.
Если пользователь нажимает кнопку Предварительный просмотр, шина событий выдаст preview
, и редактор будет его прослушивать. Предварительный просмотр означает скрытие редактора и запрос экспорта с использованием метода редактора и запрошенных миметипов, если модель редактора содержит штрихи. В противном случае мы будем запрашивать только пустой файл svg.
EventBus.$on('preview', () => { this.displayStyle = 'none';
if (this.editor.model.rawStrokes.length > 0) { this.editor.export_(['image/svg+xml','application/vnd.openxmlformats-officedocument.presentationml.presentation']); } else { EventBus.$emit('clearSvg'); } });
Событие save
запрашивается так же, как и событие preview
. Здесь мы используем библиотеку под названием FileSaver, которая позволяет нам быстро сохранять файл в формате pptx. Мы вызываем сохранение, только если у нас уже есть экспорт, в противном случае мы вызываем метод export
и указываем, что мы запросили сохранение. Если модель пуста, мы генерируем событие showNotification
для нашего компонента уведомления, используемого для отображения информационных сообщений.
EventBus.$on('save', () => {
if (this.exports && this.exports.pptx) {
const blob = new Blob([this.exports.pptx],
{ type: 'application/vnd.openxmlformats-officedocument.presentationml.presentation' });
FileSaver.saveAs(blob, 'myscript-diagram.pptx');
} else if (this.editor.model.rawStrokes.length > 0) {
this.editor.export_();
this.saveRequested = true;
} else {
EventBus.$emit('showNotification', 'save');
}
});
Последнее событие, которое мы объясним, - это thicknessUpdate
. Это происходит, когда пользователь меняет толщину пера. На слушателе мы используем полезную нагрузку, чтобы получить значение толщины. Затем мы можем установить атрибут penStyle редактора с цветом и толщиной, представленными -myscript-pen-width
.
EventBus.$on('thicknessUpdated', (data) => {
this.currentThickness = data.value;
this.editor.penStyle =
{ color: this.currentColor ? this.currentColor : '', '-myscript-pen-width': this.currentThickness, };
});
Навбар
Панель навигации содержит все основные действия, которые мы можем использовать для взаимодействия с редактором. В этой статье мы не будем объяснять все элементы управления, поскольку они просты и часто полагаются на создание события, чтобы сообщить редактору об изменении.
Для примера возьмем настройки пера и сосредоточимся на параметрах цвета пера. Остальные примеры можно найти в этом каталоге на GitHub.
Сам цвет пера - это компонент, используемый внутри компонента PenSettings
. Мы определяем массив цветов, содержащий наши предустановки цветов, в данные PenSettings
.
data() {
return { colors: ['#000000', '#808080', '#D9D9D9', '#1A8CFF', '#FF1A40', '#2BD965', '#FFDD33'], ... };
}
Затем массив colors
будет использоваться для определения цвета пера в шаблоне PenSettings
.
<template>
<div class="nav-group"> ...
<div class="colors">
<pen-color v-for="color in colors" :color="color" :checked="color === '#000000'" :key="color"/>
<color-picker/>
</div>
</div>
</template>
Давайте углубимся в компонент PenColor
. Шаблон цвета пера состоит из кнопки для определения щелчка и диапазона, представляющего галочку, чтобы сообщить пользователю, какой цвет выбран.
<template>
<div class="pensettings">
<button @click="changeColor" class="color" :style="style">
<span v-if="colorChecked" class="check" :style="{ borderColor: tickColor }"></span>
</button>
</div>
</template>
Цвет фона управляется вычисляемым свойством с использованием свойства цвета, которое мы передали в PenSettings
.
computed: { style() { return `background-color: ${this.color}`; } }
При щелчке мы используем метод changeColor()
, который генерирует событие для редактора, а затем управляет цветом галочки, используя яркость цвета.
changeColor() {
EventBus.$emit('colorChanged', this.color);
this.tickColor = blackOrWhiteTick(hexToRgb(this.color));
this.colorChecked = true;
}
Наконец, мы хотим снять отметку с цвета компонента PenColor
, если выбран другой цвет. Для этого мы используем шину событий, как показано ниже:
mounted() {
EventBus.$on('colorChanged', () => { this.colorChecked = false; });
}
Заключение
Что мы сделали:
- Как интегрировать MyScriptJS в прогрессивный фреймворк JavaScript
- Как взаимодействовать с редактором
- Как использовать экспортированные данные в реальном сценарии использования
Полный исходный код доступен на GitHub, откуда вы можете собрать и запустить приложение.
10 июля 2018
Первоначально опубликовано на developer.myscript.com.