Как отложить применение свойства в qooxdoo

Я пишу приложение для создания диаграмм HTML5, используя qooxdoo для системы объектов и набора инструментов для виджетов, а также RaphaelJS в качестве бэкенда для рисования. Модель данных для диаграммы содержит объекты высокого уровня, такие как Item, Line и т. д.; они реализованы как классы qooxdoo со свойствами положения, размеров, цвета и других данных. Каждый класс способен отображать свои экземпляры на бумаге Raphael, скажем, с помощью метода render(). В этот момент создается визуальное («элемент» в терминах Рафаэля).

Проблема в том, что некоторые свойства должны быть установлены до создания визуального элемента Raphael. В Raphael вы не можете нарисовать круг, не указав координаты его центра и радиус; вы не можете создать путь без определения пути; вы не можете создать текстовую метку без фактического текста и так далее. Кроме того, некоторые свойства можно задать только после создания визуального элемента: вы не можете установить цвет, стиль обводки и т. д. для несуществующего визуального элемента. Итак, мы можем представить следующий рабочий процесс:

var circle = new my.Circle();
circle.set({ x: 10, y: 20, r: 30 }); // can't set color here - no visual yet
circle.render(paper);
circle.set({ stroke: "red", strokeWidth: 5 });

Хорошо, мы можем контролировать этот рабочий процесс, если создадим объекты вручную. Но если весь граф сцены демаршаллирован из JSON (для загрузки сохраненной диаграммы), нет контроля над последовательностью вызовов, и все свойства будут установлены сразу. Вот почему мой класс Circle содержит следующее в разделе members:

// Setter for stroke
_applyStroke: function(val, old) {
 this.element && this.element.attr({ stroke: val });
}
// The same for fill, stroke width, stroke style, arrowhead style etc.
// ...
render: function(paper) {
 this.element = paper.circle(this.getX(), this.getY(), this.getR());
 this._applyStroke(this.getStroke());
 this._applyStrokeWidth(this.getStrokeWidth());
 // repeat for each style property
}

Есть ли способ сделать то же самое с меньшим количеством шаблонов? Я думал о создании фиктивных «элементов» Raphael для принятия атрибутов стиля до создания фактического элемента и после его создания для передачи фиктивных атрибутов фактическому элементу. Но этот подход, кажется, требует многих изменений в существующем коде. Мне интересно, есть ли более элегантный способ сделать это? Решения на основе АОП приемлемы, так как АОП отлично работает в qooxdoo.


person Sebastian Widmer    schedule 26.06.2013    source источник


Ответы (1)


Я предполагаю, что ответ зависит от нескольких ограничений, касающихся RafaelJS, которые я недостаточно хорошо знаю.

  1. Если это нормально в вашем приложении, вы можете создать элемент в конструкторе my.Circle с некоторыми значениями по умолчанию для x, y и r. Затем вы разрешите обычным методам применения свойства распространяться на атрибуты element. (Это как бы отменяет явный метод render()).

  2. Если это приведет к слишком раннему отображению элемента и отображению всех изменений его атрибутов (чего вы, возможно, захотите избежать), я бы поискал элемент управления типа скрытия/отображения элемента. Возможно, вы можете создать и изменить элемент, когда он все еще скрыт. Тогда метод render() просто переключит видимость.

  3. Если все это не работает, и вы вынуждены создать элемент в методе render() по какой-то причине, вероятно, нет никакого способа обойти какой-то небольшой протокол:

    • Создайте элемент в методе render() с любыми значениями обязательных атрибутов (например, x, y и r), будь то начальные значения или определенные пользователем.

    • Методы применения, принадлежащие свойствам, которые могут быть установлены только для существующих элементов, могут записывать свои изменения во внутреннюю очередь (вероятно, просто в список сопоставлений атрибутов) вместо того, чтобы записывать непосредственно в элемент. Таким образом вы фиксируете все «преждевременные» изменения свойств.

    • Затем метод render() просто применяет элементы в очереди. Это будет реализовывать «приложение отложенного свойства», которое вы упоминаете в заголовке вопроса. Недостатком будет то, что все дальнейшие изменения свойств вступят в силу только при следующем вызове render() (на этот раз без создания элемента).

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

person ThomasH    schedule 27.06.2013