MouseEventStream class
MouseEventStream transforms the bare bone DOM events into a stream
of higher level MouseEvents.
A MouseEventStream originates at an DOM Element
which the stream is attached to.
class MouseEventStream {
var _controler = new StreamController();
var _subscriptions = [];
var _lastMouseDownPos = null;
var _lastMouseDownTimestamp = 0;
var _mouseDown = false;
var _isDragging = false;
/// Creates a new stream which isn't attached to any element
MouseEventStream();
/// Creates a new stream which is attached to [source].
MouseEventStream.from(Element source) {
attach(source);
}
var _deferredEvent = null;
_fireDeferred() {
if (_deferredEvent != null) {
var e = _deferredEvent;
_deferredEvent = null;
_controler.sink.add(new MouseEvent(MouseEvent.CLICK, e));
}
}
void _rawMouseClick(html.MouseEvent evt) {
if (_deferredEvent == null) {
var ts = new DateTime.now().millisecondsSinceEpoch;
if (ts - _lastMouseDownTimestamp > 150) {
// a click generated at the end of a drag sequence
// mouse down, mouse move, ..., mouse move, mouse up, click
// Ignore it.
return;
}
_deferredEvent = evt;
new Timer(const Duration(milliseconds: 200), () => _fireDeferred());
} else {
_deferredEvent = null;
_controler.sink.add(new MouseEvent(MouseEvent.DOUBLE_CLICK,evt));
}
}
void _rawMouseMove(html.MouseEvent evt){
if (_mouseDown) {
if (!_isDragging) {
_controler.sink.add(new MouseEvent(MouseEvent.DRAG_START, evt));
}
_isDragging = true;
}
if (_isDragging) {
_controler.sink.add(new MouseEvent(MouseEvent.DRAG, evt));
} else {
_controler.sink.add(new MouseEvent(MouseEvent.HOVER, evt));
}
}
void _rawMouseDown(html.MouseEvent evt) {
if (evt.button != 0 /* left */) return;
evt.preventDefault();
evt.stopPropagation();
_mouseDown = true;
_lastMouseDownTimestamp = new DateTime.now().millisecondsSinceEpoch;
_lastMouseDownPos = new Point2D(evt.offset.x, evt.offset.y);
}
void _rawMouseUp(html.MouseEvent evt) {
if (evt.button != 0 /* left */) return;
evt.preventDefault();
evt.stopPropagation();
if (_isDragging) {
_controler.sink.add(new MouseEvent(MouseEvent.DRAG_END, evt));
}
_mouseDown = false;
_isDragging = false;
}
get stream => _controler.stream;
/// Detach from source and cancel all event subsriptions
void detach() {
_subscriptions
..forEach((s) => s.cancel())
..clear();
}
/// Attach to [source] and process its raw mouse events.
void attach(Element source) {
_subscriptions.add(source.onClick.listen(_rawMouseClick));
_subscriptions.add(source.onMouseDown.listen(_rawMouseDown));
_subscriptions.add(source.onMouseUp.listen(_rawMouseUp));
_subscriptions.add(source.onMouseMove.listen(_rawMouseMove));
}
}
Constructors
new MouseEventStream() #
Creates a new stream which isn't attached to any element
MouseEventStream();
Properties
final stream #
get stream => _controler.stream;
Methods
void attach(Element source) #
Attach to source and process its raw mouse events.
void attach(Element source) {
_subscriptions.add(source.onClick.listen(_rawMouseClick));
_subscriptions.add(source.onMouseDown.listen(_rawMouseDown));
_subscriptions.add(source.onMouseUp.listen(_rawMouseUp));
_subscriptions.add(source.onMouseMove.listen(_rawMouseMove));
}
void detach() #
Detach from source and cancel all event subsriptions
void detach() {
_subscriptions
..forEach((s) => s.cancel())
..clear();
}