KineticJS教程

作者:ysm @ iysm.net

邮箱:cleverysm@gmail.com

注:参考 http://www.html5canvastutorials.com/kineticjs/html5-canvas-events-tutorials-introduction-with-kineticjs/ 完成此文。

1.基本结构

KineticJS首先是要绑定到HTML页面上的一个DOM容器元素上,比如最常用的<div>标签。KineticJS在此容器中创建一个称之为舞台(stage)的结构,这个舞台由一个不可见的后台层和一个不可见的缓冲层组成,提供了高性能的路径和像素检测能力。舞台上再包含若干(至少一层)用户层(layer),每个层上又包含有若干canvas元素,比如各种图形、图像、元素组(组可以包含其他的图形和其他的组)等。用户还可以给这些层上的图形、元素组、层本身以及舞台本身添加事件监听方法,以响应鼠标、键盘等事件。浏览器最终显示的就是这些用户层的叠加效果。

原始图像来源:http://www.kineticjs.com/how-it-works.php

2.第一个画面

现在我们开始用Kinetic制作我们的第一个画面。

Kinetic绘图的基本的流程可以如下图所示:  

首先是创建一个HTML5页面,在<head>里添加对Kinetic库的引用: 

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

<body>中添加一个用于绑定到Kinetic用于创建舞台的容器,比如说可以是个<div> 

<div id="container"></div> 

我们的Kinetic图像就将在这个容器中完成绘制。

在本例中,我们打算创建一个600×400的舞台,并在中心位置画一个红色矩形框。 

同样是在<head>中添加脚本:

< script >
    //在页面加载时进行绘图 
    window.onload = function() {
        //创建Kinetic舞台,绑定我们添加的<div>容器 
        var stage = new Kinetic.Stage({
            container: "container", //<div>的id 
            width: 600, //创建的舞台宽度 
            height: 400 //创建的舞台高度 
        });

        //创建Kinetic用户层
        var layer = new Kinetic.Layer();
        //创建一个Kinetic矩形对象 
        var rect = new Kinetic.Rect({
            x: 200, //矩形左上角x坐标 
            y: 150, //矩形左上角y坐标 
            width: 200, //矩形的宽度 
            height: 100, //矩形的高度 
            fill: "red", //矩形的填充色 
            stroke: "black", //矩形边缘线的颜色
            strokeWidth: 4 //矩形边缘线的宽度
        });
        //向用户层中添加上面的矩形 
        layer.add(rect);
        //将上面的用户层添加到舞台上 
        stage.add(layer);
        stage.draw();
    };
</script>

用浏览器打开页面就能看到如下的图像了:

3.图形对象

3.1.Shape

Kinetic提供了一个Shape对象用于在层上绘制图形,我们可以通过Kinetic.Shape()构造方法返回一个Shape对象:

<script>
var shape = new Kinetic.Shape(config);
</script>

Shape方法的config参数是关于具体的绘图参数的数组对象,Kinetic就是根据这个参数里的具体信息进行绘图的。

Config的完整参数如下表所示:

Property

Description

Default

Required

drawFunc

draw function

-

required

fill

can be a color, linear gradient, radial gradient, or pattern

-

optional

stroke

stroke color

-

optional

strokeWidth

stroke width

-

optional

lineJoin

can be miterround, or bevel

miter

optional

shadow

shadow object

-

optional

detectonType

can be path or pixel

path

optional

x

x position

0

optional

y

y position

0

optional

visible

whether or not the shape is visible

true

optional

listening

whether or not to listen to events

true

optional

id

unique shape id

-

optional

name

shape name

-

optional

alpha

shape opacity

1

optional

scale

shape scale

[1,1]

optional

rotation

rotation about the center point in radians

0

optional

rotationDeg

rotation about the center point in degrees

0

optional

centerOffset

center offset

[0,0]

optional

draggable

whether or not the shape is draggable

false

optional

dragConstraint

can be nonehorizontal, or vertical

none

optional

dragBounds

drag and drop bounds

-

optional

其中最重要的参数就是drawFunc,这是一个由用户创建的方法对象,Kinetic绘图时就是调用的这个方法。

比如我们可以如下在页面上画一个矩形:

<!DOCTYPE html>
<html>
<head>
    <meta charset=“UTF-8″>
    <title>KineticJS</title>
    <script src=“../kinetic.js”></script>
</head>
<body>
    <script>
        window.onload = function() {
            //创建舞台
            var stage = new Kinetic.Stage({
                container: “container”,
                width: 600,
                height: 400
            });

            var layer = new Kinetic.Layer();
            //创建config参数
            var config = {
                //绘图方法,画一个矩形
                drawFunc: function() {
                    var context = this.getContext();
                    context.rect(200, 150, 200, 100);
                    this.fill();
                    this.stroke();
                },
                //填充色
                fill: “green”,
                //边缘线颜色
                stroke: “black”,
                //边缘线宽度
                strokeWidth: 4
            };
            //创建Shape对象
            var rectShape = new Kinetic.Shape(config);
            //把Shape对象添加到层里
            layer.add(rectShape);
            //将层添加到舞台中
            stage.add(layer);
        };
    </script>
    <div id=“container”></div>
</body>
</html>

 

3.2.常用图形

Kinetic除了有Shape可以用于绘图外,还为我们提供了一系列用于常见图形绘制的对象,包括矩形(Rect)、圆(Circle)、图像(Image)、精灵(Sprite)、文本(Text)、线(Line)、多边形(Polygon)、常用多边形(Regular Polygon)、路径(Path)、星星(Star)几种。

这几个图形对象都是继承自Shape,所以使用方法与Shape类似,以一个config对象指定绘图细节,与Shape不同的是,不需要我们指定drawFunc,只需要根据图形的类型指定关键参数就可以了。

在此,我们以Shape.Rect为例,绘制矩形图形的代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>KineticJS</title>
    <script src="../kinetic.js"></script>
</head>
<body>
    <script>
        window.onload = function () {
            var stage = new Kinetic.Stage({
                container: "container",
                width: 600,
                height: 400
            });
            var layer = new Kinetic.Layer();
            //创建config参数
            var config = {
                //左上角x坐标
                x: 200,
                //左上角y坐标
                y: 150,
                //矩形宽度
                width: 200,
                //矩形高度
                height: 100,
                //填充色
                fill: "blue",
                //边缘线颜色
                stroke: "black",
                //边缘线宽度
                strokeWidth: 4
            };

            //创建Shape对象
            var rect = new Kinetic.Rect(config);
            //把Shape对象添加到层里
            layer.add(rect);
            //将层添加到舞台中
            stage.add(layer);
        };
    </script>
    <div id="container"></div>
</body>
</html>

具体每种图形的config参数细节可以参见Kinetic的文档。

 

3.3.图形组

Kinetic提供了Group对象,用于把若干个不同的图形对象,或者是其他的Group对象组合成一个复杂的图形进行统一管理。

比如,我们创建一个包含一个矩形和一个圆的group,并添加到层中显示出来。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>KineticJS</title>
    <script src="../kinetic.js"></script>
</head>
<body>
    <script>
        window.onload = function () {
            var stage = new Kinetic.Stage({
                container: "container",
                width: 600,
                height: 400
            });

            var layer = new Kinetic.Layer();

            //创建一个要加进组中的圆
            var circle = new Kinetic.Circle({
                x: 200,
                y: 100,
                radius: 50,
                fill: "red"
            });

            //创建一个要加进组中的矩形
            var rect = new Kinetic.Rect({
                x: 300,
                y: 200,
                width: 100,
                height: 100,
                fill: "blue"
            });

            //创建group对象
            var group = new Kinetic.Group();
            //把多个图形对象添加到group里
            group.add(circle);
            group.add(rect);
            //把group对象添加到层里
            layer.add(group);
            //将层添加到舞台中
            stage.add(layer);
        };
    </script>
    <div id="container"></div>
</body>
</html>

由于Group继承自Node,而Shape也是继承自Node,因此,Group的一些属性和行为也和Shape比较类似,比如Group的构造方法也可以像接受一个config参数配置Group的位置、旋转、缩放等属性。

如:

var config = {
  x: 220,
  y: 40,
  rotationDeg: 20
};

或者也可以不在创建group时通过config参数设定,而是创建group对象后通过相对应的方法设定各属性,比如xy参数就可以分别用group.setX(220)group.setY(20)来设定。


4.图形样式

4.1.填充

Kinetic中图形的填充属性可以在构造方法中的config参数中的fill属性进行设定,也可以用图形对象的setFill方法进行设定。不过要注意,setFill使用的填充类型必须与创建这个对象时的config中所用的填充类型相同。

Kinetic支持颜色、图像、线性渐变和径向渐变四种填充模式。

4.1.1.颜色填充

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>KineticJS</title>
    <script src="../kinetic.js"></script>
</head>
<body>
    <script>
        window.onload = function () {
            var stage = new Kinetic.Stage({
                container: "container",
                width: 600,
                height: 400
            });

            var layer = new Kinetic.Layer();
            //创建第一个矩形对象的config参数
            var config1 = {
                x: 100,
                y: 150,
                width: 100,
                height: 100,
                //填充色
                fill: "blue"
            };

            //创建第一个矩形对象
            var rect1 = new Kinetic.Rect(config1);
            //创建第二个矩形对象的config参数
            var config2 = {
                x: 400,
                y: 150,
                width: 100,
                height: 100,
                //填充色
                fill: "red"
            };

            //创建第二个矩形对象
            var rect2 = new Kinetic.Rect(config2);

            //修改第二个矩形对象的颜色
            rect2.setFill("green");
            layer.add(rect1);
            layer.add(rect2);
            stage.add(layer);
        };
    </script>
    <div id="container"></div>
</body>
</html>

 

4.1.2.线性渐变填充

线性渐变填充的fill参数值如下:

{ start: { x: 100, y: 50 }, end: { x: 500, y: 50 }, colorStops: [0, "red", 0.5, "green", 1, "blue"] }

的形式,start是线性渐变线的起点位置,end是线性渐变线的终点位置,colorStops是指定线性渐变线上关键点的颜色值,位置参数是一个介于01之间的浮点数,0表示起点的颜色,1表示终点的颜色。

这里要注意的是,渐变线的坐标基点并不是以canvas左上角为(0, 0)点,如果是图形对象是矩形的话,矩形的左上角点才是(0, 0)点,如果是圆形对象的话,圆心才是(0, 0)点。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>KineticJS</title>
    <script src="../kinetic.js"></script>
</head>
<body>
    <script>
        window.onload = function () {
            var stage = new Kinetic.Stage({
                container: "container",
                width: 600,
                height: 400
            });

            var layer = new Kinetic.Layer();

            //创建第一个矩形对象的config参数
            var config1 = {
                x: 100,
                y: 50,
                width: 400,
                height: 100,
                //渐变色
                fill: {
                    start: {
                        x: 0,
                        y: 50
                    },
                    end: {
                        x: 400,
                        y: 50
                    },
                    colorStops: [0, "red", 0.5, "green", 1, "blue"]
                }
            };

            //创建第一个矩形对象
            var rect1 = new Kinetic.Rect(config1);

            //创建第二个矩形对象的config参数
            var config2 = {
                x: 100,
                y: 200,
                width: 400,
                height: 100,
                //渐变色
                fill: {
                    start: {
                        x: 0,
                        y: 50
                    },
                    end: {
                        x: 400,
                        y: 50
                    },
                    colorStops: [0, "red", 0.5, "green", 1, "blue"]
                }
            };

            //创建第二个矩形对象
            var rect2 = new Kinetic.Rect(config2);

            //修改第二个矩形对象的颜色变化模式
            rect2.setFill({
                start: {
                    x: 100,
                    y: 50
                },
                end: {
                    x: 400,
                    y: 50
                },
                colorStops: [0, "yellow", 0.5, "cyan", 1, "purple"]
            });

            layer.add(rect1);
            layer.add(rect2);
            stage.add(layer);
        };
    </script>
    <div id="container"></div>
</body>
</html>

 

上述代码的渐变效果图如下:

上面的矩形渐变线为(0, 50)(400, 50),正如上面提到的,这里的渐变线是以这个矩形的左上角为(0, 0)点的,所以实际的渐变线是如黑线条所示的区域,而下面的矩形由于setFill的修改,渐变线为(100, 50)(400, 50),所以实际渐变线是图上所示的黑线区域,而不是整个矩形的范围。不要把渐变线的坐标理解为相对于canvas的左上角。

4.1.3.径向渐变填充

径向渐变填充的fill参数值如下:

{ start: { x: 100, y: 50, radius: 100 }, end: { x: 500, y: 50, radius: 100 }, colorStops: [0, "red", 0.5, "green", 1, "blue"] }

的形式,start是径向渐变的起始圆位置,end是径向渐变的终止圆位置,colorStops是指定径向渐变圆间的关键距离的颜色值,位置参数是一个介于01之间的浮点数,0表示起始圆的颜色,1表示终止圆的颜色。

这里要注意的是,与线性渐变类似,渐变圆的圆心坐标基点并不是以canvas左上角为(0, 0)点,如果是图形对象是矩形的话,矩形的左上角点才是(0, 0)点,如果是圆形对象的话,圆心才是(0, 0)点。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>KineticJS</title>
    <script src="../kinetic.js"></script>
</head>
<body>
    <script>
        window.onload = function () {
            var stage = new Kinetic.Stage({
                container: "container",
                width: 600,
                height: 400
            });
            var layer = new Kinetic.Layer();
            //创建第一个圆形对象的config参数
            var config1 = {
                x: 150,
                y: 200,
                radius: 100,
                //渐变色
                fill: {
                    start: {
                        x: 0,
                        y: 0,
                        radius: 0
                    },
                    end: {
                        x: 0,
                        y: 0,
                        radius: 100
                    },
                    colorStops: [0, "red", 0.5, "green", 1, "blue"]
                }
            };
            //创建第一个圆形对象
            var circle1 = new Kinetic.Circle(config1);
            //创建第二个圆形对象的config参数
            var config2 = {
                x: 450,
                y: 200,
                radius: 100,
                //渐变色
                fill: {
                    start: {
                        x: 0,
                        y: 0,
                        radius: 0
                    },
                    end: {
                        x: 0,
                        y: 0,
                        radius: 100
                    },
                    colorStops: [0, "red", 0.5, "green", 1, "blue"]
                }
            };
            //创建第二个圆形对象
            var circle2 = new Kinetic.Circle(config2);
            //修改第二个矩形对象的颜色变化模式
            circle2.setFill({
                start: {
                    x: 0,
                    y: 0,
                    radius: 0
                },
                end: {
                    x: 0,
                    y: 0,
                    radius: 100
                },
                colorStops: [0, "yellow", 0.5, "cyan", 1, "purple"]
            });
            layer.add(circle1);
            layer.add(circle2);
            stage.add(layer);
        };
    </script>
    <div id="container"></div>
</body>
</html>

 

上述代码的效果如下图:

 4.1.4.图像填充

图像填充的fill参数值如下:

{ image : imageObj, offset : { x : 0, y : 0 }

imageObjjavascriptImage对象,offset是图像开始填充的位置偏移量。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>KineticJS</title>
    <script src="../kinetic.js"></script>
</head>
<body>
    <script>
        function draw(image) {
            var stage = new Kinetic.Stage({
                container: "container",
                width: 600,
                height: 400
            });
            var layer = new Kinetic.Layer();
            //创建第一个矩形config参数
            var config1 = {
                x: 50,
                y: 100,
                width: 180,
                height: 180,
                //填充图像
                fill: {
                    image: image,
                    offset: {
                        x: 0,
                        y: 0
                    }
                }
            };
            var rect1 = new Kinetic.Rect(config1);
            //创建第二个矩形config参数
            var config2 = {
                x: 350,
                y: 100,
                width: 180,
                height: 180,
                //填充图像,并将填充图像向右下移动50个像素
                fill: {
                    image: image,
                    offset: {
                        x: 0,
                        y: 0
                    }
                }
            };
            var rect2 = new Kinetic.Rect(config2);
            //将填充图像向左上移动50个像素
            rect2.setFill({
                //image : image,
                offset: {
                    x: -50,
                    y: -50
                }
            });
            layer.add(rect1);
            layer.add(rect2);
            stage.add(layer);
        }
        window.onload = function () {
            var image = new Image();
            image.onload = function () {
                draw(image);
            };
            image.src = ". / FSM.jpg";
        };
    </script>
    <div id="container"></div>
</body>
</html>

上述代码的效果如下图:

4.2.线条颜色与宽度

线条对象与其他图形的边缘线的颜色与宽度设置如下:

<script>
    // 使用构造方法的config参数设置
    var shape = new Kinetic.Circle({
        stroke: "black",
        strokeWidth: 4
    });

    // 用图形对象的方法设置
    shape.setStroke("blue");
    shape.setStrokeWidth(20);
</script>

 

4.3.透明

透明度是一个01之间的浮点值,0表示完全透明,1则是完全不透明。

<script>
    // 使用构造方法的config参数设置
    var shape = new Kinetic.Circle({
        alpha: 0.5
    });
    // 用图形对象的方法设置
    shape.setAlpha(1);
</script>

 

4.4.阴影

<script>
    // 使用构造方法的config参数设置
    var shape = new Kinetic.Circle({
        shadow: {
            color: "black",
            blur: 10,
            offset: [10, 10],
            alpha: 0.5
        }
    });
    // 用图形对象的方法设置
    shape.setShadow({
        color: "black",
        blur: 10,
        offset: [10, 10],
        alpha: 0.5
    });
</script>

 

4.5.线段间连接点样式

连接点的样式可以是 miter  bevel  round。其中,默认的样式是 miter

<script>
    // 使用构造方法的config参数设置
    var shape = new Kinetic.Circle({
        lineJoin: "bevel"
    });
    // 用图形对象的方法设置
    shape.setLineJoin("round");
</script>

 

4.6.图形的隐藏与显示

<script>
    // 使用构造方法的config参数设置
    var shape = new Kinetic.Circle({
        visible: false
    });
    // 用图形对象的show方法显示图形
    shape.show();
    // 用图形对象的hide方法隐藏图形
    shape.hide();
</script>

 

5.事件响应

5.1.图形的事件响应

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

绑定代码如下:

<script>
    shape.on("click", function (evt) {
        // 事件响应代码
    });
</script>

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

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>KineticJS</title>
    <script src="../kinetic.js"></script>
</head>

<body>
    <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>
    <div id="container"></div>
</body>

</html>

 

5.2.像素检测

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

<script>
    // 在构造方法的config中指定检测类型
    var image = new Kinetic.Image({
        detectionType: "pixel"
    });
    // 或者是用对象方法设定检测类型
    image.setDetectionType("pixel");
</script>

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

<script>
    // 保存图像数据
    image.saveData();
    // 清除图像数据
    image.clearData();
</script>
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>KineticJS</title>
    <script src="../kinetic.js"></script>
</head>

<body>
    <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 = "http://localhost/FSM.jpg";
        }
        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>
    <div id="container"></div>
</body>

</html>

 

5.3.事件命名

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

//创建矩形对象
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);

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

5.4.鼠标位置的获取

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

//绑定事件响应方法
rect.on("click", function() {
    var mousePos = stage.getMousePosition();
    var msg = "x:" + mousePos.x + " | " + "y:" + mousePos.y;
    alert(msg);
});

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

5.5.多事件绑定

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

<script>
    shape.on("mousedown mouseover", function (evt) {
        // 事件响应代码
    });
</script>

 

5.6.取消事件绑定

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

<script>
shape.off("click");
</script>

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

<script>
shape.off("click.a");
</script>

<script>
shape.off("click.b");
</script>

 

5.7.事件监听开关

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

<script>
    // 在构造方法的config参数中设置
    var shape = new Kinetic.Circle({
        listening: false
    });

    // 使用对象方法设置
    shape.listen(true);
</script>

 

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

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

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

<script>
    shape.on("click", function (evt) {
        evt.cancelBubble = true;
    });
</script>

 

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

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

<script>
    shape.on("click", function (evt) {
        var shape = evt.shape;
    });
</script>

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

5.10.触发事件响应方法

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

比如:

<script>
    // 图形对象绑定了鼠标点击事件
    shape.on("click", function (evt) {
        // 事件处理
    });

    // 触发事件鼠标点击事件
    shape.simulate("click");
</script>

 

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

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

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


 6.拖拽

6.1.拖拽功能

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

<script>
    // 在构造方法中的config参数设置
    var shape = new Kinetic.Circle({
        draggable: true
    });

    // 用图形对象的方法设置
    shape.draggable(true);
</script>

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

6.2.拖拽线条

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

<script>
    // 在构造方法中的config中设定
    var line = new Kinetic.Line({
        draggable: true
    });

    // 使用对象的方法设定
    line.draggable(true);

    // 保存像素数据
    line.saveData();

    //必须在每次拖拽完毕后执行一次saveData
    line.on("dragend", function () {
        blueLine.saveData();
    });
</script>

完整代码:

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="UTF-8">
    <title>KineticJS</title>
    <script src="../kinetic.js"></script>
</head>

<body>
    <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>
    <div id="container"></div>
</body>

</html>

 

6.3.拖拽事件

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

<script>
    shape.on("dragstart", function (evt) {
        // 响应代码
    })

    shape.on("dragmove", function (evt) {
        // 响应代码
    })

    shape.on("dragend", function (evt) {
        // 响应代码
    })
</script>

 

6.4.拖拽方向限制

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

<script>
    // 在构造方法中的config参数中设置,拖动被限制在水平方向上
    var shape = new Kinetic.Rect({
        dragConstraint: "horizontal"
    });

    // 用对象的方法设置,拖动被限制在水平方向上
    shape.setDragConstraint("horizontal");
</script>

 

6.5.拖拽范围限制

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

<script>
    // 在构造方法的config参数中设置
    var shape = new Kinetic.Circle({
        dragBounds: {
            top: 50
        }
    });
    // 在对象的方法中设置
    shape.setDragBounds({
        top: 0,
        left: 0,
        right: 200,
        bottom: 200
    });
</script>

 

7.图形变换

7.1.线性变化

Kinetic提供了一个图形对象的transitionTo(config)方法实现图形的线性变换,也就是从原始的状态线性变换到新的状态,这里的状态是指的尺度上的参数。方法的config参数也就是有关图形尺度的一些参数,比如 x y rotation width height radius strokeWidth alpha scalecenterOffset等。除了这些尺度参数,还需要一个duration参数,单位是秒,也就是指定这种线性变换是在多长时间内变换完成。

比如,下面代码实现图形在两秒钟内从原位置移动到横坐标100处,并逐渐变成透明:

<script>
    shape.transitionTo({
        x: 100,
        alpha: 0,
        duration: 2
    });
</script>

 

7.2.变换中的速度

KinetictransitionTo(config)方法中的config参数包括一个easing属性,是指的变换是以较均匀的速度到达变换目的点还是在变换过程中在不同位置以不同速度进行变换。Easing可以设定的值包括ease-in ease-out ease-in-out back-ease-in back-ease-out back-ease-in-out elastic-ease-in elastic-ease-out elastic-ease-in-out bounce-ease-inbounce-ease-out bounce-ease-in-out strong-ease-in strong-ease-out以及strong-ease-in-out

在文章里很难形容这些值之间的不同,还是具体写成代码,在浏览器里看效果吧。

<script>
    shape.transitionTo({
        x: 100,
        duration: 1,
        easing: 'ease-out'
    });
</script>

 

7.3.变换完成后的回调方法

KinetictransitionTo(config)方法中的config参数还包括一个回调方法属性,这个方法会在变换完成后被执行。

<script>
    shape.transitionTo({
        x: 100,
        duration: 1,
        easing: "bounce-ease-out",
        callback: function () {
            alert("transition complete!");
        }
    });
</script>

 

7.4.变换的开始与结束

当执行transitionTo方法的时候可以返回一个对象变量,并用这个对象的 start() stop() resume()方法来启动、停止和恢复转换的执行。

<script>
    var trans = shape.transitionTo(config);
    // 开始转换
    trans.start();
    // 停止转换
    trans.stop();
    // 恢复转换
    trans.resume();
</script>

 

 8.动画

动画就是一帧帧的画面按照时间间隔显示出来,Kinetic给我们提供了一个舞台对象的onFrame方法,用这个方法可以绑定一个动画方法,我们要显示的动画的每一帧画面就是在这个方法中完成绘制的。

其中,这个方法接受一个对象frame为参数,此参数对象包含两个属性,一个是frame.time,表示当前帧是动画开始后的毫秒数,另一个属性是 frame.timeDiff,表示的是当前帧与上一帧之间的时间毫秒差。当前帧因该是什么形态就是根据这两个事件来判断的。绘制出当前帧后,注意要调用一下动画所在的层的draw,将当前帧图像显示到屏幕上。

<script>
    stage.onFrame(function (frame) {
        // update position
        // draw layer
    });
</script>

如下代码显示了一个左右摆动的圆形

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8 ">
<title>KineticJS</title>
<script src="../kinetic.js">
    </script>
</head>

<body>
    <script>
        window.onload = function () {
            var stage = new Kinetic.Stage({
                container: "container",
                width: 600,
                height: 400
            });
            var layer = new Kinetic.Layer();
            var config = {
                x: 300,
                y: 200,
                radius: 30,
                fill: "red",
                stroke: "black",
                strokeWidth: 5
            };
            var circle = new Kinetic.Circle(config);
            layer.add(circle);
            stage.add(layer);
            var amplitude = 150;
            var period = 2000;
            var centerX = stage.getWidth() / 2;
            //动画帧定义方法
            stage.onFrame(function (frame) {
                circle
                    .setX(amplitude *
                        Math.sin(frame.time * 2 * Math.PI / period) +
                        centerX);
                layer.draw();
            });
            //动画开始
            stage.start();
            //动画停止
            //stage.stop();
        };
    </script>
    <div id="container "></div>
</body>
</html>

动画的开始与停止是用舞台对象的startstop方法实现的。

<script>
    var stage = new Kinetic.Stage({

    });

    //动画开始
    stage.start();
    //动画停止
    stage.stop();
</script>

 

 9.选择器

Kinetic在舞台、层和组对象上都提供了get方法,用于返回这三者中包含的对象。

9.1.根据ID获取对象

要用id获取对象,首先要给对象赋予一个id,比如下面代码创建的Rectid就是id1

<script>
    var rect = new Kinetic.Rect({
        id: "id1"
    });
</script>

要注意的是,id是唯一的,不同对象不能使用相同的id,否则get也只能返回其中的一个。

然后用get方法,id选择符#”为参数获取对象:

<script>
    var obj = stage.get("#id1")[0];
    var obj = layer.get("#id1")[0];
    var obj = group.get("#id1")[0];
</script>

这个地方要注意,这个get返回的是一个数组,即便id是唯一的,所以要得到所要的对象,必须带上数组的索引。

9.2.根据名称获取对象

要用名称获取对象,首先要给对象赋予一个name名称,比如下面代码创建的Rect的名称就是name1

<script>
    var rect = new Kinetic.Rect({
        name: "name1"
    });
</script>

id不同,name不是唯一的,不同对象是可以共用相同的name的。

然后用get方法,id选择符.”为参数获取对象:

<script>
    var objs = stage.get(".name1");
    var objs = layer.get(".name1");
    var objs = group.get(".name1");
</script>

这个地方要注意,这个get返回的是一个数组,包含所有叫这个名字的对象。


10.在容器之间移动图形对象

Kinetic支持通过图形对象的moveTo(container)方法把图形对象从一个容器移动到另一个容器里,这个容器指的可以是另一个舞台(Stage)、一个层(Layer)或是一个组(Group)。另外也可以把一个组(Group)移动到另一个组中或者层里,也可以把图形从一个组移动到另一个层里。

<script>
    shape.moveTo(layer);
</script>

 

11.对象的上下关系

11.1.层的上下关系

Kinetic的层是按照添加到舞台的次序,由下向上排列,上层遮盖下层的图形。每个层各自有一个ZIndex编号来表示在层级中的上下位置,编号从0开始,表示最底层,向上层依次增1

Kinetic提供了几个方法用于调整层的上下层位置,包括:

<script>
    //移动到最上层
    layer.moveToTop();
    //移动到最下层
    layer.moveToBottom();
    //向上移动一层
    layer.moveUp();
    //向下移动一层
    layer.moveDown();
    //设定层的ZIndex值
    layer.setZIndex(5);
</script>

如下代码通过点击某层上圆将所圆所在层调整至最上层:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>KineticJS</title>
    <script src="../kinetic.js"></script>
</head>

<body>
    <script>
        window.onload = function () {
            var stage = new Kinetic.Stage({
                container: "container",
                width: 600,
                height: 400
            });
            var layer1 = new Kinetic.Layer();
            var layer2 = new Kinetic.Layer();
            var layer3 = new Kinetic.Layer();
            var config1 = {
                x: 200,
                y: 200,
                radius: 100,
                height: 100,
                fill: "red",
                stroke: "black",
                strokeWidth: 4
            };
            var circle1 = new Kinetic.Circle(config1);
            var config2 = {
                x: 250,
                y: 200,
                radius: 100,
                height: 100,
                fill: "green",
                stroke: "black",
                strokeWidth: 4
            };
            var circle2 = new Kinetic.Circle(config2);
            var config3 = {
                x: 300,
                y: 200,
                radius: 100,
                height: 100,
                fill: "blue",
                stroke: "black",
                strokeWidth: 4
            };
            var circle3 = new Kinetic.Circle(config3);
            layer1.add(circle1);
            layer2.add(circle2);
            layer3.add(circle3);
            layer1.on("click", function () {
                alert("from Z index:" + this.getZIndex());
                //将本层移动至最上层
                this.moveToTop();
                alert("to Z index:" + this.getZIndex());
            });
            layer2.on("click", function () {
                alert("from Z index:" + this.getZIndex());
                //将本层移动至最上层
                this.moveToTop();
                alert("to Z index:" + this.getZIndex());
            });
            layer3.on("click", function () {
                alert("from Z index:" + this.getZIndex());
                //将本层移动至最上层
                this.moveToTop();
                alert("to Z index:" + this.getZIndex());
            });
            //将层添加到舞台中
            stage.add(layer1);
            stage.add(layer2);
            stage.add(layer3);
        };
    </script>
    <div id="container"></div>
</body>

</html>

 

11.2.图形对象的上下关系

在某一层中的各图形对象也有类似于层之间的上下层叠关系,由下向上排列,上层图形对象遮盖下层的图形对象。每个图形对象各自有一个ZIndex编号来表示在层级中的上下位置,编号从0开始,表示最底层,向上层依次增1

Kinetic提供了几个方法用于调整图形对象的上下层位置,包括:

<script>
    //移动到最上层
    shape.moveToTop();
    //移动到最下层
    shape.moveToBottom();
    //向上移动一层
    shape.moveUp();
    //向下移动一层
    shape.moveDown();
    //设定层的ZIndex值
    shape.setZIndex(5);
</script>

如下代码通过点击圆将所点击的圆调整至其所在层中各圆的最上层:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>KineticJS</title>
    <script src="../kinetic.js"></script>
</head>

<body>
    <script>
        window.onload = function () {
            var stage = new Kinetic.Stage({
                container: "container",
                width: 600,
                height: 400
            });
            var layer = new Kinetic.Layer();
            var config1 = {
                x: 200,
                y: 200,
                radius: 100,
                height: 100,
                fill: "red",
                stroke: "black",
                strokeWidth: 4
            };
            var circle1 = new Kinetic.Circle(config1);
            circle1.on("click", function () {
                alert("from Z index:" + this.getZIndex());
                //将本对象移动到本层所有对象中的最上面
                this.moveToTop();
                //重绘对象所在本层
                layer.draw();
                alert("to Z index:" + this.getZIndex());
            });
            var config2 = {
                x: 250,
                y: 200,
                radius: 100,
                height: 100,
                fill: "green",
                stroke: "black",
                strokeWidth: 4
            };
            var circle2 = new Kinetic.Circle(config2);
            circle2.on("click", function () {
                alert("from Z index:" + this.getZIndex());
                //将本对象移动到本层所有对象中的最上面
                this.moveToTop();
                //重绘对象所在本层
                layer.draw();
                alert("to Z index:" + this.getZIndex());
            });
            var config3 = {
                x: 300,
                y: 200,
                radius: 100,
                height: 100,
                fill: "blue",
                stroke: "black",
                strokeWidth: 4
            };
            var circle3 = new Kinetic.Circle(config3);
            circle3.on("click", function () {
                alert("from Z index:" + this.getZIndex());
                //将本对象移动到本层所有对象中的最上面
                this.moveToTop();
                //重绘对象所在本层
                layer.draw();
                alert("to Z index:" + this.getZIndex());
            });
            layer.add(circle1);
            layer.add(circle2);
            layer.add(circle3);
            //将层添加到舞台中
            stage.add(layer);
        };
    </script>
    <div id="container"></div>
</body>

</html>

 

12.舞台

12.1.舞台的大小

舞台创建后还可以用舞台对象的setSize(width, height)方法来设置舞台的宽度与高度。

<script>
    stage.setSize(300, 100);
</script>

 

12.2.舞台的缩放

舞台创建后还可以用舞台对象的setScale()方法来对舞台进行缩放。setScale方法可以接受一个参数,也可以接受两个参数,一个参数是指的横向与纵向均以相同比例缩放,两个参数则是分别设定横向与纵向的缩放比例。参数是不小于0的浮点数,表示缩放的比例,小于1表示缩小,大于1表示放大。另外,缩放是以舞台的左上角为基点的。

<script>
    // 横纵方向等比例缩放
    stage.setScale(scale);
    // 分别制定横纵方向上的缩放比例
    stage.setScale(scaleX, scaleY);
</script>

 

12.3.获取数据URL

Kinetic为舞台对象提供了一个toDataURL方法,可以让用户获得舞台的数据URL信息。toDataURL接受一个方法对象,这个方法至少接受一个参数dataURL保存的既是数据URL。除了这个dataURL参数外,还接受两个参数,一个是mimeType,保存的是数据URL指向数据的mime文件格式,另一个参数是quality,是一个01的浮点数,保存的是数据的质量。

用户就可以在这个方法里对数据URL进行处理了。

<script>
    stage.toDataURL(function (dataUrl, mimeType, quality) {
        // 在这里对dataUrl、 mimeType、 quality 信息进行处理
    });
</script>

 

12.4.将舞台保存成JSON数据

将舞台数据保存成JSON数据只需要执行舞台对象的toJSON方法即可。

<script>
    var json = stage.toJSON();
</script>

 

12.5.JSON数据加载回舞台

将舞台数据保存成JSON数据只需要执行舞台对象的load方法即可。

<script>
    // 创建舞台对象
    var stage = new Kinetic.Stage({
        container: "container",
        width: 600,
        height: 400
    });
    // 加载舞台
    stage.load(json);
</script>

这个地方要注意,对于事件处理和图像,是不能被序列化成JSON的,需要在加载JSON数据后在加载图像并设定这些事件处理方法

 

//在页面加载时进行绘图 
window.onload = function() {
    //创建Kinetic舞台,绑定我们添加的<div>容器 
    var stage = new Kinetic.Stage({
        container: "container", //<div>的id 
        width: 600, //创建的舞台宽度 
        height: 400 //创建的舞台高度 
    });
    //创建Kinetic用户层
    var layer = new Kinetic.Layer();
    //创建一个Kinetic矩形对象 
    var rect = new Kinetic.Rect({
        x: 200, //矩形左上角x坐标 
        y: 150, //矩形左上角y坐标 
        width: 200, //矩形的宽度 
        height: 100, //矩形的高度 
        fill: "red", //矩形的填充色 
        stroke: "black", //矩形边缘线的颜色
        strokeWidth: 4 //矩形边缘线的宽度
    });
    //向用户层中添加上面的矩形 
    layer.add(rect);
    //将上面的用户层添加到舞台上 
    stage.add(layer);
    stage.draw();
};

 

 

 

posted @ 2017-07-23 11:48  水之原  阅读(5433)  评论(0编辑  收藏  举报