sublime 有没有支持html5 canvas点击事件事件的函数

IBM Bluemix
点击按钮,开始云上的开发!
developerWorks 社区
当涉足 HTML5 游戏世界时,人们很容易低估管理键盘、鼠标和基于触摸的输入的复杂性。本文将探讨用来处理基于 HTML Canvas 的游戏中用户交互的一些基本技术。学习如何处理键盘和鼠标事件,如何阻止 Web 浏览器的默认事件行为,以及如何向游戏对象的某种逻辑表示传播事件。此外,还将学习如何处理 iPhone 和 iPad 等移动设备上与设备无关的(device-agnostic)输入。
, 软件开发人员, The Nerdery
Kevin Moot 从很小的时候就对计算机图形有浓厚的兴趣,那时他在自己的 Apple IIe(具有六种颜色的巨大矩阵以及令人震撼的 280x192 分辨率)上创建游戏。他还将 HTML5 的 Canvas 技术应用于几个前沿网站,HTML/CSS、JavaScript 和 .NET 也是他的专长。Kevin 目前是 The Nerdery 的一名交互软件开发人员。
简介令拥有 Flash 或 Silverlight 背景的开发人员感到惊讶的是,为 HTML5 Canvas 编写的应用程序在处理用户输入方面并没有什么特立独行之处。实质上,从启用了 JavaScript 的 Web 浏览器诞生之初开始,HTML 用户输入就涉及到使用内置于浏览器中的事件处理系统;HTML5 在检测和处理用户输入方面没有任何特殊之处。例如,浏览器提供了低级反馈来表明用户单击的坐标 (x,y),就这么简单。处理用户交互与其他任何低级游戏架构没什么不同。没有内置的抽象来通知您用户何时与已在 Canvas 上呈现的一个具体对象进行了交互。这对您希望处理这些事件的方式提供了强大的低级控制力度。只要您可以避免各种浏览器缺陷,最终就能根据一个独特应用程序来调优事件处理,从而实现最高效率 —而不是受到特定实现的禁锢。在本文中,将会学习处理基于 HTML Canvas 的游戏中的用户交互的一些技术。文中的示例演示了如何处理键盘、鼠标和基于触摸的事件。向游戏对象传播事件的战略和移动兼容性也会有所涉及。您可以 本文中使用的示例的源代码。事件类型用户交互完全由浏览器的传统事件监听器模型处理。HTML5 的出现并不新鲜;它采用了与自 Netscape Navigator 诞生初期就已经使用的事件模型。实质上,可以将交互式应用程序或游戏视为处理用户输入的浏览器事件模型与处理图形输出的 Canvas 的结合。除非您亲自将它们结合在一起,二者之间没有逻辑关系。您将利用事件监听器可附加到 &canvas&元素自身的事实。因为 &canvas&元素是一个块级元素,从浏览器的角度讲,这与将事件监听器附加到 &div&或其他任何块级元素上没有任何区别。键盘事件监听和处理的最简单的事件类型是键盘事件。它们不依赖于 Canvas 元素或用户的鼠标位置。键盘事件只需您在文档级别上监听按键、释放和按住事件。监听键盘事件事件监听器模型可能因为浏览器实现不同而各不相同,所以实现模型的最快捷的方式是使用一个库来规范化事件的处理。以下示例使用了 jQuery 绑定事件。这通常是最简单的开始方式,但考虑到 jQuery 在兼容遗留浏览器方面涉及的工作量水平,性能可能会受到影响。另一个流行的库(专为加速跨浏览器键盘事件处理而编写)是 Kibo(请参见 )。清单 1 演示了对键事件的监听,以及如何基于按下的键而采取适当的措施。清单 1. 处理键盘事件 $(document.body).on('keydown', function(e) {
switch (e.which) {
// key code for left arrow
console.log('left arrow key pressed!');
// key code for right arrow
console.log('right arrow key pressed!');
});如果应用程序在一个 Web 浏览器的环境中运行,那么一定要牢记一些有意义的键盘组合键。尽管定义某些常见组合键的行为来替换它们的默认浏览器行为(比如 Ctrl+R)在技术上是可行的,但这种做法受到了强烈反对。鼠标事件鼠标事件比键盘事件更复杂。您必须知道 Canvas 元素在浏览器窗口中的位置,以及用户光标的位置。监听鼠标事件使用 e.pageX和 e.pageY特性,很容易获得鼠标相对于整个浏览器窗口的位置。在本例中,原点 (0,0) 将位于整个浏览器窗口的左上角。当用户光标未在 Canvas 区域中时,您通常不会太关心用户输入。因此,最好考虑将原点 (0,0) 放在 Canvas 元素的左上角。在理想情况下,您希望在与 Canvas 区域相关的局部坐标系统内工作,而不希望在与整个浏览器窗口相关的全局坐标系统中工作。鼠标事件战略执行以下步骤,将全局窗口坐标转换为局部 Canvas 坐标。计算页面上的 Canvas DOM 元素的 (x,y) 位置。确定鼠标相对于整个文档的全局位置。要将原点 (0,0) 放在 Canvas 元素的左上角,并有效地将全局坐标转换为相对坐标,需要了解第 2 步中计算的全局鼠标位置与第 1 步中计算的 Canvas 位置之间的区别。图 1 给出了您需要捕获的有关全局坐标系统的信息示例。图 1. 鼠标位置、全局坐标图 2 显示了将鼠标位置转换为局部坐标后的结果。图 2. 转换为局部坐标后的鼠标位置清单 2 给出了确定局部鼠标坐标的方法。它假设您已经在标记中定义了一个 Canvas 元素,如下所示:&canvas id="my_canvas"&&/canvas&。清单 2. 处理鼠标事件 var canvas = $('#my_canvas');
// calculate position of the canvas DOM element on the page
var canvasPosition = {
x: canvas.offset().left,
y: canvas.offset().top
canvas.on('click', function(e) {
// use pageX and pageY to get the mouse position
// relative to the browser window
var mouse = {
x: e.pageX - canvasPosition.x,
y: e.pageY - canvasPosition.y
// now you have local coordinates,
// which consider a (0,0) origin at the
// top-left of canvas element
});非常规的浏览器行为在计算机游戏中,您通常不希望任何默认浏览器行为干扰您的操作。例如,您不希望拖动鼠标来执行文本选择,通过单击鼠标右键来打开上下文菜单,或者滚动鼠标滚轮来上下翻页。图 3 给出了一个在用户单击并拖动浏览器中的一个图像时可能出现的情况的示例。尽管从总体上讲,默认浏览器行为对拖放应用程序很有用,但这不是您的游戏中想要的行为。图 3. 拖动图像时的默认浏览器行为在所有事件处理函数中,添加一个 preventDefault()行,并从该函数返回 false。清单 3 中的代码将完成此任务,防止发生默认操作和事件发生。清单 3. 阻止默认行为 canvas.on('click', function(e) {
e.preventDefault();
var mouse = {
x: e.pageX - canvasPosition.x,
y: e.pageY - canvasPosition.y
//do something with mouse position here
});即使对于清单 3 中的代码,当用户在 DOM 元素上发起一个拖动事件时,您仍然可能遇到多种不合意的副作用,比如 I 型光标外观、文本选择等。拖动事件问题在图像上通常更常见,一种不错的想法是将它也应用于 Canvas 元素,以阻止拖动和选择。清单 4 给出了一个通过添加少量 CSS 来阻止选择的 CSS 规则。清单 4. 阻止选择的建议样式 image, canvas {
user-select:
-ms-user-select:
-webkit-user-select:
-khtml-user-select:
-moz-user-select:
-webkit-touch-callout:
-webkit-user-drag:
}覆盖桌面行为一般来讲,一个不错的想法是覆盖拖动和选择事件,确保浏览器的默认拖动和选择行为不会出现。清单 5 中的代码特意未使用 jQuery 来附加事件。jQuery 没有正确处理 ondragstart和
onselectstart事件(如果使用 jQuery 来附加事件,事件处理函数可能从不触发)。清单 5. 取消拖动和选择事件 var canvasElement = document.getElementById('my_canvas');
// do nothing in the event handler except canceling the event
canvasElement.ondragstart = function(e) {
if (e && e.preventDefault) { e.preventDefault(); }
if (e && e.stopPropagation) { e.stopPropagation(); }
// do nothing in the event handler except canceling the event
canvasElement.onselectstart = function(e) {
if (e && e.preventDefault) { e.preventDefault(); }
if (e && e.stopPropagation) { e.stopPropagation(); }
}覆盖移动行为在移动设备上,阻止用户缩放和平移浏览器窗口通常很重要(缩放和平移常常是移动浏览器处理触摸手势的默认行为)。您可以将 user-scalable=no添加到 viewport元标记来阻止缩放行为。例如: &meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1" /&要禁用使用手势对文档或窗口的所有移动,可以将清单 6 中的事件监听器附加到 document.body 文件中。这会从根本上取消用户在点击 Canvas 或游戏区域外任何位置时的所有默认浏览器行为。清单 6. 取消移动设备窗口移动 document.body.ontouchstart = function(e) {
if (e && e.preventDefault) { e.preventDefault(); }
if (e && e.stopPropagation) { e.stopPropagation(); }
document.body.ontouchmove = function(e) {
if (e && e.preventDefault) { e.preventDefault(); }
if (e && e.stopPropagation) { e.stopPropagation(); }
}传播到游戏对象对于您希望捕获的每种事件类型,只需向 Canvas 附加一个事件监听器。例如,如果您需要捕获单击和鼠标移动事件,只需向 Canvas 附加一个单击事件监听器和一个鼠标移动事件监听器。这些事件监听器只需附加一次,所以通常会在初始化应用程序期间附加这些事件。如果您需要将事件监听器捕获的所有有用信息都传播给在 Canvas 上呈现的对象,则必须为系统构建您自己的逻辑。在本例中,这样一个系统会负责将单击或鼠标移动事件传播到关注其中某个事件的处理的所有游戏对象。当每个游戏对象获知其中一个事件后,该游戏对象首先需要确定该单击或鼠标移动事件是否与它们有关。如果有关,那么该游戏对象需要确定鼠标坐标是否在它自己的边界内。传播战略您的具体战略将会取决于游戏类型。例如,2D 磁贴集可能具有与 3D 空间不同的战略。以下步骤给出了一个可用于简单 2D 应用程序的简单实现。检测用户的鼠标是否单击了 Canvas 区域内的位置。通知所有游戏对象,在一组给定的坐标上发生了一个单击事件。对于每个游戏对象,在鼠标坐标和游戏对象的边框之间执行一次命中测试,确定鼠标坐标是否接触到该对象。简单传播示例单击事件处理函数可能类似于清单 7。该示例假设您已设置了某种类型的结构来跟踪一个空间中的所有游戏对象。所有游戏对象的位置和尺寸存储在一个名为 gameObjectArray的变量中。清单 7. 单击事件处理函数向游戏对象传播 // initialize an array of game objects
// at various positions on the screen using
// new gameObject(x, y, width, height)
var gameObjectArray = [
new gameObject(0, 0, 200, 200),
new gameObject(50, 50, 200, 200),
new gameObject(500, 50, 100, 100)
canvas.on('click', function(e) {
var mouse = {
x: e.pageX - canvasPosition.x,
y: e.pageY - canvasPosition.y
// iterate through all game objects
// and call the onclick handler of each
for (var i=0; i & gameObjectArray. i++) {
gameObjectArray[i].handleClick(mouse);
});下一步是确保每个游戏对象都能够执行命中测试,从而确定鼠标坐标是否接触到了游戏对象的边框区域。图 4 给出了一个未成功的命中测试的示例。图 4. 边界外单击 -- 命中测试未成功图 5 显示了一个成功的命中测试。图 5. 边界内单击 -- 命中测试成功您可以为游戏对象定义一个类,如清单 8 所示。命中测试在 onclick()函数内执行,它测试对象的矩形边框与作为参数传入的鼠标坐标之间是否接触。清单 8. 游戏对象类和命中测试 function gameObject(x, y, width, height) {
this.width =
this.height =
// mouse parameter holds the mouse coordinates
this.handleClick = function(mouse) {
// perform hit test between bounding box
// and mouse coordinates
if (this.x & mouse.x &&
this.x + this.width & mouse.x &&
this.y & mouse.y &&
this.y + this.height & mouse.y) {
// hit test succeeded, handle the click event!
// hit test did not succeed
}提高传播效率在许多情形下,可以构建一种更高效的实现。例如,在具有数千个游戏对象的游戏中,您当然希望避免在每次触发一个事件时对屏幕中的每个游戏对象进行测试。下面的示例使用 jQuery 自定义事件触发了一个合成事件。该合成事件仅由监听该特定事件的游戏对象处理。对于该示例:像以前一样处理鼠标单击事件,执行所有必要的转换(比如将鼠标位置转换为局部坐标)。触发一个包含已转换的鼠标坐标(作为参数)的合成事件。任何负责处理一个单击事件的游戏对象都会设置一个监听器来监听该合成事件。修改鼠标单击事件处理函数,以便只触发一个自定义事件。可为该自定义事件提供任何随意名称。在清单 9 中,它名为 handleClick。清单 9. 触发一个自定义事件 canvas.on('click', function(e) {
var mouse= {
x: e.pageX - canvasPosition.x,
y: e.pageY - canvasPosition.y
//fire off synthetic event containing mouse coordinate info
$(canvas).trigger('handleClick', [mouse]);
});如清单 10 所示,游戏对象类已被修改。我们没有定义 onclick函数,而只是监听 handleClick事件。只要触发 handleClick事件,监听该事件的所有游戏对象都会触发它们相应的事件处理函数。清单 10. 处理一个自定义事件 function gameObject(x, y, width, height) {
var self =
this.width =
this.height =
$(canvas).on('handleClick', function(e, mouse) {
// perform hit test between bounding box
// and mouse coordinates
if (self.x & mouse.x &&
self.x + self.width & mouse.x &&
self.y & mouse.y &&
self.y + self.height & mouse.y) {
// hit test succeeded, handle the click event!
}高级命中测试一定要考虑在多个游戏对象彼此层叠时会发生什么。如果用户单击一个层叠了多个游戏对象的点,那么您需要确定如何处理该行为。例如,您通常只希望触发最近的对象的事件处理函数,忽略它之下的其他对象。要处理这种层叠情况,您需要知道每个层叠的游戏对象的顺序或深度。Canvas 不会公开深度的任何逻辑表示,所以您需要获得控制权,生成必要的逻辑来处理这种情况。为了介绍深度的概念,有必要为所有游戏对象分配一个 z 索引来表示它们的深度。清单 11 显示了一个示例。清单 11. 向游戏对象添加一个 z 索引 function gameObject(x, y, zIndex, width, height) {
var self =
this.zIndex = zI
this.width =
this.height =
}为了方便深度测试,您需要执行排序。在清单 12 中,对存储游戏对象的示例结构进行了排序,让具有最高 z 索引的游戏对象显示在列表的最前端。清单 12. 对游戏对象数组进行排序 // sort in order such that highest z-index occurs first
var sortedGameObjectArray = gameObjectArray.sort(function(gameObject1, gameObject2) {
if (gameObject1.zIndex & gameObject2.zIndex)
})最后,在 click函数中,通过切换来迭代这个有序数组中的所有游戏对象。只要一个游戏对象的命中测试提供了积极的结果,就会立即中断测试,使单击事件不会继续传播下去。如果未终止测试,就会像在清单 13 中一样,在更深的深度中,处理 click事件的不合意的游戏对象行为将会继续下去。清单 13. 在命中测试成功时中断 canvas.on('click', function(e) {
var mouse = {
x: e.pageX - canvasPosition.x,
y: e.pageY - canvasPosition.y
for (var i=0; i & sortedGameObjectArray. i++) {
var hitTest = sortedGameObjectArray[i].onclick(mouse);
// stop as soon as one hit test succeeds
if (hitTest) {
// break out of the hit test
});不规则的游戏对象边界对矩形边框执行命中测试通常是最简单和最高效的方法,但在许多情况下这还不够。如果游戏对象具有更加不规则的形状,对一个三角形或多边形边框执行测试可能更有意义。在这些情况下,您需要将游戏对象事件处理函数中的命中测试逻辑换为更高级的命中检测形式。通常,您会参考游戏碰撞理学来实现合适的逻辑。Canvas API 提供了一个名为 IsPointInPath()的有趣函数,它会自行执行多边形碰撞测试。实质上,IsPointInPath(x, y)允许您测试给定的 (x,y) 点是否落在一个任意路径(基本上是一个多边形边界)内。如果提供的 (x,y) 坐标落入当前路径(在 Canvas 上下文中定义)内,则会返回 true。使用 isPointInPath()图 6 显示了一种有必要对一个非矩形路径测试鼠标坐标的情形。在本例中,该路径是一个简单的三角形路径。图 6. 在一个三角形路径边界内单击出于演示之目的,填充的路径已可视化。因为无需在屏幕上物理地呈现 IsPointInPath()的路径就可以返回一个有用的结果,所以定义该路径就已经足够了,无需调用 fill()或 stroke()来实际绘制该路径。清单 14 显示了详细信息。清单 14. 使用 isPointInPath执行命中检测 $(canvas).on('handleClick', function(e, mouse) {
// first, define polygonal bounding area as a path
context.save();
context.beginPath();
context.moveTo(0,0);
context.lineTo(0,100);
context.lineTo(100,100);
context.closePath();
// do not actually fill() or stroke() the path because
// the path only exists for purposes of hit testing
// context.fill();
// perform hit test between irregular bounding area
// and mouse coordinates
if (context.isPointInPath(mouse.x, mouse.y)) {
// hit test succeeded, handle the click event!
context.restore();
});自行编写碰撞算法常常比使用 IsPointInPath()更高效,但它是一个建立原型和快速开发的不错工具。移动兼容性为了使示例游戏兼容移动设备,您需要处理触摸事件而不是鼠标事件。尽管手指点击也可以被移动浏览器解释为单击事件,但仅监听移动浏览器上的单击事件通常不是一种好方法。更好的方法是附加特定触摸事件的监听器,确保获得最佳的响应能力。检测触摸事件您可以编写一个帮助器函数,它首先检测设备是否支持触摸事件,然后相应地返回鼠标坐标或触摸坐标。这使得调用函数可以采用与设备无关的方式处理输入坐标,无论您是在桌面上还是在移动平台上。清单 15 给出了一个与设备无关的函数的示例,它将会捕获鼠标和触摸事件,并规范化响应。清单 15. 规范化鼠标和触摸事件 function getPosition(e) {
var position = {x: null, y: null};
if (Modernizr.touch) { //global variable detecting touch support
if (e.touches && e.touches.length & 0) {
position.x = e.touches[0].pageX - canvasPosition.x;
position.y = e.touches[0].pageY - canvasPosition.y;
position.x = e.pageX - canvasPosition.x;
position.y = e.pageY - canvasPosition.y;
}在检测触摸支持时,该示例使用了 Modernizr 库(请参见 )。Modernizr 库将对触摸支持的检测简化为测试变量 Modernizr.touch,如果设备支持触摸事件,那么该变量将会返回 true。与设备无关的事件处理函数在应用程序初始化期间,您可以将指定定义事件监听器的代码替换为一个支持触摸的设备和鼠标输入的独立分支。将鼠标事件映射到一个等效的触摸事件非常简单。例如,mousedown被替换为 touchstart,mouseup被替换为 touchend。清单 16 给出了一个使用 Modernizr 映射等效的鼠标 / 触摸事件的示例。它还使用了中定义的 getPosition()函数。清单 16. 使用规范化的鼠标 / 触摸事件 var eventName = Modernizr.touch ? 'touchstart' : 'click';
canvas.on(eventName, function(e) {
e.preventDefault();
var position = getPosition(e);
//do something with position here
});除非您需要处理更高级的操作,比如捏合和轻击,在直接从桌面应用程序直接移植鼠标事件时,此方法通常会良好地运行。假设使用一个单点触摸系统;如果需要执行多点触摸检测,则需要使用其他一些代码(这不属于本文的介绍范围)。结束语在本文中,您学习了如何处理键盘和鼠标事件,以及如何取消不合意的浏览器行为。本文还探讨了向游戏对象传播事件的战略,回顾了针对命中测试的更高级的考虑因素,以及一个解决移动兼容性问题的简单方法。尽管用户输入的范围不属于本文的讨论范畴,但典型的用户输入场景为创建可靠的、与设备无关的库来处理 HTML5 应用程序的用户输入提供了一个起点。
下载描述名字大小本文的代码清单5KB
参考资料 “”(developerWorks,2011 年 2 月):了解如何使用 Canvas(一个功能强大的简单 HTML5 元素)增强您的网页。
:观看此演示,了解 Canvas API 的使用和如何绘制非常简单的动画。
“”(developerWorks,2011 年 7 月):阅读这篇关于 HTML5 Canvas 元素的介绍性文章,其中包含多个演示功能的示例。
:这个来自 Safari Dev Center 的演示是一个利用 canvas 来开发有效的视觉资产的优秀示例。
:了解这个与 W3C 合作调优 HTML5 的开发人员社区。
:在本教程中使用来自 Mozilla 开发人员的 &canvas& 元素。
:探索多项有助于完善您的 canvas 知识的有用练习。
:了解用于注册将在用户与浏览器交互时生效和进一步操作这些注册的行为的方法。
:通过专门关于 Web 技术的文章和教程,扩展您在网站开发方面的技能。:这是有关 Ajax 编程模型信息的一站式中心,包括很多文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。,这是有关 Web 2.0 相关信息的一站式中心,包括大量 Web 2.0 技术文章、教程、下载和相关技术资源。您还可以通过
栏目,迅速了解 Web 2.0 的相关概念。查看 ,了解更多和 HTML5 相关的知识和动向。:立即加入,关注 developerWorks 推文。
:观看演示,从为初学者准备的产品安装,到为经验丰富的开发人员准备的高级功能。
:下载这个流行的 JavaScript 库,它简化了 HTML 文档遍历、事件处理、动画和 Ajax 交互,以实现快速 Web 开发。
:获取这个开源的 JavaScript 库,帮助您构建下一代受 HTML5 和 CSS3 支持的网站。
:使用这个流行、简单的 JavaScript 库处理键盘事件。
:下载或 ,上手使用来自 DB2®、Lotus®、Rational®、Tivoli®和 WebSphere®的应用程序开发工具和中间件产品。
:探索由浏览开发人员推动的博客、论坛、群组和维基,并与其他 developerWorks 用户进行交流。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
文章、教程、演示,帮助您构建、部署和管理云应用。
立即加入来自 IBM 的专业 IT 社交网络。
免费下载、试用软件产品,构建应用并提升技能。
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=Web developmentArticleID=947555ArticleTitle=在基于 HTML5 Canvas 的游戏中处理用户输入publish-date=突破canvas语法限制 让他支持链式语法
作者:佚名
字体:[ ] 来源:互联网 时间:12-24 16:39:48
突破canvas语法限制,有很多的朋友可能还不相信,本文将详细介绍如何让canvas支持链式语法,需要了解的朋有可以参考下
先来看一段正常的canvas画图语法:代码如下:ctx.arc(centerX,centerY,radius,0,PI*2,true);ctx.shadowColor = 'rgba(0,0,0,0.5)';ctx.shadowBlur = "10";ctx.fill();ctx.beginPath();ctx.shadowColor = 'rgba(0,0,0,0)';ctx.moveTo(centerX-radius,centerY);ctx.lineTo(centerX-radius,centerY - 50);ctx.lineTo(centerX+radius,centerY - 50);ctx.lineTo(centerX+radius,centerY);// ctx.lineTo(centerX-radius,centerY);ctx.fill();ctx.beginPath();ctx.fillStyle = 'rgba(255,0,0,1)';ctx.arc(centerX,centerY-50,radius,0,PI*2,true);ctx.fill();我对canvas原生语法不爽的有两点:1是每句前面都有写ctx(即canvas的context2d对象),2是每个函数或属性都要占一行,浪费空间。 我对jQuery的链式语法很欣赏,比如: 代码如下:$('#div1').show(300).html(p).delay(3000).slideUp(300).remove();所以,我也想用这种语法来进行canvas绘图:代码如下:ctx.moveTo(500,0).lineTo(500,500).strokeStyle('#f00').stroke();有个办法就是模拟一个context2d对象,这个对象支持所有的原生context2d方法,但又支持链式。 不过,代码不能太多,多了就没人喜欢用了。 下面就是完整的代码段,这个&类&我取名为XtendCanvas(又是以X开头的哟): 代码如下:// 让canvas支持链式语法,来自十年灯~function
() {var pro = ['save','restore', 'scale', 'rotate', 'translate', 'transform',
'createLinearGradient', 'createRadialGradient', 'getLineDash', 'clearRect', 'fillRect', 'beginPath', 'closePath', 'moveTo', 'lineTo', 'quadraticCurveTo', 'bezierCurveTo', 'arcTo', 'rect', 'arc', 'fill', 'stroke', 'clip', 'isPointInPath', 'measureText', 'clearShadow', 'fillText', 'strokeText',
'strokeRect', 'drawImage', 'drawImageFromRect',
'putImageData', 'createPattern', 'createImageData', 'getImageData',
'lineWidth','strokeStyle','globalAlpha','fillStyle','font','shadowOffsetX','shadowOffsetY','shadowBlur','shadowColor','lineCap','lineJoin','miterLimit'];
function XtendCanvas (canvas) {
var ctx = canvas.getContext('2d'),
fn = function(){},
for(var j = 0,p=pro[0];p;p=pro[j++]) {
fn.prototype[p] = function
return function
var args = Array.prototype.slice.call(arguments);
// console.log(args);
if(typeof ctx[p] == 'function') {
ctx[p].apply(ctx,args);
ctx[p] = args+'';
return fnP;
window.XtendCanvas = XtendC}();使用方法很简单,给他传一个canvas对象,他就会返回一个类似context2d的对象,你可以像普通的context2d一样使用,但不同的是,他支持链式语法了:代码如下:var cvs = document.getElementById('cvs');var ctx = XtendCanvas(cvs);ctx.moveTo(500,0).lineTo(500,500).strokeStyle('#f00').stroke();这样一来你就可以把所有操作都放在一句话里,你也可以随时中断,做其他的事,然后继续。 这段代码并不是对canvas的增强,只是单纯的让他支持链式语法了。但胜在代码少,可以嵌入到任何JS库中,在此我希望能得到你的一个&推荐& 代码中肯定有值得改进的地方,大家可以自行完善。但&&吃水不忘挖井人,希望大家记得我,最重要的是思路,对吧?下面就是思路: 大家可以看到,代码中最长的部分,是那个保存方法名的数组pro,核心代码反而很短。为什么我要建这么一个数组呢? 本来我也想直接从CanvasRenderingContext2D继承所有原生方法,但每个浏览器下面遍历这个CanvasRenderingContext2D,结果都不一致。如果我把他们直接继承,那么当你想用chrome中的方法套在firefox里执行,就会报错。 所以我只是把CanvasRenderingContext2D中的通用的,无异议的方法与属性名提取了出来,没办法,只有建一个固定的数组&&大家可以自行决定往里面添加你的方法。 方法与属性提取出来了,接着就是把原生的方法加在我的新对象上。我建了一个叫fn的空函数,放置我的方法。 由于数组中的这些元素既有函数,也有属性,所以我在循环中判断了他是否是一个函数,如果是函数,就带参数执行;不是函数&&那么就肯定是属性了,就把参数赋给这个属性。 这样大家在碰到设置canvas属性的时候,就不用中断链了,直接把属性值当参数传进去就行了,比如: 代码如下:ctx.strokeStyle('#f00')最后,关键的关键,就是返回fn,这招是从jQuery学来的,是支持链式语法的关键。 这段中用到了匿名函数,闭包,原型,以及我以前文章讲过的奇怪的for循环。 说起来好像挺简单的,不过我实在是想了很久,希望对大家有用。 在写代码的过程中,我发现chrome的做法很不错,他有一串以set开头的函数,如setStrokeColor,setLineCap等函数,给他们传参数,就可以替代对应的strokeStyle和lineCap等属性,也就是说,他的canvas里面就全是函数而没有属性了那样的话我就不用判断是函数还是是属性了。但firefox里面没有这些,所以我还是只能用前面的思路。 我也把那一串set函数给放出来吧: 代码如下:var bak = ['setTransform','setAlpha', 'setCompositeOperation', 'setLineWidth', 'setLineCap', 'setLineJoin', 'setMiterLimit', 'setLineDash','setShadow','setStrokeColor','setFillColor'];他们的用处一看就懂。你也可以选择一些加入前面代码的pro数组中。 最后,我很奇怪我的代码怎么会没有高亮了。。。如果你都看到最后了,那么还是给个推荐吧,让我也虚荣一把
大家感兴趣的内容
12345678910
最近更新的内容}

我要回帖

更多关于 canvas 事件 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信