CreateJS-入门指南-全-

CreateJS 入门指南(全)

原文:zh.annas-archive.org/md5/6a0b13cc9a19ea6379d1ec40f65ec9f8

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

CreateJS 是一个功能齐全的工具,网络开发者可以使用它来在网页浏览器中使用 HTML5 创建和维护动画和绘图。它由一些模块组成,每个模块执行不同的任务来管理基于 Web 的应用程序。

在本书中,我们将通过许多交互式示例和截图讨论 CreateJS 的不同部分。

本书涵盖的内容

第一章, 安装 CreateJS,为初学者提供了快速安装参考。

第二章, 开始使用 CreateJS,介绍了如何开始使用 CreateJS 以及其他组件,使用 API 以及配置模块。

第三章, 使用拖放交互,讨论了 CreateJS 的拖放功能以及如何在项目中自定义这些功能或扩展它们。

第四章, 执行动画和变换功能,介绍了如何使用 CreateJS 在页面上使用动画和变换对象。

第五章, 在 EaselJS 中使用缓存,介绍了如何在 CreateJS 中使用缓存以实现动画中的更好性能。

第六章, 在 EaselJS 中使用滤镜,讨论了在 CreateJS 中的图像和对象上使用滤镜。

第七章, 开发绘画应用程序,讨论了如何使用图形在画布上开发一个简单的绘画应用程序。

第八章, 利用矢量蒙版,讨论了将形状用作任何显示对象的剪切路径。

第九章, 开发您的第一个 CreateJS 应用程序,介绍了如何使用 CreateJS 从零开始构建和创建 UI。

您需要为本书准备什么

本书中包含的所有示例和源代码都在现代网络浏览器中运行。为了所有示例都能完美运行,您需要安装最新版本的 Google Chrome 或 Mozilla Firefox。

本书面向对象

如果您是一位有 JavaScript 开发经验的网络开发者,并希望进入使用 CreateJS 的功能丰富的互联网应用迷人世界,那么这本书非常适合您。

术语约定

在本书中,您将找到多种文本样式,用于区分不同类型的信息。以下是一些这些样式的示例及其含义的解释。

文本中的代码词显示如下:"在 EaselJS 中,当您有一个形状,或者更好的是,一个不经常改变的 DisplayObject 实例时,最好使用 cache 函数将其缓存到不同的 Canvas 元素中"。

代码块设置如下:

var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0, 0, 50);
circle.x = 100; 
circle.y = 100; 

任何命令行输入或输出都应如下所示:

# Install the grunt command line utility globally 
npm install grunt-cli -g 

# Install all the dependencies from package.json
npm install

新术语重要词汇将以粗体显示。你在屏幕上看到的,例如在菜单或对话框中的文字,将以如下方式显示:“使用下拉菜单,用户可以更改画笔样式画笔大小背景颜色画笔颜色字段。”

注意

警告或重要注意事项将以如下框中的方式显示。

小贴士

小贴士和技巧看起来像这样。

读者反馈

我们始终欢迎读者的反馈。告诉我们您对这本书的看法——您喜欢什么或可能不喜欢什么。读者反馈对我们开发您真正从中获得最大收益的标题非常重要。

要向我们发送一般反馈,只需发送电子邮件到<feedback@packtpub.com>,并在邮件主题中提及书籍标题。

如果您在某个主题上具有专业知识,并且您对撰写或为书籍做出贡献感兴趣,请参阅我们的作者指南www.packtpub.com/authors

客户支持

现在您已经是 Packt 书籍的骄傲拥有者,我们有一些事情可以帮助您从您的购买中获得最大收益。

下载示例代码

您可以从您在www.packtpub.com的账户中下载您购买的所有 Packt 书籍的示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。

下载本书的彩色图像

我们还为您提供了一个包含本书中使用的截图/图表彩色图像的 PDF 文件。彩色图像将帮助您更好地理解输出中的变化。您可以从以下链接下载此文件:www.packtpub.com/sites/default/files/downloads/0260OS_coloredimages.pdf

勘误

尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在我们的书中发现错误——可能是文本或代码中的错误——如果您能向我们报告这一点,我们将不胜感激。通过这样做,您可以节省其他读者的挫败感,并帮助我们改进本书的后续版本。如果您发现任何勘误,请通过访问www.packtpub.com/submit-errata,选择您的书籍,点击勘误提交表单链接,并输入您的勘误详情来报告。一旦您的勘误得到验证,您的提交将被接受,勘误将被上传到我们的网站,或添加到该标题的勘误部分下的现有勘误列表中。您可以通过从www.packtpub.com/support选择您的标题来查看任何现有勘误。

侵权

互联网上对版权材料的盗版是一个跨所有媒体的持续问题。在 Packt,我们非常重视我们版权和许可证的保护。如果您在互联网上发现我们作品的任何非法副本,无论形式如何,请立即提供位置地址或网站名称,以便我们可以寻求补救措施。

请通过<copyright@packtpub.com>与我们联系,并提供疑似盗版材料的链接。

我们感谢您在保护我们作者以及为我们提供有价值内容的能力方面的帮助。

问题

如果您在本书的任何方面遇到问题,可以通过<questions@packtpub.com>联系我们,我们将尽力解决。

第一章。安装 CreateJS

正确安装和使用客户端库非常重要。错误地使用大型客户端库可能会导致真正的问题;一个明显的问题是网页加载缓慢。在本章中,我们将探讨如何为开发和生产环境设置和使用 CreateJS。

在本章中,您将了解以下主题:

  • 要求

  • 下载

  • 安装和设置

理解 CreateJS 和子集

CreateJS 包含不同的库,如 SoundJSTweenJSEaselJSPreloadJS。每个库在浏览器中运行都有不同的要求。

TweenJS 应该在所有浏览器及其旧版本中运行。SoundJS 需要 HTMLAudioFlashWebAudio,这些功能需要现代浏览器。SoundJS 应该与以下浏览器完美兼容:

  • Google Chrome 31+

  • Mozilla Firefox 25+

  • Internet Explorer 9+

  • Opera 18+

在移动浏览器中,它应该与以下浏览器兼容:

  • iOS Safari 4.0+

  • Android 浏览器 2.3+

  • BlackBerry 浏览器 7.0+

PreloadJS 应该与所有浏览器兼容,甚至包括 Internet Explorer 6。

EaselJS 依赖于 HTML5 canvas,因此您的观众应该拥有以下浏览器之一才能使用 EaselJS:

  • Google Chrome 31+

  • Mozilla Firefox 25+

  • Internet Explorer 9+

  • Opera 18+

对于移动设备,需要以下浏览器之一:

  • iOS Safari 3.2+

  • Opera Mini 5.0-7.0

  • Android 浏览器 2.1+

  • BlackBerry 浏览器 7.0+

下载 CreateJS

在以下章节中讨论了将 CreateJS 文件下载并包含到您的项目中的几种方法。

GitHub

您可以从 GitHub 下载 CreateJS 的最新版本及其所有子集,如下面的截图所示:github.com/CreateJS/

GitHub

在访问每个仓库后,您可以选择下载最新更改的 ZIP 文件,或者使用 Git 克隆命令从 GitHub 获取源代码,如下面的截图所示:

GitHub

您可以在每个仓库页面的右侧找到此框,它有助于您获取代码。

理解内容分发网络

CreateJS 拥有一个优秀的 内容分发网络 (CDN),其中包含所有版本和所有子集库。您可以通过 code.createjs.com/ 访问 CDN 服务器。

注意

在项目中使用托管在 CDN 上的 CreateJS 库的版本可以快速下载并在不同站点上使用相同版本的库进行缓存。这可以减少带宽成本和页面加载时间。

您可以在 code.createjs.com/ 找到所有版本,如下面的截图所示:

理解内容分发网络

您还可以使用包含所有库(包括 EaselJS、TweenJS、SoundJS 和 PreloadJS)最新稳定版本的组合版本。

设置库

在选择下载源之后,您需要设置库以使其工作。在本节中,我们将了解如何为生产环境和开发环境设置库。

生产环境

如果您想在生产环境中使用 CreateJS,事情将会简单得多。您只需要使用单个编译后的源文件。为此,您可以使用 CreateJS CDN 上的托管文件,或者本地构建然后本地链接。

使用 CDN

在这种情况下,您需要做的只是将 <script…> 链接到 CreateJS CDN 服务器上文件的源(见本章的 下载 CreateJS 部分);之后,一切应该都能正常工作。

开发环境

如果您想调试、使用 CreateJS 进行开发或查看 CreateJS 内部的情况,您需要使用未编译的源文件。

对于每个库,您可以在 /src/ 中找到未编译的源文件。所有依赖项和源代码都将在这里。

要使用未编译的源文件,重要的是要注意所有文件都应该按照正确的顺序调用;否则,您将遇到一些错误。幸运的是,每个项目中都有一个文件会为您提供有关如何按正确顺序包含文件的提示。此配置文件位于 build/config.json

您可以在以下屏幕截图中看到 EaselJS 的此配置示例:

开发环境

因此,您必须按照以下顺序放置 <script…> 和加载文件。您也可以在其他项目的相同位置找到相同的配置文件。

在加载所有 JS 文件后,您可以使用库,并且也可以在源代码上设置断点以进行跟踪或调试。

构建源代码

所有 CreateJS 库都使用 Grunt 来创建和构建文件,因此您需要安装 NodeJS 和 Grunt 模块(需要 0.10.2 或更高版本)。

首先,从 www.nodejs.org 获取 NodeJS 的最新版本并安装它。然后转到库(例如 EaselJS)的 /build 文件夹,并在您的命令环境中运行以下命令:

# Install the grunt command line utility globally 
npm install grunt-cli -g 

# Install all the dependencies from package.json
npm install

执行这些命令后,您应该获得以下屏幕截图所示的结果:

构建源代码

在安装所有依赖项后,您只需剩下最后一步来构建库。转到库文件夹并运行以下命令:

grunt build

您应该在命令环境中看到以下结果:

构建源代码

当您看到“完成,无错误”的消息时,您可以在库的 /lib 文件夹中找到您的编译文件,文件名为 {PROJECT_NAME}-{VERSION}.min.js,例如 easeljs-0.7.0.min.js。这与 CDN 服务器上的文件完全相同。您可以将本地 script 标签链接到该文件并使用它。

如需了解更多关于选项及其使用方法的信息,您可以阅读每个库的 /build 文件夹中的 README.md 文件。

摘要

在本章中,我们学习了如何为不同的环境设置和准备 CreateJS,因为作为一名程序员,您可能希望修改 CreateJS 或为其进行自定义。我们还讨论了在生产环境中使用 CreateJS、使用 CDN 服务器以及构建源代码。

在下一章中,我们将讨论如何使用 CreateJS 编写第一个工作示例以及如何使用 API。

第二章:开始使用 CreateJS

在本章中,我们将讨论如何在 CreateJS 和 EaselJS 中处理基本对象和事件。在了解这些主题后,你可以使用 CreateJS 的基本方法和函数来创建你的形状,并通过事件来控制它们。

我们将讨论以下主题:

  • 探索 CreateJS

  • 与 API 一起工作

  • 方法与事件

探索 CreateJS

EaselJS 是 CreateJS 的主要模块之一,它使开发者能够与 Canvas 元素一起工作。要使用 EaselJS,我们需要有一个canvas元素,因此所有形状都可以渲染到这个区域。在创建Stage类的实例后,我们需要将displayObject添加到Stage类中。EaselJS 支持以下功能:

  • 位图:这用于图像。

  • 形状图形:这些用于矢量图形。

  • 精灵图集精灵:这些用于动画位图。

  • 文本:这用于简单的文本实例。

  • 容器:这些包含其他 DisplayObjects。

  • DOM 元素:这用于控制 HTML DOM 元素。

Stage对象包裹canvas元素时,所有形状和文本都会出现在Canvas元素中。

注意

更多详情,请查看 EaselJS 文档:www.createjs.com/Docs/EaselJS/modules/EaselJS.html

让我们通过一个在 EaselJS 中创建基本形状的例子来了解一下。这里,我们有一个具有特定高度和宽度的canvas元素:

<canvas id="demoCanvas" width="500" height="200"></canvas>

CreateJS 有一个Stage方法,它接受第一个参数为一个canvas元素,我们应该将我们的canvas元素的 ID 传递给它:

var stage = new createjs.Stage("demoCanvas");

现在我们为我们的canvas元素创建了一个舞台。在下一步中,我们需要创建一个形状:

var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0, 0, 50);
circle.x = 100; 
circle.y = 100; 

提示

下载示例代码

您可以从您在www.packtpub.com购买的 Packt 书籍的账户中下载所有示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support并注册以直接通过电子邮件获得文件。

在第一行,创建了一个名为circle的变量。它包含来自 EaselJS 的Shape对象。所有Shape对象都有一个graphics属性。

在下一行,我们使用beginFill方法将其填充为红色,然后在下一行,我们使用drawCircle方法创建一个圆形。drawCircle方法有三个参数;前两个参数用于定位圆形(x 和 y 轴的值),最后一个参数是像素半径。因此,我们创建了一个位置为0(相对于形状的位置)和半径为50的圆形。

EaselJS 支持方法链,我们可以一个接一个地调用所有函数,就像我们在之前的创建圆形和填充背景颜色的示例中看到的那样。

在创建Shape对象后,我们需要将其添加到我们的stage对象中,并按以下方式更新舞台:

stage.addChild(circle);
stage.update();

请记住,在添加 child (shape, circle 等等) 之后,我们必须从 stage 对象中调用 update 方法来更新舞台;否则,代码将无法正常运行,我们也不会得到期望的结果。您可以在下面的屏幕截图中看到我们简单代码的结果:

探索 CreateJS

与事件一起工作

DisplayObject 有一个方法可以向形状或对象添加事件。使用 addEventListener,我们可以向 DisplayObject(例如,shape)添加事件。此函数有两个强制参数:

  • 事件的名称

  • 事件回调函数

我们将通过以下代码了解这种处理事件的方法:

displayObject.addEventListener("click", handleClick); 
function handleClick(event) {
  // Click happened.
}

在第一行,向 displayObject 添加了一个点击事件,以便当用户点击对象时调用 handleClick 函数。在这个例子中,handleClick 函数是空的。

让我们考虑我们之前的圆圈示例,并向我们的圆圈添加一个点击事件。在点击事件的回调函数内部,我们将圆圈向右移动 10 像素。以下是该代码:

circle.addEventListener("click", handleClick); 
function handleClick(event) { 
event.target.x += 10; 
stage.update(); 
}

在第一行,我们有我们的 DisplayObject。使用 addEventListener,我们将点击事件添加到圆圈上。我们的回调处理程序是 handleClick。在这个函数内部,我们可以获取目标对象(在这个例子中是圆形形状)并通过 event 变量更改形状的属性(例如,宽度、高度或位置)。

event.target 是目标形状对象。在每次回调函数调用中,我们添加 x 属性 10,然后从 stage 对象中调用 update 函数。我们必须在更改属性后调用更新函数,以便应用更改。

记住,为了向 DisplayObject 添加事件,我们首先需要添加事件监听器,然后将 displayObject 添加到舞台中。以下是我们的示例的完整源代码:

var stage = new createjs.Stage("demoCanvas");

var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0, 0, 50);
circle.x = 100; 
circle.y = 100; 

circle.addEventListener("click", handleClick); 
function handleClick(event) { 
  event.target.x += 10; 
  stage.update(); 
}
stage.addChild(circle);
stage.update();

EaselJS 有更多的事件,您可以在之前解释的相同示例中使用它们。

目前 DisplayObjects 支持以下事件:

  • click:用户点击并释放鼠标

  • dblclick:用户双击鼠标

  • mousedown:用户点击鼠标

  • mouseout:用户将鼠标指针从对象移开

  • mouseover:用户将鼠标指针移到对象上

  • pressmove:用户点击鼠标然后移动它

  • pressup:用户在对象上方或外部释放鼠标

  • rollout:用户从子元素移开

  • rollover:用户在子元素上悬停

注意

更多详细信息,请参阅 www.createjs.com/Docs/EaselJS/classes/DisplayObject.html#events

摘要

在本章中,我们学习了如何使用 CreateJS 和 EaselJS 的基本功能和事件。我们学习了如何在 EaselJS 中创建舞台对象,DisplayObject 是什么,以及如何将它们附加到 stage 对象。

我们还在 EaselJS 中创建了第一个简单形状,一个圆。在章节的最后部分,我们讨论了如何在 EaselJS 中为一个对象添加事件监听器。

在下一章中,我们将通过复杂的示例来创建拖放交互,并在 EaselJS 中使用鼠标事件。

第三章:处理拖放交互

在本章中,我们将介绍 CreateJS 的基本事件和回调,以实现拖放功能。阅读本章后,您将能够理解 CreateJS 中对象的常见事件,以及如何更改宽度或高度等属性。本章将涵盖以下主题:

  • 拖放场景

  • 鼠标事件

  • 创建拖放示例

场景

要创建拖放功能,我们只需要将事件绑定到Stage对象上的DisplayObject(如圆圈)上,然后随着鼠标的移动,持续更改目标对象的 x 和 y 轴。幸运的是,CreateJS 提供了许多鼠标悬停事件,我们可以利用它们来实现目标。

在接下来的章节中,我们将看到如何将事件绑定到对象上,并从鼠标光标获取信息。我们还将了解如何更改Stage对象中对象或形状的属性。

理解 on 函数

在 EaselJS 中,您可以访问所有鼠标事件,如点击、鼠标抬起等。MouseEvent实例作为所有鼠标事件回调的唯一参数传递。它包括stageXstageY属性,它们表示光标相对于舞台坐标的位置。

在以下示例中,当鼠标点击圆圈时,pressed将被记录到控制台;之后,每当鼠标移动时,都会记录鼠标移动,直到鼠标释放。

circle.on("mousedown", function(mousedownEvent) {
    console.log("pressed");
    circle.on("pressmove", function(moveEvent) { 
        console.log("mouse moved: "+moveEvent.stageX+","+moveEvent.stageY); 
    });
});

如您所见,我们可以简单地将鼠标事件绑定到我们的DisplayObject对象上,然后在每个事件回调中读取或修改属性。以下截图显示了上一个示例的输出以及鼠标事件的详细信息:

理解 on 函数

在下一节中,我们将把这些东西放在一起,创建一个简单的拖放交互。

创建拖放交互

在上一章中,我们了解到与 EaselJS 一起工作的第一个要求是创建一个Stage对象,然后将所有DisplayObject对象附加到它上。假设我们有一个 ID 为demoCanvasCanvas元素。我们需要以下代码来完成同样的任务:

var stage = new createjs.Stage("demoCanvas");

如果你想在鼠标光标离开Canvas元素时跟踪鼠标光标事件的移动,应将mouseMoveOutsideproperty设置为true

stage.mouseMoveOutside = true;

在下一步中,将创建一个圆:

var circle = new createjs.Shape(); 
circle.graphics.beginFill("red").drawCircle(0, 0, 50);

当然,我们必须将我们的形状添加到以下所示的stage元素中:

stage.addChild(circle);

现在,是时候将函数绑定到mousedownpressmove事件上了:

circle.on("mousedown", function (evt) {
    var offset = {
        x: evt.target.x - evt.stageX,
        y: evt.target.y - evt.stageY
    };

    circle.on("pressmove", function (ev) {
        ev.target.x = ev.stageX + offset.x;
        ev.target.y = ev.stageY + offset.y;
        stage.update();
    });
});

如你所见,我们为显示对象 circlemousedown 事件设置了一个回调函数。在匿名函数内部,有一个偏移变量,它有两个属性,xy。这些属性收集鼠标在形状(本例中的圆)上的每次点击的偏移值,因此我们可以使用这个偏移值来改变圆的位置。在这个例子中,xy 的值可能在 +50 和 -50 之间。

之后,将一个匿名函数添加到形状的 pressmove 事件中。

pressmove 事件的下一个匿名函数内部,我们有两行代码。这两行代码都计算鼠标光标的当前位置,然后改变目标形状的坐标。ev.stageXev.stageY 总是给出舞台内鼠标光标的坐标。因此,使用这些属性,我们可以正确地改变目标形状的坐标。

现在一切准备就绪,但我们需要执行最后一步来完成挑战。正如我们在 EaselJS 中之前学到的,我们应该在 stage 事件中对对象进行任何更改后调用 update 函数,以更新舞台。在拖放示例中,我们正在连续更改目标形状的坐标。因此,我们也必须连续更新 Stage 事件;问题是如何做到这一点。这个问题的答案是,我们必须在每个事件的调用上调用 stage.update(),如下所示:

stage.update();

EaselJS 将在每次更改圆的坐标后更新舞台事件。

完整示例

这里你可以看到创建一个简单的拖放交互的完整源代码:

stage = new createjs.Stage("demoCanvas");
stage.mouseMoveOutside = true;

var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(100, 100, 50);
stage.addChild(circle);

circle.on("mousedown", function(evt) {
    var offset = {
        x: evt.target.x - evt.stageX,
        y: evt.target.y - evt.stageY
    };

    circle.on("pressmove", function(ev) {
        ev.target.x = ev.stageX + offset.x;
        ev.target.y = ev.stageY + offset.y;
        stage.update();
    });
});

stage.update();

运行示例后,你应该看到一个红色圆圈,如下面的截图所示。通过点击并拖动圆圈,圆圈的坐标将会改变。

完整示例

摘要

在这一章中,我们学习了如何处理 mousedownpressmove 事件,如何更改对象属性,以及如何使用 EaselJS 功能连续更新舞台事件。通过结合所有提到的功能,我们可以使用 CreateJS 构建动画或拖放交互。

在下一章中,我们将讨论如何使用 CreateJS 处理对象的动画和变换,以在浏览器中开发出色的动画。

第四章:执行动画和变换功能

现在您已经在前一章学习了如何处理事件和回调,现在是时候继续前进并处理动画和变换功能了。本章预计比前一章更具互动性,因为我们将要讨论并使用 CreateJS 的动画和变换功能。在本章中,我们使用 TweenJSEaselJS 在浏览器中创建基本动画。然后您可以使用这些功能创建更创新的动画。

在本章中,我们将涵盖以下主题:

  • 使用 CreateJS 创建动画

  • 理解 TweenJS

  • 理解 TweenJS API

  • 创建简单动画

  • 变换形状

  • 理解精灵表单

  • 使用精灵表单开发动画

使用 CreateJS 创建动画

如您可能已经知道,在网页开发过程中在网页浏览器中创建动画是一项困难的工作,因为您必须编写必须在所有浏览器中工作的代码;这被称为 浏览器兼容性。好消息是 CreateJS 提供了模块来在网页浏览器中编写和开发动画,而无需考虑浏览器兼容性。CreateJS 模块可以很好地完成这项工作,您需要做的就是与 CreateJS API 一起工作。

理解 TweenJS

TweenJS 是 CreateJS 的模块之一,它帮助您在网页浏览器中开发动画。我们现在将介绍 TweenJS。

TweenJS JavaScript 库提供了一个简单但强大的缓动接口。它支持数字对象属性和 CSS 样式属性的缓动,并允许您将缓动和动作链接在一起以创建复杂的序列。——TweenJS API 文档

如需更多关于 TweenJS 的信息,请参阅官方文档:

www.createjs.com/Docs/TweenJS/modules/TweenJS.html

什么是缓动?

让我们精确地了解什么是缓动:

中间帧或缓动是生成两个图像之间中间帧的过程,以使第一个图像看起来平滑地演变到第二个图像。——维基百科

如需更多关于缓动的信息,请访问:

en.wikipedia.org/wiki/Tweening

什么是缓动?

与其他 CreateJS 子集一样,TweenJS 包含许多函数和方法;然而,我们将使用并创建特定基本方法的示例,基于这些示例,您可以阅读 TweenJS 的其余文档以创建更复杂的动画。

理解 TweenJS 的 API 和方法

为了在 TweenJS 中创建动画,您不需要处理很多方法。有一些函数可以帮助您创建动画。以下都是带有简要描述的方法:

  • get: 它返回一个新的缓动实例。

  • to: 它从当前值到目标属性排队一个缓动。

  • set:它排队一个动作来设置指定目标上的指定属性。

  • wait:它排队等待(本质上是一个空的补间动画)。

  • call:它排队一个动作来调用指定的函数。

  • play:它排队一个动作来播放(暂停)指定的补间。

  • pause:它排队一个动作来暂停指定的补间。

以下是一个使用补间 API 的示例:

var tween = createjs.Tween.get(myTarget).to({x:300},400).set({label:"hello!"}).wait(500).to({alpha:0,visible:false},1000).call(onComplete);

之前的示例将创建一个补间,它:

  • 将目标补间到 x 值为 300,持续时间为 400 毫秒,并将其 label 设置为 hello!

  • 等待 500 毫秒。

  • 将目标的 alpha 属性补间到 0,持续时间为 1 秒,并将 visible 属性设置为 false

  • 最后,调用 onCom 完成函数。

创建简单动画

现在,是时候使用 TweenJS 创建我们最简单的动画了。它是一个简单但功能强大的 API,它赋予你使用 方法链式调用 开发动画的能力。

场景

动画有一个从 Canvas 元素顶部开始并落下的红色球。

场景

在前面的屏幕截图中,你可以看到我们简单动画的所有步骤;因此,你可以预测我们需要做什么来准备这个动画。在我们的动画中,我们将使用两种方法:getto

以下是我们动画的完整源代码:

var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);

var ball = new createjs.Shape();
ball.graphics.beginFill("#FF0000").drawCircle(0, 0, 50);

ball.x = 200;
ball.y = -50;

var tween = createjs.Tween.get(ball) to({
  y: 300
}, 1500, createjs.Ease.bounceOut);

stage.addChild(ball);
createjs.Ticker.addEventListener("tick", stage);

在 JavaScript 代码片段的第二行和第三行中,声明了两个变量,即 canvasstage 对象。在下一行中,声明了 ball 变量,它包含我们的 shape 对象。在接下来的行中,我们使用 drawCircle 方法(我们已在上一章讨论过 drawCircle 方法)绘制了一个红色圆圈。然后,为了将我们的形状对象坐标设置在视口外,我们将 x 轴设置为 -50 像素。

之后,我们创建了一个 tween 变量,它包含 Tween 对象;然后,使用 TweenJS 方法链,调用 to 方法,持续时间为 1500 毫秒,并将 y 属性设置为 300 像素。to 方法的第三个参数代表 tweenease 函数,在这个例子中我们将其设置为 bounceOut

在以下行中,将 ball 变量添加到 Stage,并将 tick 事件添加到 Ticker 类,以在动画播放时保持 Stage 更新。你还可以在 30 行找到 Canvas 元素,使用它渲染所有动画和形状。

变换形状

CreateJS 提供了一些函数,可以在 Stage 上轻松变换形状。每个 DisplayObject 都有一个 setTransform 方法,允许变换 DisplayObject(如圆形)。

以下是一个快捷方法,用于快速设置显示对象的变换属性。所有参数都是可选的。省略的参数将使用默认值设置。

setTransform([x=0] [y=0] [scaleX=1] [scaleY=1] [rotation=0] [skewX=0] [skewY=0] [regX=0] [regY=0])

这是从:

www.createjs.com/Docs/EaselJS/classes/Shape.html#method_setTransform

此外,你可以通过DisplayObject直接更改所有属性(如scaleYscaleX),如下例所示:

displayObject.setTransform(100, 100, 2, 2);

Transforming 函数的示例

作为使用 CreateJS 的形状转换功能的实例,我们将扩展我们之前的示例:

var angle = 0;
window.ball;
var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);

ball = new createjs.Shape();
ball.graphics.beginFill("#FF0000").drawCircle(0, 0, 50);

ball.x = 200;
ball.y = 300;

stage.addChild(ball);

function tick(event) {
  angle += 0.025;
  var scale = Math.cos(angle);

  ball.setTransform(ball.x, ball.y, scale, scale);
  stage.update(event);
}

createjs.Ticker.addEventListener("tick", tick);

在这个例子中,我们有一个红色圆圈,类似于之前的缓动示例。我们将圆圈的坐标设置为200300,并将其添加到stage对象中。在下一行,我们有一个tick函数,它转换圆圈的形状。在这个函数内部,我们有一个angle变量,它在每次调用时增加。然后我们将ballXballY坐标设置为angle变量的余弦值。所进行的转换类似于以下截图:

Transforming 函数的示例

这是在 CreateJS 中转换形状的基本示例,但显然你可以通过调整形状的属性和值来开发更好的转换。

理解精灵图集

在本节中,我们将讨论使用一系列图像制作动画的 EaselJS 功能。这个功能称为精灵图集。精灵图集将一系列图像或动画帧组合成一个 2D 或 3D 动画。例如,如果你想为一个正在行走的英雄制作动画,我们可以将行走角色的所有帧组合成单个图像,然后使用 EaselJS 的精灵图集功能制作动画。

以下是一系列图像(动画帧)的组合成单个图像:

理解精灵图集

在下一节中,你将学习如何使用精灵图集功能开发动画。

使用精灵图集开发动画

让我们先了解SpriteSheet类。这个类用于初始化精灵图集功能并封装其属性和配置。创建SpriteSheet类后,我们可以使用其方法来控制动画。

这个类的基本配置有三个强制属性:

  • 用于动画帧的图像或图像。

  • 每个图像的位置,可以使用单个值定义所有帧,甚至可以为每个帧定义单独的配置。

  • 动画的表现,可以通过起始帧和结束帧定义,或者为每个帧定义单独的值。

以下是一个定义SpriteSheet类配置的代码片段:

data = {
  // list of images or image URIs to use. SpriteSheet can handle preloading.
  // the order dictates their index value for frame definition.
images: [image1, "path/to/image2.png"],

  // the simple way to define frames, only requires frame size because frames are consecutive:
  // define frame width/height, and optionally the frame count and registration point x/y.
  // if count is omitted, it will be calculated automatically based on image dimensions.
frames: {width:64, height:64, count:20, regX: 32, regY:64},

// OR, the complex way that defines individual rects for frames.
  // The 5th value is the image index per the list defined in "images" (defaults to 0).
frames: [
  // x, y, width, height, imageIndex, regX, regY
  [0,0,64,64,0,32,64],
  [64,0,96,64,0]
],

  // simple animation definitions. Define a consecutive range of frames (begin to end inclusive).
  // optionally define a "next" animation to sequence to (or false to stop) and a playback "speed".
animations: {
  // start, end, next, speed
run: [0,8],
jump: [9,12,"run",2]
}

// the complex approach which specifies every frame in the animation by index.
animations: {
  run: {
  frames: [1,2,3,3,2,1]
  },
  jump: {
    frames: [1,4,5,6,1],
    next: "run",
    speed: 2
  },
stand: { frames: [7] }
  }
}

以下是为SpriteSheet类提供的示例配置:

var data = {
  images: ["sprites.jpg"],
  frames: { width:50, height:20 },
  animations: { 
    run:[0,4], 
    jump:[5,8,"run"]
  }
};

这在www.createjs.com/Docs/EaselJS/classes/SpriteSheet.html中有更详细的解释。

现在,我们将使用精灵图集开发一个简单的行走动画。以下是我们将用于动画帧的精灵图像:

使用精灵图集开发动画

精灵图像

下一步是配置我们的 SpriteSheet 类。以下是其配置:

var data = {
  "animations":
  {
    "run": [0, 15]
  },
  "images": ["running.png"],
  "frames": {
    "height": 70,
    "width": 51,
    "regX": 0,
    "regY": 0,
    "count": 16
  }
};

我们动画总共有 16 帧;因此,定义动画帧的 run 帧集从 0 开始,扩展到 15。我们定义了精灵图像的路径。然后我们定义了帧的配置,高度为 70,宽度为 51(这是每个单独图像的宽度),以及一个表示帧数的 16

以下是为动画提供的完整源代码:

stage = new createjs.Stage(document.getElementById("canvas"));

varss = new createjs.SpriteSheet({
  "animations":
  {
    "run": [0, 15]
  },
  "images": ["running.png"],
  "frames": {
    "height": 70,
    "width": 51,
    "regX": 0,
    "regY": 0,
    "count": 16
  }
});

var grant = new createjs.Sprite(ss, "run");

stage.addChild(grant);
createjs.Ticker.setFPS(40);
createjs.Ticker.addEventListener("tick", stage);

如前文示例所示,首先我们使用 Stage 类定义了舞台。之后,使用配置信息初始化了 SpriteSheet 类,然后将对象传递给 Sprite 类以开始动画。Sprite 类的第二个参数定义了动画的起始帧集。最后,我们使用 addChild 方法将 Sprite 对象添加到舞台中。

Ticker 类添加 tick 事件并将 Stage 对象传递给它以启动动画是很重要的;否则,你将看到一个空白的屏幕。此外,使用 Ticker 类和 setFPS 方法,我们可以控制动画渲染的比率。

以下图像展示了我们的精灵图集示例的预览:

使用精灵图集开发动画

摘要

在本章中,我们学习了如何使用 TweenJS 和 EaselJS 开发和创建动画。我们详细讨论了在 TweenJS 中使用链式方法、动画中的回调函数,以及如何使用 TweenJS 函数更改形状的属性。然后我们学习了如何使用 EaselJS 进行变换,以更改形状的属性,如旋转或缩放。接着我们学习了如何利用精灵图集功能来创建动画角色。

在下一章中,我们将讨论 CreateJS 中的缓存技术以及如何通过缓存来提高应用程序的性能。

第五章:在 EaselJS 中利用缓存

正如你所知,在开发动画后,解决性能问题以使其平滑运行非常重要。渲染动画的性能在不同浏览器之间有所不同,但有一些技术,如缓存,可以简单地提高性能。在本章中,我们将学习如何使用 DisplayObjectEaselJS 缓存系统制作更好、更平滑的动画或绘图。

在本章中,我们将涵盖以下主题:

  • 探索 EaselJS 的缓存功能

  • 理解缓存方法

  • 缓存使用示例

  • 在动画中使用缓存

  • 使用位图缓存

探索 EaselJS 的缓存功能

在 EaselJS 中,当你有一个形状,或者更好的是,一个不经常改变的 DisplayObject 实例时,最好使用 缓存 函数将其缓存到一个不同的 Canvas 元素中。这种技术将帮助你使用 EaselJS 在绘图过程中平滑地动画化和渲染动画或绘图,因为形状不需要在每一帧中重新渲染。

这基本上是使用 DisplayObject 类中的 cache 方法的核心思想。你所需要做的就是更多地了解如何在 EaselJS 中使用缓存方法。在接下来的章节中,我们将介绍方法、它们的用法以及如何使用缓存创建动画。

理解缓存方法

为了理解在 EaselJS 中缓存 DisplayObject 的工作原理,我们以一个假想的画布区域为例,这样缓存的元素就会被渲染到其中,每次你需要更新目标形状时,你再次调用 cache 方法。

你可以在以下代码片段中看到 DisplayObject 类中 cache 方法的定义:

cache (x, y, width, height, [scale=1])

将显示对象绘制到一个新的画布上,然后用于后续的绘制。对于不经常改变的内容(例如,一个包含许多不移动的子项的容器,或一个复杂的矢量形状),这可以提供更快的渲染速度,因为内容不需要在每一帧中重新渲染。缓存的显示对象可以自由移动、旋转、淡入淡出等,然而如果其内容发生变化,你必须手动通过调用 updateCache() 或再次调用 cache() 来更新缓存。你必须通过 x、y、w 和 h 参数指定缓存区域。这定义了将使用此显示对象的坐标渲染和缓存的矩形。

这是从以下内容摘录的:

www.createjs.com/Docs/EaselJS/classes/DisplayObject.html#method_cache

如你所见,cache 方法接受四个强制参数和一个可选参数。第一个和第二个参数定义了缓存区域的 坐标;第三个和第四个参数定义了缓存区域的 宽度高度。使用最后一个参数,你可以在缓存区域内定义形状的 缩放比例。默认设置为 1,但你也可以更改它。

缓存使用示例

现在是时候看看在 EaselJS 中使用cache方法的示例了。以下代码片段使用cache方法将一个圆渲染到画布元素中:

var shape = new createjs.Shape(); 
shape.graphics.beginFill("#ff0000").drawCircle(0, 0, 25); 
shape.cache(-25, -25, 50, 50);

在第一行中,我们使用Shape类创建了一个形状,用红色填充,然后在(0, 0)位置以25的半径渲染它。在第三行中,你会注意到cache方法的使用。在这一行中,创建了一个位于-25-25缓存区域,宽度和高度为50

注意

为了更新目标形状(如上述示例中的形状变量),你需要再次调用cacheupdateCache方法,并带上所有新的参数。

完整的源代码和结果如下:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
<title>Cache method in EaselJS</title>
<script type='text/javascript' src='createjs.js'></script>

<script type='text/javascript'>
window.onload=function() {
  var canvas = document.getElementById("testCanvas");
  var stage = new createjs.Stage(canvas);

  var shape = new createjs.Shape();
  shape.graphics.beginFill("#ff0000").drawCircle(0, 0, 25); 
  shape.cache(-25, -25, 50, 50);

  stage.addChild(shape);
  stage.update();
}
</script>

</head>
<body>
<canvas id="testCanvas" width="400" height="100" style="border: 1px solid black;"></canvas>
</body>
</html>

上述源代码是使用 EaselJS 中缓存方法完成的示例。此源代码的结果如下面的截图所示:

使用缓存的示例

在复杂形状和动画中使用缓存

在 EaselJS 中,当你画布中有复杂形状或动画时,缓存非常有用。在大多数情况下,带有细节的复杂形状不应该在每个 tick 中渲染。因此,你可以简单地使用缓存方法来缓存它,以防止渲染开销。

现在我们将看到一个来自 EaselJS 库的复杂示例(来源:github.com/CreateJS/EaselJS/blob/master/examples/Cache.html)以及使用缓存技术在其中的效果。在这个动画中,我们将创建大约200个复杂的圆圈并在每个 tick 上移动它们。页面上有一个复选框,用于通过cacheuncache方法启用或禁用画布区域内所有形状的缓存。

以下截图展示了我们动画的预览(注意复选框):

在复杂形状和动画中使用缓存

有三个主要函数处理这个动画和所有逻辑;initticktoggleCache。我们将分别讨论每一个。

在代码的第一行中,我们将使用以下变量:

var canvas;
var stage;
var shape;
varcircleRadius= 30;
var rings = 30;

第一个变量持有画布元素,第二个用于Stage对象,shape变量用于在舞台上绘制形状,而circleRadiusrings用于圆的基本设置。circleRadius用于定义每个圆的半径,而rings用于定义每个圆内环的数量。

以下代码展示了绘制所有形状并准备舞台的基本init方法:

Function init() {
  // create a new stage and point it at our canvas:
  canvas = document.getElementById("testCanvas");
  stage = new createjs.Stage(canvas);

  // create a large number of slightly complex vector shapes, and give them random positions and velocities:

  var colors = ["#828b20", "#b0ac31", "#cbc53d", "#fad779", "#f9e4ad", "#faf2db", "#563512", "#9b4a0b", "#d36600", "#fe8a00", "#f9a71f"];

  for(var i= 0; i< 200; i++) {
    shape = new createjs.Shape();
      for(var j = rings; j > 0; j--) {
        shape.graphics.beginFill(colors[Math.random() * colors.length | 0]).drawCircle(0, 0, circleRadius * j / rings);
    }
    shape.x = Math.random() * canvas.width;
    shape.y = Math.random() * canvas.height;
    shape.velX = Math.random() * 10 - 5;
    shape.velY = Math.random() * 10 - 5;

    stage.addChild(shape);
  }

  // add a text object to output the current FPS:
  fpsLabel = new createjs.Text("-- fps", "bold 18px Arial", "#FFF");
  stage.addChild(fpsLabel);
  fpsLabel.x = 10;
  fpsLabel.y = 20;

  // start the tick and point it at the window so we can do some work before updating the stage:
  createjs.Ticker.addEventListener("tick", tick);
  createjs.Ticker.setFPS(50);
}

这段代码用于创建舞台和所有形状对象。在第 3 和第 4 行中,创建了Stage对象。在第 8 行中,我们为圆环定义了随机颜色。之后,我们使用了一个for 循环,在舞台上绘制了 200 个不同位置的随机圆圈。在第 12 行中,我们还有一个 for 循环来绘制圆圈内部的环。

在我们的动画中,有一个标签指示每次 tick 的每秒帧数FPS)。因此,在第 28 到 31 行,我们定义了我们的标签属性。在第 34 行,创建了Ticker类,在第 36 行,动画的 FPS 被设置为50

init函数之后,我们有一个 tick 函数,它将由 EaselJS 在每次 tick 时调用:

function tick(event) {
  var w = canvas.width;
  var h = canvas.height;
  var l = stage.getNumChildren() - 1;

  // iterate through all the children and move them according to their velocity:
  for(var i= 1; i< l; i++) {
    var shape = stage.getChildAt(i);
    shape.x = (shape.x + shape.velX + w) % w;
    shape.y = (shape.y + shape.velY + h) % h;
  }
  fpsLabel.text = Math.round(createjs.Ticker.getMeasuredFPS()) + " fps";
  // draw the updates to stage:
  stage.update(event);
}

上面的init函数的主要任务是每次 tick 时改变舞台上的所有圆的位置,将当前 FPS 速率设置为标签,然后更新舞台。第 4 行中的-1的原因是排除标签对象从children中;请记住,我们只需要改变所有圆的位置。

最后一个函数是toggleCache函数。此方法为所有圆形启用或禁用缓存:

function toggleCache(value) {
  // iterate all the children except the fpsLabel, and set up the cache:
  var l = stage.getNumChildren() - 1;
  for(var i= 0; i< l; i++) {
    var shape = stage.getChildAt(i);
    if (value) {
      shape.cache(-circleRadius, -circleRadius, circleRadius * 2,circleRadius * 2);
    } else {
      shape.uncache();
    }
  }
}

这个函数仅在你在页面上勾选或取消勾选复选框时被调用,因此它为stage上所有圆形对象启用或禁用缓存。有一个 for 循环遍历所有圆形形状,并根据复选框的状态调用cacheuncache方法。因此,圆形形状的缓存将被启用或禁用。

通过点击复选框,你可以明显看到当启用缓存时,动画渲染变得更加平滑。

最后,你可以在 Packt 网站上找到我们动画的完整源代码。

缓存位图

在本节中,我们将利用cache方法和AlphaMaskFilter在 EaselJS 中开发反射效果。目标是加载一个图像并创建一个Bitmap类来绘制图像。然后,克隆Bitmap图像,改变旋转并添加渐变背景,并使用AlphaMaskFilter创建反射效果。

下面的截图是结果的预览:

缓存位图

下面的代码是这个示例的源代码:

function init() {
  var canvas = document.getElementById("canvas");
  var stage = new createjs.Stage(canvas);

  var image = new Image();
  image.src = "easeljs.png";

  //wait to load the image
  image.onload = function(evt) {
    var bitmap = new createjs.Bitmap(evt.target);
    var width = bitmap.image.width;
    var height = bitmap.image.height;

    //clone the existing bitmap to use as reflection
    var reflectBitmap = bitmap.clone();
    reflectBitmap.regY = height;
    reflectBitmap.rotation = 180;

    //to add a padding from the main bitmap
    reflectBitmap.y = height + 2;
    reflectBitmap.scaleX = -1;

    var maskShape = new createjs.Shape();
    var graphics = maskShape.graphics;
    //add reflection effect
    graphics.beginLinearGradientFill(["rgba(255, 255, 255, 0)", "rgba(255, 255, 255, 0.6)"], [0.5, 1], 0, 10, 0, height);
    graphics.drawRect(0, 0, width, height);
    graphics.endFill();

    maskShape.cache(0, 0, width, height);

    reflectBitmap.filters = [new createjs.AlphaMaskFilter(maskShape.cacheCanvas)];
    reflectBitmap.cache(0, 0, width, height);

    //add both pictures
    stage.addChild(bitmap);
    stage.addChild(reflectBitmap);
    stage.update();
  }
}

如前例所示,首先我们创建了Stage类。然后,为了加载图像,我们使用了Image类并将图像的地址传递给src属性。Image类有一个onload事件,这有助于开发人员知道图像是否已完全加载。我们使用此事件来正确执行应用程序的其他部分。

之后,我们使用Bitmap类并将Image类的图像参数传递给它。因为我们需要图片的宽度和高度,我们将它们保存到两个不同的变量中,分别称为widthheight。此时,我们已经有了一幅图片,但我们还需要另一幅图片来创建反射效果。因此,我们使用了clone函数来复制图像。为了改变第二幅图像的旋转、缩放和坐标,我们改变了regYrotationyscaleX属性。

之后,使用 Shape 类创建了一个新的形状。这是将要用于 AlphaMaskFilter 的遮罩层。然后,我们向其添加了线性背景以创建反射效果,并使用 cache 函数进行了缓存。最后,将 AlphaMaskFilter 添加到第二张图片(一个克隆的 Bitmap 类)上,并将此形状用作遮罩层。第二张图片也再次进行了缓存。这两张图片都通过 addChild 函数添加到 Stage 中,并且 Stage 也通过 update 函数进行了更新。

摘要

在本章中,我们学习了如何在 EaselJS 中使用 cache 方法来创建更好的画布绘制和动画。我们在 EaselJS 中使用缓存的原因是为了在浏览器中提供更好的动画渲染速度,同时在渲染动画或绘图时使用更少的资源。在下一节中,我们讨论了如何使用 cache 方法与 Bitmap 类结合来创建反射效果。

在下一章中,我们将讨论如何在 EaselJS 中应用滤镜于画布,这是 EaselJS 的最佳特性之一,你可以利用这个特性制作出令人惊叹的作品。

第六章。在 EaselJS 中使用过滤器

CreateJS 的一个伟大功能是能够轻松地玩转过滤器并将各种过滤器应用于图片和形状。CreateJS 通过提供Filter类和DisplayObjectfilters属性来实现这一点;因此,我们可以简单地创建Filter类的实例并将它们应用于对象。在本章中,我们将查看 CreateJS 过滤器以及与Filter类一起工作的基本示例。

在本章中,我们将涵盖以下主题:

  • 理解Filter

  • 如何使用内置的 EaselJS 过滤器

理解过滤器类

EaselJS 提供了一个Filter类,这是所有其他过滤器的基类,其他过滤器类应该从这个类继承。过滤器需要应用于使用cache方法缓存的对象;之后,如果对象再次更改,我们应该使用cacheupdateCache方法来更新形状。

以下是将过滤器应用于对象的示例:

  /* Add canvas and stage */
  var canvas = document.getElementById("canvas");
  var stage = new createjs.Stage(canvas);

/* create and draw the shape */
var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(50, 50, 40);

/* add the blur filter to filters property */
circle.filters = [new createjs.BlurFilter(5, 5, 10)];
/* cache the shape to apply the filter */
circle.cache(0, 0, 100, 100);
/* add shape to stage and update */
stage.addChild(circle);
stage.update();

在第一行,我们创建了一个形状对象;在下一行,我们创建了一个红色的圆形。下一行包含过滤器配置,而在最后一行我们使用cache函数缓存了对象。

在带有过滤器的示例中使用cache方法不仅可以提高性能,还可以将过滤器应用于形状并使其工作。

理解过滤器类

EaselJS 包含几个基本过滤器,如blurcolor过滤器,您可以使用它们。以下是一个内置过滤器的列表:

  • AlphaMapFilter:这个用于将灰度图像映射到显示对象的 alpha 通道。

  • AlphaMaskFilter:这个用于将图像的 alpha 通道映射到显示对象的 alpha 通道。

  • BlurFilter:对显示对象应用垂直和水平模糊。

  • ColorFilter:这个颜色转换显示对象。

  • ColorMatrixFilter:使用ColorMatrix转换图像。

在下一节中,我们将详细讨论所有这些过滤器。

使用 AlphaMapFilter 类

AlphaMapFilter是一个内置过滤器,用于将灰度 alpha 映射图像(或画布)应用于目标。为了更清晰,结果图像的 alpha 通道将从映射的红通道复制,而 RGB 通道将从目标对象复制。

通常,建议您使用AlphaMaskFilter,因为它具有更好的性能。

这是从:www.createjs.com/Docs/EaselJS/classes/AlphaMapFilter.html中摘取的。

以下代码片段是该类的定义:

AlphaMapFilter (alphaMap)

参数如下:

alphaMap | Image | HTMLCanvasElement

我们已经使用了灰度图像或画布作为 alpha 通道。它应该与目标具有相同的尺寸。

以下是一个使用AlphaMapFilter类的示例代码:

/* Add canvas and stage */
var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);

/* Create filter */
var box = new createjs.Shape();
box.graphics.beginLinearGradientFill(["#0000ff", "#ff0000"], [1, 0], 0, 0, 0, 300)
box.graphics.drawRect(0, 0, 300, 300);
box.cache(0, 0, 300, 300);

/* create the second shape */
var box2 = new createjs.Shape();
box2.graphics.beginLinearGradientFill(["#0000ff", "#ff0000"], [0, 1], 0, 0, 0, 300);
box2.graphics.drawRect(0, 0, 300, 300);

/* Add filter to box2 */
box2.filters = [
  new createjs.AlphaMapFilter(box.cacheCanvas)
];
/* and finally, cache the shape to apply changes */
box2.cache(0, 0, 300, 300);

/* Add bitmap to stage and update stage */ 
stage.addChild(box2);
stage.update();

在代码的第一行中,我们创建了一个具有线性渐变的矩形,然后使用cache方法缓存了对象。缓存对象的原因是将其用于滤镜参数。

然后,我们创建了box2变量;它是我们的父形状。这个形状与第一个相同,但渐变颜色不同。我们改变了线性渐变的起始和结束颜色。之后,我们将AlphaMapFilter添加到box2的滤镜中,并将box变量作为滤镜的参数。然后,为了将滤镜应用于形状,我们使用cache方法缓存了形状并将其添加到舞台中。

以下图像显示了上一个示例的预览:

使用 AlphaMapFilter 类

使用 AlphaMaskFilter 类

此滤镜的使用方式与AlphaMapFilter类相似,但我们将简要讨论此滤镜。根据 CreateJS 文档,建议您使用此滤镜而不是AlphaMapFilter,因为它具有更好的性能。

AlphaMaskFilter将来自遮罩图像(或画布)的 alpha 遮罩应用于目标。结果的 alpha 通道将来自遮罩,而 RGB 通道将复制自目标对象。

这里是我们如何定义AlphaMaskFilter类的:

AlphaMaskFilter (mask)

代码片段中的参数如下:

mask | Image

这个类是Image类的一个实例。

下面是一个使用此滤镜的示例:

/* Declare variables */
var canvas, stage, img;

function init() {
  /* Add canvas and stage */
  canvas = document.getElementById("canvas");
  stage = new createjs.Stage(canvas);

  /* Load image */
  img = new Image();
  img.onload = handleimg;   //function that's called once image has loaded
  img.src = "targetImg.png";  //image url
}

function handleimg() {
  /* Create mask layer */
  var box = new createjs.Shape();
  box.graphics.beginLinearGradientFill(["#000000", "rgba(0, 0, 0, 0)"], [0, 1], 0, 0, 0, 200)
  box.graphics.drawRect(0, 0, 200, 200);
  box.cache(0, 0, 200, 200);

  /* Create bitmap */
  var bmp = new createjs.Bitmap(img); 

  /* Add filter to bitmap */
  bmp.filters = [
     new createjs.AlphaMaskFilter(box.cacheCanvas)
  ];
    bmp.cache(0, 0, 200, 200);

  /* Add bitmap to stage and update stage */ 
  stage.addChild(bmp);
  stage.update();
}

如您所见,此滤镜的使用几乎与AlphaMapFilter相同。

示例源代码分为两个函数,inithandleimg。为了正确加载图像,我们使用了Image类和onload事件。然后,我们使用handleimg函数作为onload事件的回调函数。

init函数内部,创建了stage类。我们还配置了Image类,并将handleimg函数分配给onload事件。示例源代码的大部分内容都在handleimg函数中。在第一行代码中,我们创建了一个具有线性渐变背景的矩形。使用rgba函数定义颜色的原因是为了改变渐变的 alpha 通道,以便滤镜可以为最终结果提取这个 alpha 通道。最后,我们使用cache方法缓存了形状。

然后,我们使用Bitmap函数加载了一张图片,并将其应用于bmp变量的filters属性。我们还缓存了这张图片以便应用滤镜变化。

以下截图显示了我们的示例结果:

使用 AlphaMaskFilter 类

实现 BlurFilter 类

模糊滤镜是用于创建创新动画和绘图的可用滤镜之一。在本节中,我们将讨论使用BlurFilter类。

此滤镜将一个模糊框应用于DisplayObject

注意

此过滤器是 CPU 密集型的,尤其是当质量设置为大于 1 时。

下面是BlurFilter类及其参数的定义:

BlurFilter ([blurX=0] [blurY=0] [quality=1])

代码片段中包含的参数如下:

  • [blurX=0] | 数值:这是一个可选参数。它用于设置以像素为单位的水平模糊半径。

  • [blurY=0] | 数值:这是一个可选参数。它用于设置以像素为单位的垂直模糊半径。

  • [quality=1] | 数值:这是一个可选参数。它用于设置模糊迭代的次数。

下面是使用红色圆形应用模糊过滤器的示例:

/* Add canvas and stage */
var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);

/* create circle shape */
var shape = new createjs.Shape().set({x:100,y:100});
shape.graphics.beginFill("#ff0000").drawCircle(0,0,50);

/* create blur filter and add to shape */
var blurFilter = new createjs.BlurFilter(5, 5, 1);
shape.filters = [blurFilter];

/* add getbounds to give spread effect to blur */
var bounds = blurFilter.getBounds();
shape.cache(-50+bounds.x, -50+bounds.y, 100+bounds.width, 100+bounds.height);

/* add shape to stage and update */
stage.addChild(shape);
stage.update();

在第一行,我们有shape变量,这是我们形状的变量,一个圆形。在下一行,我们用红色填充了圆形,并使用drawCircle函数完成了形状的绘制。

然后,我们使用三个参数创建了模糊过滤器,并将其应用于具有filters属性的shape对象。为了找到缓存区域的尺寸,我们使用了getBounds函数,因为你知道,在应用getBounds函数之后,模糊过滤器会有一些额外的填充。

实现类

使用ColorFilter

此过滤器将颜色转换应用于DisplayObject。当你需要在 EaselJS 中玩转颜色时,此过滤器非常有用。

在以下代码片段中,你可以看到此过滤器的定义:

ColorFilter ([redMultiplier=1] [greenMultiplier=1][blueMultiplier=1] [alphaMultiplier=1] [redOffset=0][greenOffset=0] [blueOffset=0] [alphaOffset=0])

代码片段中的各种参数如下:

  • [redMultiplier=1]数值:这是一个可选参数。它设置与红色通道相乘的值。该值应在 0 和 1 之间。

  • [greenMultiplier=1]数值:这是一个可选参数。它设置与绿色通道相乘的值。该值应在 0 和 1 之间。

  • [blueMultiplier=1]数值:这是一个可选参数。它设置与蓝色通道相乘的值。该值应在 0 和 1 之间。

  • [alphaMultiplier=1]数值:这是一个可选参数。它设置与 alpha 通道相乘的值。该值应在 0 和 1 之间。

  • [redOffset=0]数值:这是一个可选参数。它设置在红色通道乘以之后要添加的值。该值应在-255 和 255 之间。

  • [greenOffset=0]数值:这是一个可选参数。它设置在绿色通道乘以之后要添加的值。该值应在-255 和 255 之间。

  • [blueOffset=0]数值:这是一个可选参数。它设置在蓝色通道乘以之后要添加的值。该值应在-255 和 255 之间。

  • [alphaOffset=0]数值:这是一个可选参数。它设置在 alpha 通道乘以之后要添加的值。该值应在-255 和 255 之间。

下面是使用此过滤器的示例:

/* Add canvas and stage */
var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);

var shape = new createjs.Shape().set({x:100,y:100});
shape.graphics.beginFill("#ff0000").drawCircle(0,0,50);

shape.filters = [
  new createjs.ColorFilter(0,0,0,1, 0,0,255,0)
];
shape.cache(-50, -50, 100, 100);
/* add shape to stage and update */
stage.addChild(shape);
stage.update();

在这个例子中,我们创建了一个红色圆圈,然后使用ColorFilter将其颜色改为蓝色。这是通过将所有通道乘以 0(除了 alpha 通道,设置为 1)然后向蓝色通道添加 255,向其他通道添加 0 来完成的。

利用 ColorFilter 类

使用 ColorMatrixFilter 类

使用这个过滤器,你可以玩转复杂的颜色操作,例如饱和度、亮度或反转。这个过滤器使用ColorMatrix类来执行操作。

以下代码片段定义了这个类:

ColorMatrixFilter (matrix)

代码片段中存在的参数如下:

  • matrix– 数组:一个 4x5 的矩阵,描述了使用ColorMatrix类要执行的颜色操作。

下面是使用这个过滤器的例子:

/* Add canvas and stage */
var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);

var shape = new createjs.Shape().set({x:100,y:100});
shape.graphics.beginFill("#ff0000").drawCircle(0,0,50);

var matrix = new createjs.ColorMatrix().adjustHue(180).adjustSaturation(100);
shape.filters = [
 new createjs.ColorMatrixFilter(matrix)
];

shape.cache(-50, -50, 100, 100);
/* add shape to stage and update */
stage.addChild(shape);
stage.update();

在前面的例子中,我们创建了一个红色圆圈,然后反转了色调并将饱和度改为 100。我们首先在第一行创建了stage类。然后,我们使用drawCircle函数创建了一个圆。为了将圆放置在canvas元素的视口中,我们使用set函数更改了xy的值。

然后,我们使用ColorMatrix类初始化了matrix变量。我们使用了adjustHueadjustSaturation函数来改变圆的色调和饱和度。adjustHue的可接受值在-180 到 180 之间。adjustSaturation的值在-100 到 100 之间。在我们的例子中,我们将色调值设置为 180,饱和度值设置为 100,以便更好地观察差异。

我们应用了shape变量的filter属性的所有功能。最后,我们使用cache方法缓存了形状,并使用update方法更新阶段以应用这些更改。

使用 ColorMatrixFilter 类

摘要

在这一章中,我们学习了如何使用 EaselJS 的内置过滤器来更改DisplayObject属性,如颜色、色调、饱和度等。我们还通过交互式示例和截图讨论了过滤器的定义和基本用法。

在下一章中,我们将讨论如何使用我们迄今为止所学到的所有方法和函数创建一个基于网页的绘画应用程序。

第七章. 开发绘画应用程序

在本章中,我们将创建一个简单的绘画应用程序,使用几乎我们在前几章中已经讨论过的所有 EaselJS 功能。本章将更加互动和具有挑战性,因为我们需要总结我们已经学到的所有内容。所以,让我们开始吧。

在本章中,我们将涵盖以下主题:

  • 准备舞台

  • 理解 mousemovemouseupmousedown 事件

  • 实现每个回调函数

准备舞台

此应用程序的整体功能几乎与拖放应用程序相同;我们将使用 mousedownmouseupmousemove 事件来处理绘画逻辑。首先,我们将创建一个 stage 对象,然后是一个用于画笔颜色的颜色数组。我们将启用 Web 浏览器和支持触摸事件的设备的 触摸功能。最后,我们为 mousedownmouseupmousemove 事件设置回调函数来处理绘图功能和绘制线条。

以下截图显示了我们的绘画应用程序的预览:

准备舞台

最终的源代码由以下函数组成:

  • init: 它用于创建舞台并准备其他对象。

  • handleMouseDown: 它用于处理 mousedown 事件并绑定 mousemove 事件。

  • handleMouseMove: 它用于处理 mousemove 事件并绘制线条。

  • handleMouseUp: 它用于处理 mouseup 事件并解绑 mousemove 事件以停止绘图。

以下图像说明了事件如何协同工作以绘制线条:

准备舞台

在接下来的章节中,我们将更详细地讨论源代码及其创建方式。

理解初始化函数

init 函数内部,我们将设置舞台,声明基本变量,并将函数附加到主要事件,如 mousedown 事件。

以下代码是 init 函数的源代码:

function init() {
  var canvas = document.getElementById("cvs");
  var index = 0;
  var colors = ["#828b20", "#b0ac31", "#cbc53d", "#fad779", "#f9e4ad", "#faf2db", "#563512", "#9b4a0b", "#d36600", "#fe8a00", "#f9a71f"];

  var stage = new createjs.Stage(canvas);
  stage.autoClear = false;
  stage.enableDOMEvents(true);

  createjs.Touch.enable(stage);
  createjs.Ticker.setFPS(24);
  drawingCanvas = new createjs.Shape();

  stage.addEventListener("stagemousedown", handleMouseDown);
  stage.addEventListener("stagemouseup", handleMouseUp);

  stage.addChild(drawingCanvas);
  stage.update();
}

在函数体的第一行,我们有一个全局的 canvas 变量,它指向页面中的 Canvas 元素。我们有一个 index 变量,它持有计数器以在绘画时选择画笔颜色,下一行包含一个颜色数组。我们使用 index 变量从这个数组中随机选择一个值。之后,如前例所示,我们必须创建一个 stage 对象;这也是一个全局变量。

之后,我们将 stageautoClear 属性设置为 false。此属性表示舞台是否应自动清除画布上的渲染元素。通过将此值设置为 false,我们可以手动控制清除。

然后,我们使用 enableDOMEvents 方法启用了 DOM文档对象模型)事件。此方法实际上启用了或禁用了 stage 添加到 DOM 元素(如窗口、文档和画布)的事件监听器。

在下面的行中,配置了触摸事件和每秒帧数FPS)。setFPS函数设置了目标帧率(以每秒帧数计)。这个函数是Ticker类的一个成员。Ticker类是 EaselJS 的主要功能之一,它提供了一个集中的计时器或心跳,监听器可以订阅计时器事件,以便在时间流逝时得到通知。

然后,全局变量drawingCanvas使用一个Shape对象初始化,它将成为我们的绘画形状。在以下事件中,我们将使用这个变量来完成绘制过程。

此外,mousedownmouseup事件被分配给适当的函数,然后一个绘画形状被添加到stage中。添加事件监听器有多种方法,其中之一是使用addEventListener函数。将事件名称和函数传递给它。在这个例子中,我们使用了addEventListener函数。

与前面的例子类似,我们必须将形状添加到stage中,并使用update函数更新它。在下面的行中,我们将形状添加到stage中并更新了它。

这是对init函数的定义。实际上,这个函数是一个引导函数,用于启动绘画应用程序。在这个函数内部,所有用于绘画和绘制的相关事件都进行了配置。在接下来的章节中,我们将讨论事件回调函数。

实现 handleMouseDown 函数

以下代码是handleMouseDown函数的源代码,该函数用于处理mousedown事件:

function handleMouseDown(event) {
  color = colors[(index++) % colors.length];
  stroke = Math.round(Math.random() * 30 + 10);
  oldPt = new createjs.Point(stage.mouseX, stage.mouseY);
  oldMidPt = oldPt;
  stage.addEventListener("stagemousemove", handleMouseMove);
}

这个函数用于处理mousedown事件,并在按下鼠标按钮后被调用。在这个函数内部,我们设置了笔触的颜色和大小,并保存当前的鼠标位置以供下一次函数调用使用。

所有变量都是全局的,因此你不会在它们前面看到任何var关键字,以便在后续的函数调用和其他作用域中拥有这些变量。在最后一行,一个函数还设置了mousemove事件,以便管理绘制线条。实际上,mousemove事件会在鼠标光标在stage中移动时触发。

笔刷的颜色是从init函数中定义的colors数组中依次选择的,使用index变量。我们为了从数组中选择下一个颜色所做的是增加index变量,然后计算除法的余数。通过这个简单的技巧,我们可以选择一个介于零和数组长度之间的值。

笔刷的大小是通过使用random函数来选择的。JavaScript 中的Math类中的random函数返回一个介于 0 和 1 之间的值(但不包括 1)。通过将这个值乘以 30,我们可以得到一个介于 0 和 30 之间的值(但不包括 30)。JavaScript 中的round函数也会向上取整一个数字。

那段代码的重要部分是 stage.mouseXstage.mouseY 返回 Canvas 元素上的当前鼠标坐标。我们使用这些变量来获取鼠标位置并将其保存在全局变量中。这些值将用于绘制线条,我们之所以将它们保存在全局变量中,是为了在其他作用域和函数中提供可访问性。正如你所见,我们使用了 Point 类来收集鼠标光标的坐标。Point 类代表 EaselJS 中的二维坐标系,我们使用这个类来保存光标指针。

使用 handleMouseMove 函数

这个函数实际上绘制线条,并用于处理 mousemove 事件。这是我们处理绘制的主体函数。

mousemove 函数的源代码如下:

function handleMouseMove(event) {
  var midPt = new createjs.Point(oldPt.x + stage.mouseX>> 1,oldPt.y + stage.mouseY>> 1);

  drawingCanvas.graphics.clear().setStrokeStyle(stroke, 'round', 'round').beginStroke(color).moveTo(midPt.x, midPt.y).curveTo(oldPt.x, oldPt.y,oldMidPt.x, oldMidPt.y);

  oldPt.x = stage.mouseX;
  oldPt.y = stage.mouseY;

  oldMidPt.x = midPt.x;
  oldMidPt.y = midPt.y;

  stage.update();
}

当鼠标光标在 stage 上拖动时,这个函数会持续被调用。在这个函数中,我们使用 beginStroke 函数绘制线条,并再次保存当前的鼠标位置以便在后续的函数调用中使用;实际上,是下一次鼠标移动。随着鼠标光标的每次移动,这个函数都会再次被调用,因此我们将得到线条。

注意

在第一行中,你可以看到右移操作符(>> 操作符)。我们使用这个函数来简化 Math.floor(num / 2) 操作。

实际上,num>> 1Math.floor(num / 2) 有相同的结果。

之后,我们使用 update 函数更新 stage,以将更改应用到 stage 并将一切渲染到画布上。

使用 handleMouseUp 函数

当用户释放鼠标点击时,这个函数会被调用,并用于结束绘制线条并从 stage 中移除事件。其源代码如下:

function handleMouseUp(event) {
  stage.removeEventListener("stagemousemove", handleMouseMove);
}

在这个函数中,我们只调用 removeEventListener 来移除 mousemove 事件,并防止再次调用该函数。在从 stage 中移除此事件后,handleMouseMove 函数将不再被调用。因此,通过移动鼠标光标,EaselJS 不会在下一个 mousedown 事件之前调用我们的函数。这正是我们在绘画逻辑中想要处理的。

在下面的屏幕截图,你可以看到这个应用的预览:

使用  函数

下载源代码

这个绘画示例是 EaselJS 的基本示例之一。你可以从 EaselJS 的 GitHub 下载项目的完整源代码:

github.com/CreateJS/EaselJS/blob/master/examples/CurveTo.html

摘要

在本章中,我们讨论了如何从头开始使用 mousemovemousedownmouseup 事件创建一个简单的绘画应用,这是理解这些事件概念的良好练习。然后,我们学习了如何管理内部鼠标事件以绘制线条。我们使用了 addEventListenerremoveEventListener 函数来添加和移除对象中的事件。

此外,我们还学习了如何使用 EaselJS 中的描边功能来绘制具有特定颜色和大小的线条。我们使用了beginStrokecurveTomoveTo函数来绘制线条并处理绘图逻辑。

在下一章中,我们将讨论矢量蒙版以及如何在 CreateJS 中创建蒙版层。

第八章:利用向量蒙版

在本章中,我们将讨论在 CreateJS 中使用向量蒙版以及如何使用向量蒙版开发动画或绘图。首先,我们应该了解什么是向量蒙版以及它做什么。使用向量蒙版,我们可以控制父层中哪些部分被隐藏或显示。我们甚至可以向向量蒙版添加特殊效果,使父层的那部分与其它部分不同。

在本章中,我们将介绍:

  • 学习向量蒙版

  • 将向量蒙版添加到现有的 DisplayObject 对象

  • 将向量蒙版应用于图片

  • 动画蒙版层

学习向量蒙版

向量蒙版是 EaselJS 中一个有用的功能,它允许开发者轻松地创建令人惊叹的动画或绘图。每个 DisplayObject 对象都有一个 mask 属性,您可以使用它来应用蒙版层,换句话说;在现有形状或图片上创建一个层。在应用蒙版层并更新 stage 事件后,您将看到新层覆盖了现有层。换句话说,您可以使用向量蒙版控制父层中隐藏或显示的部分。

学习向量蒙版

此外,蒙版层也是形状,因此您可以连续更改蒙版层的属性以创建动画。

这里是使用 EaselJS 中向量蒙版的示例:

/* Declare stage in usual way */
var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);

/* Create the mask */
var mask = new createjs.Shape();
mask.graphics.drawCircle(0, 0, 30);
mask.x = 100;
mask.y = 100;

var bg; /* Create a red background */
var bg = new createjs.Shape();
bg.graphics.clear().beginFill("red").rect(0, 0, 400, 200);

/* Add mask to background */
bg.mask = mask;

/* Add to stage */
stage.addChild(bg);

/* update stage in usual way */
stage.update();

与本书中的其他示例一样,我们首先从页面中获取 canvas 元素,然后创建 Stage 对象。然后,我们使用 Shape 类和 drawCircle 函数创建一个简单的圆形。对于默认位置,我们将 xy 都设置为 100。这个圆形是我们的向量蒙版层。

然后,我们创建一个 bg 变量,它包含一个填充红色的矩形。之后,我们将第一个形状(即圆形)分配给 bg 变量的 mask 属性。最后,我们将 bg 变量添加到舞台中。

这里是前面源代码的输出:

学习向量蒙版

为了更好地理解示例,请查看以下截图。这是移除蒙版层后的输出。

学习向量蒙版

如您在第一个示例中所见,我们的蒙版层仅在圆形形状中可见,但在下一个示例中,整个矩形都可见,因为没有蒙版层了。

以下截图显示了独立的蒙版层:

学习向量蒙版

在将蒙版层分配给父层(红色矩形)后,矩形唯一可见的部分将是蒙版层的可见部分。

在下一节中,我们将查看一个带有蒙版层的拖放示例。

使用位图图像的向量蒙版

在本节中,您将通过示例学习如何使用矢量蒙版、滤镜和Bitmap类。Bitmap类是DisplayObject的子集;因此,它几乎具有Shape类的所有属性,例如filtersmask等。

这里是一个使用Bitmap类与矢量蒙版的示例:

//query the canvas element
var canvas = document.getElementById("canvas");

//create the Stage class
var stage = new createjs.Stage(canvas);

//create the mask layer
var mask = new createjs.Shape();
mask.x = img.width / 2;
mask.y = img.height / 2;
mask.graphics.drawCircle(0, 0, 100);

var bg = new createjs.Bitmap(img);
//add blur filter
bg.filters = [new createjs.BlurFilter(50,50,10)];
bg.cache(0,0,img.width,img.height);
bg.mask = mask;
stage.addChild(bg);

stage.update();

在第一行,我们创建了指向页面上的canvas元素的canvas变量。然后,我们使用Stage类初始化了stage变量。

在下一行,我们使用Shape类初始化了一个mask变量。这个形状是我们的蒙版层,它是一个圆形。对于蒙版层的坐标,我们使用了img.width / 2img.height / 2将蒙版层放置在图片的中心。然后,我们使用drawCircle方法创建了圆形。

然后我们创建了bg变量,它指向我们的图像。我们使用Bitmap类初始化了这个变量;Bitmap类的第一个参数是Image类。我们已使用Image类加载了图像。

这里是一个加载图像并使用onload事件的示例:

var img = new Image();
img.src = "easlejs.png";

img.onload = function(evt) {
    //logic
}

注意

您可以使用相同的方法在 EaselJS 中加载图像并将它们传递给Bitmap类。

然后,我们在图片滤镜中添加了一个模糊滤镜,并使用cache方法缓存了形状。我们使用原始图像尺寸作为cache方法的参数。然后我们使用mask属性将蒙版层赋值给bg变量。

最后,我们将bg变量添加到stage事件中,并更新了这个事件以应用更改。

为了更好地理解差异,请查看以下没有mask属性的bg变量的输出截图。这是没有蒙版层的Bitmap类。

使用矢量蒙版与位图图像

下图显示了矢量蒙版单独的情况:

使用矢量蒙版与位图图像

下面的截图展示了带有蒙版层的最终示例结果:

使用矢量蒙版与位图图像

如您所见,第一张截图显示了整个图像。然而,第三张图中唯一可见的部分是我们的蒙版层,即圆形。这就是矢量蒙版与图片和形状一起工作的方式。您可以创建任何形状,并用这个形状蒙版一个现有的层,例如一个图片。

在下一个示例中,我们将创建一个使用矢量蒙版的拖放交互。

玩转矢量蒙版

现在,我们将完成之前的示例,使用矢量蒙版创建一个简单的拖放示例。想法是在父层的mousemove事件中更改蒙版层的 x 和 y 坐标,这样我们只能看到覆盖现有形状的蒙版层。看起来就像只有圆形形状被拖动,但实际上我们的蒙版层正在不断变化。我们示例的源代码如下:

var stage = new createjs.Stage("canvas");
var mask = new createjs.Shape();

mask.graphics.drawCircle(0, 0, 30);
mask.x = 100;
mask.y = 100;

var bg = new createjs.Shape();
bg.graphics.clear().beginFill("red").rect(0, 0, 400, 400);

bg.mask = mask;

function handlePress(event) {
    event.addEventListener("mousemove", handleMove);
}

function handleMove(event) {
    mask.x = stage.mouseX;
    mask.y = stage.mouseY;
    stage.update();
}

bg.addEventListener("mousedown", handlePress);

stage.addChild(bg);
stage.update();

如前一个示例所示,我们在第一行创建了一个圆形的遮罩层。我们使用 x=100y=100 指定了遮罩层的默认坐标。然后,我们创建了一个 bg 变量,它包含背景或父层。

因为我们需要遮罩层的坐标随着鼠标光标的移动而连续变化,所以我们为 mousedownmousemove 事件绑定了回调函数。然后,在 mousemove 回调函数内部,我们改变了遮罩层的坐标并更新了舞台。

结果看起来像是在舞台上拖放的一个球,但实际上,是随着鼠标的每一次移动而不断变化的遮罩层。

玩转矢量遮罩

摘要

矢量遮罩功能是绘制和开发动画中最有用的功能之一,不仅限于 CreateJS,还适用于所有其他工具。在本章中,我们学习了如何在 EaselJS 中创建矢量遮罩层,以及如何增强它们来创建动画。当您需要将不同的过滤器应用于现有形状或图片的特定部分时,这个功能也非常有用。

在下一章中,我们将总结所有内容,从头开始使用我们已讨论过的所有 CreateJS 功能来创建一个完整的 UI。

第九章:开发您的第一个 CreateJS 应用程序

在我们之前的章节中,您学习了构建令人印象深刻的 Web 应用程序所需的所有关于 CreateJS 的知识。在本章中,我们将总结所有内容,并学习从头开始使用 CreateJS 构建实际应用程序。我们将开发一个简单的绘画应用程序,具有更改背景颜色、画笔颜色、画笔样式、画笔大小等功能。此外,您还将了解有助于您开发更好的 JavaScript 库和应用程序的技巧和提示。

在本章中,我们将涵盖以下主题:

  • 构想应用程序

  • 解释应用程序的结构

  • 实现应用程序的每个部分

  • Canvas 元素导出图像

理解您的应用程序结构

为了演示使用 CreateJS 的应用程序开发,我们将构建一个绘画应用程序。在这个应用程序中,我们将使用 EaselJS 模块和一些纯 JavaScript 片段来从 Canvas 元素导出图像。正如您所知,EaselJS 将所有输出渲染到 Canvas 元素中;有一些 JavaScript 函数可以从 Canvas 元素获取图像输出。

此应用程序包含三个文件:

  • index.html

  • app.js

  • style.css

index.html 文件中,我们创建 HTML 元素并将外部文件链接到它。app.js 是包含几乎所有运行应用程序的 JavaScript 代码的主要 JavaScript 文件,而 style.css 用于设置页面、下拉菜单和其他小元素的风格。

理解您的应用程序结构

我们将依赖项拆分到不同的文件中,以便更好地管理它们,并在加载应用程序时提供更好的性能。外部静态文件将在浏览器中缓存,因此用户在刷新页面时不需要重新下载它们。

我们的绘画应用程序主要使用 EaselJS 功能,例如 curveTobeginStroke 函数。为了控制应用程序的全局设置,如背景颜色和画笔颜色,我们使用了全局变量来保存这些设置。我们将在其他事件或函数中使用它们。当用户点击页面上的不同选项和菜单时,这些变量会发生变化。

应用程序界面的预览如下:

理解您的应用程序结构

应用程序有一个由四个下拉菜单和一个标题组成的导航栏。用户可以通过下拉菜单更改画笔样式、画笔大小、背景颜色和画笔颜色。此外,还有一个 导出 链接,它将 Canvas 元素转换为 PNG 图像,并为用户提供下载链接,用户可以从该链接下载图像。

我们的下拉菜单使用纯 CSS 代码,因此我们不需要为它们编写任何 JavaScript 代码。在下一节中,我们将详细解释每个部分。

开发 index.html 文件

我们的主 HTML 页面有一个简单的结构。以下是一个 HTML 页面的 head 标签:

<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="content-type" content="text/html; charset=UTF-8">
   <title>Painting</title>
   <link rel="stylesheet" type="text/css" href="style.css">
</head>

head 标签中,我们只链接 CSS 文件到页面。其他 JavaScript 文件将在文件末尾连接到页面,原因是提供更好的页面加载性能。当我们向 head 标签添加样式表,并在 HTML 文件末尾(在关闭 body 标签之前)添加 JavaScript 文件时,我们的页面界面看起来会更快,因为浏览器不会等待加载所有 JavaScript 和 CSS 文件。浏览器加载 CSS 文件,因为它们在 head 标签中,在渲染所有 HTML 元素之后,它加载 JavaScript 文件。这个技巧给用户带来了更好的应用程序性能感。

在以下行中,我们有 bodywrapper 元素:

<body>
   <div id="wrapper">
       <div id="header">
           <h1>Painting</h1>

wrapper 层是所有其他元素的容器。此外,div 标题是页面顶部黑色标题的容器,正如在输出屏幕上所见。本节还包含下拉菜单和导出链接。

选择画笔颜色的下拉菜单的源代码如下:

<div id="colorPicker" class="pickerDropDown">
   <span class="hex">Brush color</span>
   <span class="fill" style="background-color: #004358;"></span>
   <div class="sub">
       <ul>
           <li>
               <a href="javascript:void(0);" class="sphexbrushColor" style="background: #FD7400;">
                  #FD7400
               </a>
           </li>
           <li>
               <a href="javascript:void(0);" class="sphexbrushColor" style="background: #FFE11A;">
                   #FFE11A
               </a>
           </li>
           <li>
               <a href="javascript:void(0);" class="sphexbrushColor" style="background: #BEDB39;">
                   #BEDB39
               </a>
           </li>
           <li>
               <a href="javascript:void(0);" class="sphexbrushColor" style="background: #1F8A70;">
                   #1F8A70
               </a>
           </li>
           <li>
               <a href="javascript:void(0);" class="sphexbrushColor" style="background: #004358;">
                   #004358
               </a>
           </li>
       </ul>
   </div>
</div>

每个下拉菜单都有一个具有子类的 div 元素。在 div 元素内部,我们有 ulli 元素,它们定义了下拉菜单。对于颜色选择器,有一个显示当前颜色的圆形。其他下拉菜单具有相同的结构。在下拉菜单之后,我们有一个导出图像的链接。

相同的源代码如下:

<div id="exportToImage" class="pickerDropDown">
   <span class="hex">
       <a href="javascript:void(0)" onclick="exportToImage(this);">Export</a>
   </span>
</div>

如您所见,当用户点击 Export 链接时,会调用一个函数。我们调用 exportToImage 函数,该函数将 Canvas 元素转换为 PNG 图像。

注意

我们将在下一节中更好地解释这个函数。

最后,我们有 Canvas 元素的定义:

<div id="main">
   <canvas id="pStage"></canvas>
</div>

canvas id 对象被分配了 pStage 的值,并被放置在一个 div 元素内部。之后,我们链接了两个 JavaScript 文件。第一个文件是包含所有子集的 CreateJS 库的合并文件,第二个是 app.js 文件,如下所示:

<script type='text/javascript' src="img/createjs-2013.12.12.min.js"></script>
<script type='text/javascript' src="img/app.js"></script>

我们使用 CreateJS CDN 服务器来加载主库文件。此文件已经压缩,我们可以在生产环境中使用它。

实现 app.js 文件

app.js 文件是包含绘画应用程序所有功能和逻辑的主要 JavaScript 文件。该文件由五个函数组成;其中一个是主函数,它执行其他事件的设置、配置和创建舞台。接下来的三个函数是不同鼠标事件的回调函数,最后一个函数用于从 Canvas 元素创建 PNG 图像。但在所有其他事情之前,我们有全局变量的声明,如下所示:

var canvas, stage, drawingCanvas, oldPt, oldMidPt, bgLayer, brushColor, brushSize, bgColor, brushStyle, mouseMoveFn;

注意

我们将在下一节中详细解释每个变量的用法。

之后,我们有 init 函数,它是应用程序的主要函数。

 canvas = document.getElementById("pStage");

 canvas.width = window.innerWidth;
 canvas.height = window.innerHeight - 73;

 //set default colors
 brushColor = "#004358";
 bgColor = "#FCFFF5";
 brushSize = 12;
 brushStyle = "round";

在第一行,我们使用 getElementById 函数获取 Canvas 元素。然后我们将 Canvas 元素的宽度和高度设置为窗口的宽度和高度,以便将画布适应到页面。我们使用 -73 作为 innerHeight 值的原因是防止页面垂直滚动,因为我们的页眉高度大约是 73 像素。之后,我们设置默认选项。您可以根据需要更改它们。

为了将 onclick 事件绑定到下拉菜单中,我们有一个简单的 for 循环,遍历 ul 项目并将 onclick 事件绑定到链接上:

 //bind onclick event to the brush color picker
 for (var i = document.getElementsByClassName("brushColor").length - 1; i>= 0; i--) {
    var item = document.getElementsByClassName("brushColor")[i];

    item.onclick = function () {
        brushColor = document.querySelector("#colorPicker .fill").style.backgroundColor = this.style.backgroundColor;
    }
 };

在第一行,我们有一个遍历下拉项的 for 循环,然后为每个项绑定一个 onclick 事件。相同的代码也用于其他下拉菜单。最后,我们使用以下代码结束文件:

 stage = new createjs.Stage(canvas);
 stage.autoClear = false;

 createjs.Touch.enable(stage);

 stage.on("stagemousedown", mouseDownCallback);
 stage.on("stagemouseup", mouseUpCallback);

 bgLayer = new createjs.Shape();
 bgLayer.graphics.beginFill(bgColor).drawRect(0, 0, canvas.width, canvas.height);
 stage.addChild(bgLayer);

 drawingCanvas = new createjs.Shape();
 stage.addChild(drawingCanvas);
 stage.update();

在第一行,就像我们之前的例子一样,Stage 是创建的对象。之后,我们将 autoClear 属性设置为 false 以便手动管理 stage 对象的清除。然后,我们设置 touch 功能为 enable

我们正在开发一个绘画应用程序,因此我们需要将回调函数绑定到 mousedownmouseupmousemove 事件,以便管理和控制鼠标事件。在接下来的几行中,我们将回调函数绑定到 stagemousedownstagemouseup 事件,这些事件用于处理鼠标点击事件。

注意

在绘画应用程序中,我们有一个背景层,用户可以使用下拉菜单更改颜色。

在接下来的几行中,我们创建了一个用于背景层的 Shape 对象,然后我们创建了下一个形状来绘制绘画线条。这两个形状都通过 addChild 函数添加到舞台中。

mouseDownCallback 事件的源代码如下所示:

oldMidPt = oldPt = new createjs.Point(stage.mouseX, stage.mouseY);
mouseMoveFn = stage.on("stagemousemove", mouseMoveCallback);

在这个函数内部,我们收集当前鼠标光标的坐标,并添加一个回调函数到 stagemousemove 事件。

mouseMoveCallback 函数的源代码如下所示:

Var midPt = new createjs.Point(Math.floor((oldPt.x + stage.mouseX) / 2), Math.floor((oldPt.y + stage.mouseY) / 2));

drawingCanvas.graphics.setStrokeStyle(brushSize, brushStyle).beginStroke(brushColor).moveTo(midPt.x, midPt.y).curveTo(oldPt.x, oldPt.y, oldMidPt.x, oldMidPt.y);

oldPt.x = stage.mouseX;
oldPt.y = stage.mouseY;

oldMidPt.x = midPt.x;
oldMidPt.y = midPt.y;

stage.update();

在第一行,我们使用当前鼠标位置和旧鼠标位置计算下一个 moveTo 函数所需的点。在下一行,我们使用当前选项创建一个描边,并将点移动到我们在第一行计算的新坐标。之后,更新旧位置,最后从 stage 对象调用 update 函数。

我们的事件最后回调函数是 mouseUpCallback 函数。在这个函数内部,我们取消绑定 stagemousemove 回调函数以停止绘制,如下所示:

stage.off("stagemousemove", mouseMoveFn);

最后一个函数是exportToImage函数,它用于从Canvas元素获取导出的 PNG 图像。在这个函数中,我们将Canvas元素转换为以 64 位为基础的 PNG 图像格式,并将输出设置到链接的href对象中。有一个名为toDataUrl的函数,它将Canvas元素的内容转换为图像。当用户点击导出链接时,会调用exportToImage函数。以下代码解释了相同的内容:

var dateTime = new Date();

obj.href = canvas.toDataURL();
obj.download = "paint_" + dateTime.getHours() + "-" + dateTime.getMinutes() + "-" + dateTime.getSeconds();

在文件末尾,我们调用init函数来启动应用:

init();

最终应用的预览

一旦代码运行,我们的绘画应用就准备好使用了。以下截图展示了我们最终应用的预览:

最终应用的预览

摘要

在本章中,我们学习了如何从头开始使用 CreateJS 创建实际的 Web 应用,并使用这个库提供的不同功能。我们获得了如何声明全局选项以及如何通过用户输入来更改它们并在应用中应用这些更改的经验。此外,我们还学习了如何使用强大的 JavaScript API 从Canvas元素导出图像。

此外,我们还讨论了如何包含静态文件,如 JavaScript 和 CSS,以在加载应用时提供更好的性能。

每一个新的开始都是某个结束的开始,当你翻到这本直观指南的最后一页时,你将获得探索、发现、发展和构建令人惊叹的 Web 应用的能力,使用 CreateJS。在这个网络公民的时代,HTML5 已经崛起为一个强大的平台,你可以通过引人入胜的 Web 应用留下自己的印记。所以,大胆地去做吧,创造下一个惊人的 Web 应用,让世界为之振奋!

posted @ 2025-09-26 22:07  绝不原创的飞龙  阅读(19)  评论(0)    收藏  举报