Здравствуйте! Прошу вас дочитать вопрос до конца, он не короткий, но это по тому, что я постарался как можно понятнее описать проблему.
Я пишу сложное приложение на Vue.js + Vuex: работа с текстом, изображениями и другими графическими объектами на canvas'e, для этого еще использую библиотеку fabric.js.
Так как библиотека fabric.js не как не связана с Vue.js то реактивности в ней нет, и я использую для обновление элементов watch.
Так вот, вопрос в том, что я столкнулся с проблемой управления объектов fabric.js в других компонентах кроме как в том, где инициализируется fabric.js. Мой вопрос связан с хранилищем, не важно Vuex или Redux, правда с Redux я почти толком и не работал, но принцип думаю пойму.
В моем случае я использую библиотеку fabric.js, но это не имеет значения, так как всяких библиотек для работы с элементами много, но суть я постараюсь понятно донести затрагивая fabric.js.
Кратко о моей реализации вывода объектов:
В компоненте TheCanvas, в хуке mounted, инициализируется объект canvas (new fabric.Canvas) и вызывается метод render, где идет цикл по объектам из хранилища. Пример упрощен, я не пишу код, который не имеет отношения к вопросу и не хочу сделать простыню на 3к пикселей в высоту)
mounted () {
this.canvas = new fabric.Canvas(this.$el, {
selectionColor: 'rgba(0, 112, 224, 0.02)',
selectionBorderColor: 'rgba(0, 112, 224, 0.3)'
})
this.render(this.elems)
},
methods: {
render (elems) {
elems.forEach(elem => {
if (elem.type === 'image') {
fabric.Image.fromURL(elem.url, imgObj => {
imgObj.set(elem.attrs)
this.canvas.add(imgObj)
})
} else if (elem.type === 'text') {
const textObj = new fabric.Textbox(elem.content, elem.attrs)
this.canvas.add(textObj)
}
})
}
}
Новые объекты я добавляю в хранилище вручную, иначе их ни как не добавить, так как какую-либо информацию о объекте fabric, можно получить только после создания объекта через new fabric
// вызов мутации добавления нового элемента
this.addElem({
type: 'image',
url: urls.regular,
attrs: {
top,
left
}
})
// а вот сама мутация, очень простая
addElem (state, payload) {
state.elems.push(payload)
}
И получается у меня такая структура объектов:
// пример с 2 типами элементов, очень просто.
store: {
elems: [
{
type: 'image',
url: 'someUrl',
attrs: {
top,
left
}
},
{
type: 'text',
content: 'Текст',
attrs: {
top: this.canvasSize.height / 2 - 14,
left: this.canvasSize.width / 2 - 40,
padding: 4,
width: 80,
fontFamily: 'Arial',
fontSize: 24,
textAlign: 'center'
}
}
]
}
Так вот, такой способ хранения объектов в хранилище вообще не рабочий, потому, что в других компонентах я не могу получить данные о объекте, такие как выделенный текст и стиль каждого символа, так как эти данные можно получить только методом объекта fabric, который создается к примеру как в рендере (код render'a выше):
const textObj = new fabric.Textbox(elem.content, elem.attrs)
this.canvas.add(textObj)
// и уже у объекта texObj я могу вызвать метод и получить нужные стили:
textObj.getSelectionStyles()
// или же установить новые стили для выделенных символов текста
textObt.setSelectionStyles({ color: 'red' })
Подведу итоги:
Способ которым я добавляю объекты - не рабочий, хотя для большинства случаев годен.
У объекта созданного через вызов new fabric есть метод toJson , который возвращает json объекта.
Я думал добавлять в хранилище json объекта fabric (сам объект нельзя передать, иначе выдает ошибку maximum call stack...), но смысла от json я не вижу, ведь в других компонентах, где нужно получать информацию о конкретном объекте (к примеру как я писал выше со стилями: textObj.getSelectionStyles()) я не смогу обратиться к этому методу, потому, что при вызове метода toJson, у объекта фабрики, в json просто свойства попадают.
Еще раз уточню вопрос:
Вопрос довольно не простой, по этому прошу профессионалов, которые уже имеют опыт в разработке сложных приложений, поделиться как лучше реализовать хранение объектов в хранилище и работы с ними.