在 Tizen 使用Raphael JS 库
PUBLISHED
本文介绍了 Raphael JavaScript 库,以及如何在 Tizen 上使用它。 您将学习如何绘制简单的 2D 形状:内置(矩形、 圆、 椭圆)和其他(使用路径),如何利用 Raphael 元素的属性以及如何创建简单的动画。 您还将学习如何操作元素(移动、缩放和旋转)。
Raphael JS 库入门指南
Raphael JS 是一个小的 JavaScript 库,允许用户在 Tizen Web 应用程序中使用矢量图形。 它使用 SVG W3C 推荐标准和 VML。 通过使用 SVG 对象,每个对象也是一个 SVG DOM 对象,允许例如将事件处理程序附加到对象上。
要使用 Rapheal JS 库:
- 从下载页面下载 Raphael JS 框架。 您可以选择下载压缩后或未压缩版本的库。
- 将其包含到您项目的标题区。
注:为方便您参考,本文中使用/描述的特定功能已被超链接到 Raphael 文档的合适部分。
欲了解更多关于 Raphael JS 库和一些令人惊叹的演示的信息,请访问 raphaeljs.com。 可在此处找到该文档。 显示 Raphael JS 库功能的完美页面可在此处找到。
介绍 RaphaelPaint 示例应用程序
RaphaelPaint 示例应用程序演示如何使用 Raphael JavaScript 库来创建和使用 2D 矢量图形。
示例应用程序的用户界面包括单个页面。 启动后,您可以看到页面顶部的工具栏和空白画布。 工具栏包含下列选项:“箭头”、“矩形”、“正方形”、“三角形”、“圆形”、“椭圆形”、“星形”、“橡皮擦”、“填充颜色”、“笔触颜色”和“清除画布”。 第一个选项允许操作选定的形状 (移动、 缩放和旋转)。 接下来的六个选项负责绘制典型形状。 其他工具的用法不言自明。
示例应用程序使用完整的 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 库提供三个内置形状。 要绘制这些形状,您必须使用以下函数(下面的图像描述如何理解输入参数):
- 矩形 — Paper.rect() 函数
var rect = paper.rect(x, y, width, height);
我们还使用 paper.rect() 方法来绘制一个正方形 (一个宽度 = 高度的矩形)。
- 圆形 — Paper.circle() 函数
var circle = paper.circle(x, y, radius);
- 椭圆 — Paper.ellipse() 函数
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 学校地图
- 和更多......