仓库源文站点原文


layout: post title: KineticJS教程3:事件响应与拖曳 categories:


<script src="/jscss/kinetic.min.js"></script>

2015-06-11 08:27:22

5. 事件响应

5.1. 图形的事件响应

图形对象对事件的响应处理可以使用on()方法绑定事件类型和相应方法. on()方法需要一个事件类型参数和相应方法, 其中所支持的事件类型包括: mouseover, mouseout, mousemove, mousedown, mouseup, click, dblclick, dragstart以及dragend事件. 默认情况下, 图形对象事件响应使用的是路径检测方法, 下一节还会介绍像素检测方法.

绑定代码如下:

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> shape.on("click", function(evt) { // 事件响应代码 }); </script> </code></pre>

如下代码绘制一个矩形, 并响应鼠标在此矩形上的点击操作, 弹出消息框:

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> window.onload = function() { var stage = new Kinetic.Stage({ container: "container", width: 600, height: 400 }); var layer = new Kinetic.Layer(); //创建config参数 var config = { x: 200, y: 150, width: 200, height: 100, fill: "blue", stroke: "black", strokeWidth: 4 }; //创建矩形对象 var rect = new Kinetic.Rect(config); //绑定事件响应方法 rect.on("click", function() { alert("clicked"); }); //把矩形对象添加到层里 layer.add(rect); //将层添加到舞台中 stage.add(layer); }; </script> </code></pre>

运行效果如下:

<div id="ctn_51" style="border:solid 2px #CCC;"></div>

<script> var stage = new Kinetic.Stage({ container: "ctn_51", width: 600, height: 400 }); var layer = new Kinetic.Layer(); var config = { x: 200, y: 150, width: 200, height: 100, fill: "blue", stroke: "black", strokeWidth: 4 }; var rect = new Kinetic.Rect(config); rect.on("click", function() { alert("clicked"); }); layer.add(rect); stage.add(layer); </script>

5.2. 像素检测

对于图像, 线条和文本之类的对象, 路径检测就不太合适, 这时就需要使用像素检测方法来响应事件. 为了使用像素检测, 就需要为图形图像对象的检测类型detectionType设置为像素检测pixel. 这个值默认是路径检测path.

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> // 在构造方法的config中指定检测类型 var image = new Kinetic.Image({ detectionType: "pixel" }); // 或者是用对象方法设定检测类型 image.setDetectionType("pixel"); </script> </code></pre>

然后, Kinetic还需要用对象的saveData()来保存数据才可以使用像素检测功能. 另外还可以用clearData()来清除保存的数据. 但要注意的是, saveData()需要在对象所在的层被添加到舞台上以后才能使用, 否则会出错.

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> // 保存图像数据 image.saveData(); // 清除图像数据 image.clearData(); </script> </code></pre>

示例代码如下:

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> var stage; function loadImage() { var image = new Image(); image.onload = function() { var kimage = new Kinetic.Image({ x: 100, y: 100, image: image, detectionType: "pixel" }); //绑定事件响应方法 kimage.on("click", function() { alert("image clicked"); }); var layer = new Kinetic.Layer(); layer.add(kimage); stage.add(layer); //保存数据以响应事件 kimage.saveData(); }; //图像需要与此页面在同一个服务器上, 否则会Javascript会抛出安全异常 image.src = "FSM.png"; } window.onload = function() { stage = new Kinetic.Stage({ container: "container", width: 600, height: 400 }); var rect = new Kinetic.Rect({ x: 400, y: 100, width: 100, height: 100, fill: "red", detectionType: "pixel" }); //绑定事件响应方法 rect.on("click", function() { alert("rect clicked"); }); var layer = new Kinetic.Layer(); layer.add(rect); stage.add(layer); //保存数据以响应事件 rect.saveData(); loadImage(); }; </script> </code></pre>

运行效果如下:

<div id="ctn_52" style="border:solid 2px #CCC;"></div>

<script> var stage; function loadImage() { var image = new Image(); image.onload = function() { var kimage = new Kinetic.Image({ x: 100, y: 100, image: image, detectionType: "pixel" }); kimage.on("click", function() { alert("image clicked"); }); var layer = new Kinetic.Layer(); layer.add(kimage); stage.add(layer); }; image.src = "FSM.png"; } stage = new Kinetic.Stage({ container: "ctn_52", width: 600, height: 400 }); var rect = new Kinetic.Rect({ x: 400, y: 100, width: 100, height: 100, fill: "red", detectionType: "pixel" }); rect.on("click", function() { alert("rect clicked"); }); var layer = new Kinetic.Layer(); layer.add(rect); stage.add(layer); loadImage(); </script>

5.3. 事件命名

对于同一个事件, 可以通过对事件进行命名绑定多个事件处理方法. 事件的命名格式遵循事件类型.自定义名称. 比如, 针对鼠标点击事件click, 可以命名两个事件处理方法click.aclick.b分别绑定各自的事件处理方法:

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js //创建矩形对象 var rect = new Kinetic.Rect(config); //绑定消息响应方法 rect.on("click.a", function() { alert("clicked a"); }); rect.on("click.b", function() { alert("clicked b"); }); //把矩形对象添加到层里 layer.add(rect); //将层添加到舞台中 stage.add(layer); </code></pre>

点击这个矩形的时候会依次调用这两个绑定的方法, 弹出两个消息框.

5.4. 鼠标位置的获取

在响应鼠标事件的时候常常需要获取鼠标位置信息, 这时可以在事件响应方法中使用舞台对象的getMousePosition方法获取鼠标位置:

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js //绑定事件响应方法 rect.on("click", function() { var mousePos = stage.getMousePosition(); var msg = "x:"+mousePos.x+" | "+"y:"+mousePos.y; alert(msg); }); </code></pre>

当然, 要注意的是, 这个坐标是相对于舞台左上角的, 而不是绑定的图像左上角.

5.5. 多事件绑定

如果希望同时响应多个不同的事件, 可以在on方法绑定事件处理方法的时候, 在事件参数中以空格分隔不同的事件, 如下代码在鼠标按下和移过的时候都调用此处理方法:

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> shape.on("mousedown mouseover", function(evt) { // 事件响应代码 }); </script> </code></pre>

5.6. 取消事件绑定

要取消对某个事件响应的绑定, 只需要用图形对象的off方法, 参数为要取消的事件名称, 如下代码取消了鼠标点击事件的响应:

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> shape.off("click"); </script> </code></pre>

对于有多个自定义命名的事件, 比如上文中的click.aclick.b, 使用shape.off("click")会将两个事件处理的绑定都取消掉, 如果只是单独取消其中某个, 可以如下操作:

shape.off("click.a");

shape.off("click.b");

5.7. 事件监听开关

Kinetic中还可以通过设定listening属性的方法来确定是否要监听事件. 如果设为false, 则绑定的事件响应方法会被忽略不执行.

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> // 在构造方法的config参数中设置 var shape = new Kinetic.Circle({ listening: false }); // 使用对象方法设置 shape.listen(true); </script> </code></pre>

5.8. 禁止事件向上级对象传递

如果某个图形对象属于某个组, 则某个发生在图形上的事件会被依次传递到图形对象, 组, 层, 那么如果这三者都绑定了此事件的相应方法, 那么这些方法也会被依次执行.

那么如果希望在本对象处理事件后事件不再继续向上级传递, 则可以在绑定事件处理方法时如下用方法的evt参数处理:

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> shape.on("click", function(evt) { evt.cancelBubble = true; }); </script> </code></pre>

5.9. 在事件处理方法中获取图形对象

同样也是用在绑定事件处理方法时方法的evt参数获取当前事件绑定的图形对象:

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> shape.on("click", function(evt) { var shape = evt.shape; }); </script> </code></pre>

然后就可以在事件处理方法中对图形对象进行操作了.

5.10. 触发事件响应方法

除了由用户交互操作出发事件而执行响应方法外, 还可以在代码里用simulate方法触发事件.

比如:

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> // 图形对象绑定了鼠标点击事件 shape.on("click", function(evt){ // 事件处理 }); // 触发事件鼠标点击事件 shape.simulate("click"); </script> </code></pre>

5.11. 移动设备的触摸屏事件响应

触摸屏的事件响应与普通电脑的响应处理方法类似, 只是事件类型的名称略有不同. Kinetic支持的触摸屏事件包括touchstart, touchmove, touchend, tap, dbltap, dragstart, dragmove以及dragend.

而触摸点坐标的获取就不是用getMousePosition(evt), 而是触摸屏专用方法getTouchPosition(evt)或者桌面与触摸屏通用方法getUserPosition(evt).

6. 拖拽

6.1. 拖拽功能

要实现Kinetic对象的拖拽功能很简单, 只需要将图形对象的draggable属性设为true就可以了.

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> // 在构造方法中的config参数设置 var shape = new Kinetic.Circle({ draggable: true; }); // 用图形对象的方法设置 shape.draggable(true); </script> </code></pre>

这种拖拽功能还可以应用到组(Group), 层(Layer)和舞台(Stage), 设置方法类似. 不过要注意的是, 应用到组或层上时, 拖拽组或层上的任一对象, 整个组或层都会移动, 而对于舞台, 拖拽舞台上任何位置都能移动整个舞台, 而无需拖拽舞台上的图形对象.

6.2. 拖拽线条

线条(Line)拖拽功能的设定与其他类型图形类似, 只是线条需要用像素检测功能, 因此需要线条所在层添加到舞台后执行一次saveData方法, 在拖拽动作结束事件处理方法中也要执行一次saveData方法.

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> // 在构造方法中的config中设定 var line= new Kinetic.Line({ draggable: true; }); // 使用对象的方法设定 line.draggable(true); // 保存像素数据 line.saveData(); //必须在每次拖拽完毕后执行一次saveData line.on("dragend", function() { blueLine.saveData(); }); </script> </code></pre>

完整代码:

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> window.onload = function() { var stage = new Kinetic.Stage({ container: "container", width: 600, height: 400 }); var layer = new Kinetic.Layer(); var line = new Kinetic.Line({ points: [ 100, 150, 340, 230 ], stroke: "blue", strokeWidth: 10, draggable: true }); layer.add(line); stage.add(layer); //保存像素数据 line.saveData(); //必须在每次拖拽完毕后执行一次saveData line.on("dragend", function() { blueLine.saveData(); }); }; </script> </code></pre>

6.3. 拖拽事件

有关拖拽的事件包括拖拽开始dragstart, 拖拽中dragmove, 拖拽结束dragend, 我们可以根据自己的需要绑定这几个事件响应方法.

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> shape.on("dragstart", function(evt) { // 响应代码 }; shape.on("dragmove", function(evt) { // 响应代码 }; shape.on("dragend", function(evt) { // 响应代码 }; </script> </code></pre>

6.4. 拖拽方向限制

Kinetic支持对拖拽运动限制在水平或者垂直方向上, 这个功能通过对象的dragConstraint属性进行设置来实现. dragConstraint属性可以有三个选项, 包括none, horizontalvertical, 默认情况下这个属性的值是none.

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> // 在构造方法中的config参数中设置, 拖动被限制在水平方向上 var shape = new Kinetic.Rect({ dragConstraint: "horizontal" }); // 用对象的方法设置, 拖动被限制在水平方向上 shape.setDragConstraint("horizontal"); </script> </code></pre>

6.5. 拖拽范围限制

Kinetic通过dragBounds属性的设置可以将拖拽限制在一个矩形范围之内. dragBounds属性包括top, right, bottomleft四个参数, 这四个参数可以只设置其中的几个, 不需要全部设置.

<pre class="line-numbers" data-start="0"><code class="language-javascript"># Language: js <script> // 在构造方法的config参数中设置 var shape = new Kinetic.Circle({ dragBounds: { top: 50 } }); // 在对象的方法中设置 shape.setDragBounds({ top: 0, left: 0, right: 200, bottom: 200 }); </script> </code></pre>