-
Notifications
You must be signed in to change notification settings - Fork 0
Snap之Event
何波 edited this page Jul 11, 2019
·
3 revisions
mouse.js为Element.prototype添加event方法,同时为Element.node添加addEventListener和removeEventListener,并挂载到Snap全局变量上。
click, dblclick, mousedown, mousemove, mouseout, mouseover, mouseup, touchstart, touchmove, touchend, touchcancel
var elproto = Element.prototype,
events = [
"click", "dblclick", "mousedown", "mousemove", "mouseout",
"mouseover", "mouseup", "touchstart", "touchmove", "touchend",
"touchcancel"
],
touchMap = {
mousedown: "touchstart",
mousemove: "touchmove",
mouseup: "touchend"
},
addEvent = function (obj, type, fn, element) {
console.info(element.node === obj) // true
// 这里的obj一般为element.node,也就是element.node.addEventListener
// obj也有可能是document
var realName = supportsTouch && touchMap[type] ? touchMap[type] : type,
f = function (e) {
var scrollY = getScroll("y", element),
scrollX = getScroll("x", element);
if (supportsTouch && touchMap[has](type)) {
for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) {
if (e.targetTouches[i].target == obj || obj.contains(e.targetTouches[i].target)) {
// 如果是touch事件,则让e = e.targetTouches[i],以便与click等事件在回调中的e保持一致
var olde = e;
e = e.targetTouches[i];
e.originalEvent = olde; // 把真的e放到originalEvent中,createjs也是这样干的
e.preventDefault = preventTouch;
e.stopPropagation = stopTouch;
break;
}
}
}
var x = e.clientX + scrollX,
y = e.clientY + scrollY;
// 注意这里的回调参数为e, x, y,包括了点击的坐标
/*
let svg = Snap("#svg");
var c = svg.paper.circle(50, 50, 40).attr({
fill: "#f00"
}).click((e, x, y) => {
console.info(e, x, y)
})
*/
return fn.call(element, e, x, y);
};
// 真正绑定事件的是element.node,而非element。可以在chrome开发者工具
// 查看元素所绑定的事件
if (type !== realName) {
obj.addEventListener(type, f, false);
}
obj.addEventListener(realName, f, false);
// let unbind = addEvent(...)
// unbind() 如果执行的话,直接调下面函数内容
return function () {
// 清除绑定的事件
if (type !== realName) {
obj.removeEventListener(type, f, false);
}
obj.removeEventListener(realName, f, false);
return true;
};
}
for (var i = events.length; i--;) {
(function (eventName) {
// Snap.mousemove,Snap.mouseup也可以执行,如下面的drag方法中会用到
Snap[eventName] = elproto[eventName] = function (fn, scope) {
// 如果fn是函数就进行事件绑定,如:Element.click(() => alert('click'))
if (Snap.is(fn, "function")) {
// Element.events = []
// 如果是Snap.mousemove,Snap.mouseup,则this为Snap全局变量
this.events = this.events || [];
// unbind:addEvent为this.node绑定事件
// 如果是Snap.mousemove,Snap.mouseup这样的,this.node不存在,则会把事件绑定在document上面
this.events.push({
name: eventName,
f: fn,
unbind: addEvent(this.node || document, eventName, fn, scope || this)
});
} else {
// 如果 fn未定义,或不是函数,就直接取出Element.events[]数组,执行其中的f方法
// 如:Element.click()
for (var i = 0, ii = this.events.length; i < ii; i++) if (this.events[i].name == eventName) {
try {
this.events[i].f.call(this);
} catch (e) {}
}
}
return this;
};
// 添加un bind事件
Snap["un" + eventName] =
elproto["un" + eventName] = function (fn) {
// 从events数组中删除该事件
var events = this.events || [],
l = events.length;
while (l--) if (events[l].name == eventName &&
(events[l].f == fn || !fn)) {
events[l].unbind(); // 同时对真的Element.node进行事件删除
events.splice(l, 1);
!events.length && delete this.events;
return this;
}
return this;
};
})(events[i]);
}示例:
let svg = Snap("#svg");
let c = svg.paper.circle(50, 50, 40).attr({
fill: "#f00"
}).click((e, x, y) => {
console.info(e, x, y)
});
console.dir(c)
// c.click() // 成功
// c.node.click() 会报错
c.node.dispatchEvent(new Event('click')) // 成功
c.unclick() // 清除click事件输出:
Element:{
anims: {},
events: [{name: "click", f: ƒ, unbind: ƒ}],
id: "circleSjxy35tcy1",
node: circle,
paper: Element,
type: "circle"
}为Element.node绑定的click事件,会放到Element.events[]数组中进行事件记录。 其作用是,如果执行c.click(),则会取出Element.events[]数组中取出name为click的对象,然后执行其中的f()方法,进行事件调用。
注意:执行c.click()是直接进行了函数调用,而非c.node.addEventListener后,执行c.node.click()会报错,这是因为:
let div = document.getElementById('div')
div.addEventListener('click',function(){
alert('click')
})
div.click() // 执行成功
div.dispatchEvent(new Event('click')); // 执行成功我们对html元素绑定事件,可以直接执行div.click(),然而svg元素不行
// <svg id="svg" width="2000" height="1000"><desc>Created with Snap</desc><defs></defs><circle id="circle" cx="50" cy="50" r="40" fill="#ff0000" style=""></circle></svg>
let circle = document.getElementById('circle')
circle.addEventListener('click',function(){
alert('click')
})
circle.click() // 会报错
circle.dispatchEvent(new Event('click')) // 替代目前Snap.js唯一依赖于eve.js
-
onmove(function) handler for moving -
onstart(function) handler for drag start -
onend(function) handler for drag end -
mcontext(object) #optional context for moving handler -
scontext(object) #optional context for drag start handler -
econtext(object) #optional context for drag end handler
开始事件和句柄调用特定的上下文,或者元素自身带有如下参数的上下文:
-
x数值。鼠标x位置。 -
y数值。鼠标y位置。 -
event对象。DOM事件对象。
移动事件和句柄调用特定的上下文,或者元素自身带有如下参数的上下文:
-
dx数值。距离鼠标开始点的x偏移。 -
dx数值。距离鼠标开始点的y偏移。 -
x数值。鼠标x位置。 -
y数值。鼠标y位置。 -
event对象。DOM事件对象。
结束事件和句柄调用特定的上下文,或者元素自身带有如下参数的上下文:
-
event对象。DOM事件对象。
Adds event handlers for an element's drag gesture
var drag = [],
dragMove = function (e) {
var x = e.clientX,
y = e.clientY,
scrollY = getScroll("y"),
scrollX = getScroll("x"),
dragi,
j = drag.length;
while (j--) {
dragi = drag[j];
if (supportsTouch) {
var i = e.touches && e.touches.length,
touch;
while (i--) {
touch = e.touches[i];
if (touch.identifier == dragi.el._drag.id || dragi.el.node.contains(touch.target)) {
x = touch.clientX;
y = touch.clientY;
(e.originalEvent ? e.originalEvent : e).preventDefault();
break;
}
}
} else {
e.preventDefault();
}
var node = dragi.el.node,
o,
next = node.nextSibling,
parent = node.parentNode,
display = node.style.display;
// glob.win.opera && parent.removeChild(node);
// node.style.display = "none";
// o = dragi.el.paper.getElementByPoint(x, y);
// node.style.display = display;
// glob.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node));
// o && eve("snap.drag.over." + dragi.el.id, dragi.el, o);
x += scrollX;
y += scrollY;
eve("snap.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e);
}
},
dragUp = function (e) {
Snap.unmousemove(dragMove).unmouseup(dragUp);
var i = drag.length,
dragi;
while (i--) {
dragi = drag[i];
dragi.el._drag = {};
eve("snap.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e);
eve.off("snap.drag.*." + dragi.el.id);
}
drag = [];
};
// 添加Element.prototype.drag()方法
elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) {
var el = this;
// drag无参数,添加默认onmove,onstart事件
if (!arguments.length) {
var origTransform;
return el.drag(function (dx, dy) {
// onmove 后对当前element添加transform
this.attr({
transform: origTransform + (origTransform ? "T" : "t") + [dx, dy]
});
}, function () {
// onstart后 origTransform为当前element.transform().local
origTransform = this.transform().local;
});
}
// 如果drag有参数如:
/*
c.drag(()=> {
console.info(333)
})
*/
function start(e, x, y) {
(e.originalEvent || e).preventDefault();
el._drag.x = x;
el._drag.y = y;
el._drag.id = e.identifier;
// 注意这里是对document绑定mousemove和mouseup事件,而不是当前的Element
// 执行上面的dragMove和dragUp方法
!drag.length && Snap.mousemove(dragMove).mouseup(dragUp);
drag.push({el: el, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope});
onstart && eve.on("snap.drag.start." + el.id, onstart);
onmove && eve.on("snap.drag.move." + el.id, onmove);
onend && eve.on("snap.drag.end." + el.id, onend);
eve("snap.drag.start." + el.id, start_scope || move_scope || el, x, y, e);
}
function init(e, x, y) {
eve("snap.draginit." + el.id, el, e, x, y);
}
eve.on("snap.draginit." + el.id, start);
el._drag = {};
draggable.push({el: el, start: start, init: init});
// 为当前el只添加mousedown事件,对document添加了mousemove和mouseup事件
el.mousedown(init);
return el;
};
// 添加Element.prototype.undrag()方法
elproto.undrag = function () {
var i = draggable.length;
while (i--) if (draggable[i].el == this) {
this.unmousedown(draggable[i].init);
draggable.splice(i, 1);
eve.unbind("snap.drag.*." + this.id);
eve.unbind("snap.draginit." + this.id);
}
!draggable.length && Snap.unmousemove(dragMove).unmouseup(dragUp);
return this;
};示例1:
let svg = Snap("#svg");
let c1 = svg.paper.circle(50, 50, 40).drag();示例2:
let svg = Snap("#svg");
let path = svg.paper.path('M30 75 Q240 30, 300 120').attr({stroke:'green','stroke-width': 10, fill:'none'})
let origTransform
// 参照了源码
function onMove(dx, dy) {
this.attr({
transform: origTransform + (origTransform ? "T" : "t") + [dx, dy]
})
// 做其它事情
console.info(dx, dy)
}
function onStart () {
origTransform = this.transform().local;
}
// 如果参数存在,则按照源码再重写onMove和onStart函数
path1.drag(onMove, onStart)-
f_in函数。hover进入的事件句柄。 -
f_out函数。hover出来的事件句柄。 -
icontext函数。hover进入事件句柄的上下文。 -
ocontext函数。hover出来事件句柄的上下文。
// 同时为当前element绑定mouseover和mouseout事件
elproto.hover = function (f_in, f_out, scope_in, scope_out) {
return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in);
};
elproto.unhover = function (f_in, f_out) {
return this.unmouseover(f_in).unmouseout(f_out);
};示例:
let svg = Snap("#svg");
let c = svg.paper.circle(50, 50, 40).attr({
fill: "#f00"
}).hover(function() {
// 移入
this.animate({
fill: "#00f"
}, 1000);
}, function() {
// 移出
this.animate({
fill: "#f00"
}, 1000);
});