我正在为Google Visualization / Charts API开发一个基于 Dart 的包装器,已经可以在github上查看。我为所有可用的图表创建了一个特定于图表的包装类。
现在我正在研究底层类的事件。问题是所有图表都没有共享各种事件。因此,我需要找到一种将特定事件类型分配给其相应图表的方法。我已经做的是:
我为Events api创建了一个包装器:
abstract class Events { static JsObject addListener(source_visualization, event_name, Function handling_function) { return vis['events'].callMethod('addListener', [source_visualization, event_name, new JsFunction.withThis(handling_function)]); } static JsObject addOneTimeListener(source_visualization, event_name, handling_function(e)) { return vis['events'].callMethod('addOneTimeListener', [source_visualization, event_name, new JsFunction.withThis(handling_function)]); } static void removeListener(listener_handler) { return vis['events'].callMethod('removeListener', [listener_handler]); } /// TODO(rh): removeAllListeners }
我创建了一个封装类,它封装了一个事件的所有代码。代码如下所示:
class EventWrapper<E extends Event> { JsObject _jsChart; String _eventName; JsObject _handler; Stream<E> get onEvent => _streamController.stream; StreamController<E> _streamController; ... EventWrapper(this._jsChart, this._eventName, E reviver(p)) { _streamController = new StreamController.broadcast(onListen: () => _onListen(_eventName), onCancel: () => _onCancel(_eventName)); } void _onListen(String event) { _handler = Events.addListener(_jsChart, event, ...); } void _onCancel(String event) { Events.removeListener(_handler); } }
在图表中,您可以使用如下代码:
class PieChart ... { Stream<SelectEvent> get onSelect => _selectEventHandler.onEvent; EventWrapper _selectEventHandler; PieChart(Element e) : super._(e, "PieChart", vis) { _selectEventHandler = new EventWrapper<SelectEvent>(jsChart, 'select', (p) => new SelectEvent()); // Other Events } // ... }
问题如下:Events
接口需要一个source_visulization
参数,即我要在其上注册事件的图表。但是当我使用dart:js
它时,只有在我在图表上调用构造函数之后才可用,因为它通过JsObject
( jsChart = new JsObject(ctx[chartName], [element])
) 创建了对象。通常我会EventWrapper
在构造函数中创建实例,但由于我必须在几个类中使用事件,所以我想到了其他两种解决方案,而不是你可以在 #3 中看到的当前解决方案。
创建一个 mixin - 这实际上不起作用,因为我没有构造函数,并且我无法指定实例方法,因为它给了我一个错误:
abstract class SelectEventMixin { Stream<SelectEvent> get onSelect => _selectEventHandler.stream; final StreamController _selectEventHandler = new StreamController.broadcast(onListen: _onListen); void _onListen() { // jsChart is available here } }
为看到的每个事件组合创建 BaseClasses,这将允许我共享最常见的代码。一些 BaseClass 将是:
NoEvents
,SelectEvent
,SelectReadyEvents
,SelectReadyAnimationFinishEvents
, ...
你们中有人有更好的解决方案吗?或者有人可以告诉我如何解决我的问题#1?#2 已经是最好的解决方案了吗?因为我只需要结合几种方法并且只有一点重复的代码?