在 Tizen 使用Raphael JS 库

本文介绍了 Raphael JavaScript 库,以及如何在 Tizen 上使用它。 您将学习如何绘制简单的 2D 形状:内置(矩形、 圆、 椭圆)和其他(使用路径),如何利用 Raphael 元素的属性以及如何创建简单的动画。 您还将学习如何操作元素(移动、缩放和旋转)。

Raphael JS 库入门指南

Raphael JS 是一个小的 JavaScript 库,允许用户在 Tizen Web 应用程序中使用矢量图形。 它使用 SVG W3C 推荐标准和 VML。 通过使用 SVG 对象,每个对象也是一个 SVG DOM 对象,允许例如将事件处理程序附加到对象上。

要使用 Rapheal JS 库:

  1. 下载页面下载 Raphael JS 框架。 您可以选择下载压缩后或未压缩版本的库。
  2. 将其包含到您项目的标题区。

注:为方便您参考,本文中使用/描述的特定功能已被超链接到 Raphael 文档的合适部分。

欲了解更多关于 Raphael JS 库和一些令人惊叹的演示的信息,请访问 raphaeljs.com。 可在此处找到该文档。 显示 Raphael JS 库功能的完美页面可在此处找到。

介绍 RaphaelPaint 示例应用程序

RaphaelPaint 示例应用程序演示如何使用 Raphael JavaScript 库来创建和使用 2D 矢量图形。

示例应用程序的用户界面包括单个页面。 启动后,您可以看到页面顶部的工具栏和空白画布。 工具栏包含下列选项:“箭头”、“矩形”、“正方形”、“三角形”、“圆形”、“椭圆形”、“星形”、“橡皮擦”、“填充颜色”、“笔触颜色”和“清除画布”。 第一个选项允许操作选定的形状 (移动、 缩放和旋转)。 接下来的六个选项负责绘制典型形状。 其他工具的用法不言自明。

图 1 示例应用程序的屏幕快照

示例应用程序使用完整的 Tizen 视口 (720 x 1280), 包括 jQuery Mobile 1.3.0 框架和 jQuery 1.9.0 库并在 Tizen SDK 2.0.0 上进行测试。

绘制形状和路径

您可以按照以下两种方式使用 Raphael JS 绘制形状:

  • 使用内置的形状(由库提供):矩形、圆形、椭圆形
  • 使用路径。

下面介绍这两种方法。

所有的形状都在 Raphael 纸上绘制,因此要使用 Raphael JS 框架,必须先创建至少一个实例。 您可以通过使用 Raphael() 函数执行此项操作。 此函数可以采用几个不同的参数集。 示例应用程序使用以下参数:

container = document.getElementById('canvas_container');
paper = new Raphael(container, config.canvas.width, config.canvas.height);

容器代表了一个 DOM 元素,能够容纳其他元素。 Raphael 纸在此元素内部绘制。 您还可以定义纸张的 (x,y) 位置,而不是将容器作为参数应用。

参数的宽度和高度表示创建纸张的宽度和高度。

当我们有绘图画布时,可以在上面绘制一些形状。 要操作这个画布,我们需要单击位置的坐标。 为此目的,我们需要将一个事件处理程序附加到容器:

$("#canvas_container").on(
        "click",
        function(e) {
            e.preventDefault();
            var rect = container.getBoundingClientRect();
            var x0 = e.pageX, y0 = e.pageY;
            var x = x0 - rect.left, y = y0 - rect.top;
            var elem = paper.getElementByPoint(x0, y0);

            if (config.tool === "arrow") {
                ...
            } else {
                paint(x, y);
            }
        })

GetBoundingClientRect() 函数返回一个 TextRectangle 对象与四个属性:顶部、左侧、右侧、底部。 这些属性用于定义容器的位置。 当您单击该容器的内部时,回调函数获取一个事件对象 (e) 作为一个参数,其中 pageX 和 pageY 属性表示鼠标指针的位置。 该位置是相对于设备屏幕的左上角。 我们必须将它以相对于容器的左上角的位置做一个小小的数学转换:

Rect 意味着由 getBoundingClientRect () 函数返回的 TextRectangle 对象。

图 2 确定绘制对象的坐标

您现在可以在适当的位置绘制形状(当然,如果您选择箭头以外的任何工具)。

注:Raphael 的坐标系统与画布的坐标系统相同。

图 3 Raphael JS 坐标系统

内置形状

如前面所提到的,Raphael JS 库提供三个内置形状。 要绘制这些形状,您必须使用以下函数(下面的图像描述如何理解输入参数):

var rect = paper.rect(x, y, width, height);

我们还使用 paper.rect() 方法来绘制一个正方形 (一个宽度 = 高度的矩形)。

var circle = paper.circle(x, y, radius);

var ellipse = paper.ellipse(x, y, rx, ry);

绘制路径

但如何绘制其他形状 (如三角形、 其他多边形)呢?我们可以使用“路径”。

路径是一个字符串,其中包含一个命令和用空格分隔的参​​数,例如

"M 100 100 l 100 0 l 0 100 l -100 -100"

此路径是指:“移动到 (100, 100),向右第 100 行,向下第 100 行,从左上角开始画线,x 轴和 y 轴均为 100 像素”。 结果如下所示。 

同样的效果将会给出一条路径:

"M 100 100 l 100 0 l 0 100 z”

这意味着:“移动到 (100, 100),向右第 100 行,向下第 100 行,然后封闭路径(连接路径的最后和第一个点)”。

根据 Raphael 参考的命令及其含义:

有两种命令类型。 命令“L”(大写)与“l”(小写) 的含义不同。 第一种类型的命令是绝对命令,第二种是相对命令。 有什么区别呢?

"L 100 0” 含义:线到点 (100,0)

"l 100 0” 含义:向右第 100 行

您可以在此处找到有关命令的更多信息。

RaphaelPaint 示例应用程序使用路径来绘制以下形状:

  • 三角形
  • 星形

新创建的形状有明显的边界框(就像这些选择)。 要获得任何元素的边界框,您可以使用 Element.getBBox() 函数。 该函数采用的唯一参数是一个布尔值。 它指定您是否希望边界框(在转换之前)为原始形状。 它是可选的,且在默认情况下等于 false。 使用此函数的示例: 

addBox : function() {
    ...

    var bBox = selectedShape.getBBox();
    lastbBox = paper.rect(bBox.x,bBox.y,bBox.width,bBox.height).attr({stroke:"#9a9a9a"});
},

正如您所看到的,该函数为边界框获取所选的形状,然后绘制该形状。 创建形状后和每次拖动元素时,都会添加边界框。

使用属性

要更改或获取绘制元素的属性,您可以使用 Element.attr() 函数。

这两种方法在设置属性上是等效的:

elem.attr({
    // Attributes of the element
    "fill" : "#dfed48",
    "stroke" : "#dfed48"
});

Elem.attr("fill", "#dfed48");
Elem.attr("stroke ", "#dfed48");

您可以一次性设置一个或许多元素的属性。 设置多个属性时,您必须传递对象与指定属性名称的键和指定属性值的值。 当设置一个属性时,第一个参数是属性的名称,第二个参数是一个新的值。  如果只有一个参数被传递(属性的名称),则 Element.attr() 函数返回这个属性的值,例如: Elem.attr("fill") 将返回“#dfed48”字符串。 自 2011 年 8 月 16 日,Raphael 参考W3C SVG 1.1 推荐标准对可能的属性名称进行了描述。

 

添加转换

RaphaelPaint 允许移动、缩放和旋转对象。 要提供这些转换,您可以使用 Element.transform() 函数。 调用此函数的方式类似于创建路径的方法。 您需要创建一个带命令及其参数的字符串。 示例应用程序使用 Raphael JS 提供的四个命令中的三个:  

:本文不对 m(矩阵) 命令进行描述。 您需要将创建的字符串应用为 Element.transform() 函数的参数。 在我们的示例应用程序中,applyTransforms() 函数负责以下操作:

/**
 * Adds specified transformation to the element
 *
 * @param that {Object} Element to which the transformation is added
 */
applyTransforms : function(that) {
    var str = "t" + that.translate[0] + "," + that.translate[1] + "r"
            + that.rotate + "s" + that.scale[0] + "," + that.scale[1];
    that.transform(str);
    …
}

设置新创建形状的属性时,创建并初始化 that.translate、that.rotate 和 that.scale 的属性。 稍后将详细介绍这些属性。 

var setProperties = function(elem) {
    ...

    // Initial values of applied transforms
    elem.translate = [ 0, 0 ];
    elem.scale = [ 1, 1 ];
    elem.rotate = 0;

    ...

    return elem;
}

按正确的顺序应用转换很重要。 “T100,20r60”和“r60t100,20”看起来很相似,但产生的结果大不相同:   

1 — 没有进行任何转换的三角形;

2 — “T100,20r60”转换后的三角形

3 — “r60t100,20”转换后的三角形

向 Raphael 元素添加转换时,请牢记这一点。  

您知道如何将创建的转换应用于元素。 现在可以开始设置转换的命令属性。 这些属性都与拖动事件有关。 以下片段会解释“如何”设置。 首先,您需要添加事件处理程序,要拖动元素,您可以使用 Element.drag() 函数。 

// Sets event handlers for moving, drag start and drag end
elem.drag(transforms.move, transforms.start, transforms.up);

您可以在 ./js/transforms.js 模块找到用于移动、拖动开始和拖动结束所有绘制的形状的事件处理程序。 

/**
 * Event handler for drag start
 */
start : function() {
    that = this;

    ...

    if (config.tool === 'arrow') {
        ...

        switch (config.operation) {
        case "move": {
            // read last translation
            that.odx = that.translate[0];
            that.ody = that.translate[1];
        }
            break;

        case "scale": {
            // read last scale
            that.osx = that.scale[0];
            that.osy = that.scale[1];
        }
            break;

        default:
            break;
        }
    }
},

/**
 * Event handler for moving
 * @param dx {Number} shift by x axis from the start point
 * @param dy {Number} shift by y axis from the start point
 */
move : function(dx, dy) {
    if (config.tool === 'arrow') {
        switch (config.operation) {
        case "move": {
            // change translation
            that.translate[0] = that.odx + dx;
            that.translate[1] = that.ody + dy;
        }
            break;

        case "scale": {
            // change scaling
            if ((that.fig !== "circle") && (that.fig !== "square")) {
                // for all figures except circle and square
                that.scale[0] = that.osx + 10 * dx
                        / config.canvas.width;
                that.scale[1] = that.osy + 10 * dy
                        / config.canvas.height;
            } else {
                // for circle and square
                if (dx > dy) {
                    that.scale[0] = that.scale[1] = that.osx + 10 * dx
                            / config.canvas.width;
                } else {
                    that.scale[0] = that.scale[1] = that.osy + 10 * dy
                            / config.canvas.height;
                }
            }
        }
            break;

        default:
            break;
        }

        transforms.applyTransforms(that);
    }
},

 

简单动画

要将动画应用于对象,您必须使用 Element.animate() 函数。 它为指定的元素创建并启动动画。 使用 Element.animate() 函数的示例:

// Animation for selected element
that.animate({
    "fill-opacity" : 0.4
}, 500);

第一个参数定义具有动画效果的形状的最终属性值。 第二个参数指定动画的持续时间(以毫秒为单位)。 Element.animate() 函数还采用第三个和第四个参数,分别指缓动类型和回调函数(动画结束时调用)。

当您拖动一些元素时,RaphaelPaint 示例应用程序使用 Element.animate() 函数。 当拖动开始事件获取调用时,形状的填充不透明度属性降低,on drag-end 返回至其以前的状态。

 

使用“纸张”

您可以绘制形状、更改其属性和添加转换和动画。 但如何选择您想要操作的元素呢?Raphael JS 建议使用 Paper.getElementByPoint (x, y) 函数。 它将返回最顶层的元素,其形状内包含 (x,y) 点。 x、y 代表 x 和 y 坐标,从设备屏幕的左上角度量 (参见图 2)。

var elem = paper.getElementByPoint(e.pageX, e.pageY);

  您可以使用可调用 Element.remove() 函数的“橡皮擦”工具,从纸张删除选定的元素。

/**
 * Removes specified element (figure) from canvas
 * @param elem {Object} Element to be removed
 */
removeShape : function(elem) {
    elem.remove();
    if (lastbBox) {
        lastbBox.remove();
    }
},

如果您想要从纸张删除所有元素,您可以使用 Paper.clear() 函数。 它并不需要任何参数,例如

case "clear": {
    ...
    paper.clear();
    ...
}
break;

 

总结

我们希望这篇文章将向您展示如何在您的 Tizen Web 应用程序中利用 Raphael JS 库。 您可以使用它来创建:

  • 呈现数据的具体图表,例如 动画技能图人口金字塔
  • 简单的游戏,例如拼图,等等。
  • 您的应用程序的用户界面,其菜单作为可点击的图形元素
  • 含互动元素的地图和计划,例如 Woodsetton 学校地图
  • 和更多......
文件附件: