1

我正在编写一个 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 中解组(以加载保存的图),则无法控制调用顺序,并且所有属性都将立即设置。members这就是为什么我的 Circle 类在其部分中包含以下内容:

// 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“元素”以在创建实际元素之前接受样式属性,并在创建后将虚拟属性提交给实际元素。但是这种方法似乎需要对现有代码进行许多更改。我想知道是否有更优雅的方式来实现这一点?基于 AOP 的解决方案是可以接受的,因为 AOP 在 qooxdoo 中运行良好。

4

1 回答 1

0

我想答案取决于我不太了解的关于 RafaelJS 的一些限制。

  1. 如果这在您的应用程序中没问题,您可以在 my.Circle 构造函数中创建元素,并为 x、y 和 r 设置一些默认值。然后,您将让普通属性应用方法传播到元素属性。(这会破坏显式的render()方法)。

  2. 如果这会使元素过早呈现,并显示对其属性的所有更改(您可能希望避免),我会寻找元素的隐藏/显示类型控件。也许您可以在仍然隐藏时构建和更改元素。然后render()方法将只是切换可见性。

  3. 如果这一切都不起作用,并且由于某种原因您被迫在render()方法中创建元素,则可能无法绕过某种小协议:

    • 在render()方法中创建元素,使用您对强制属性(例如 x、y 和 r)的任何值,无论是初始值还是用户定义的值。

    • 属于只能在现有元素上设置的属性的应用方法可以将其更改写入内部队列(可能只是属性映射列表),而不是直接写入元素。这样您就可以捕获所有“过早”的属性更改。

    • 然后render()方法只应用队列中的元素。这将实现您在问题标题中提到的“延迟属性应用程序”。缺点是所有进一步的属性更改只会在下一次render()调用时生效(这次避免创建元素)。

    • 当然,您可以将其与已有的内容结合起来,在尚未创建元素时写入队列,否则直接修改它。

于 2013-06-27T12:48:52.800 回答