文档结构  
翻译进度:已翻译     翻译赏金:0 元     ¥ 我要打赏

HTML5是现代 Web 的骨干。 现在,当涉及到创建交互式图像时,SVG和Canvas通常是最佳的技术 - Flash已经被遗忘,Silverlight也像一只罕见的独角兽一般游离在网络的边缘,很少有人记得第三方插件。

Canvas和SVG的优点和缺点在本文中详细地论述,但简而言之,SVG更适合创建和处理交互式元素。 这是因为SVG是基于XML的向量格式,当使用<svg>标记将图像加载到页面中时,其中的每个元素在SVG DOM中可用。

第 1 段(可获 1.34 积分)

在本文中,我想向您介绍GraphicsJS,一个新的强大的开源JavaScript绘图库,它基于SVG(对于旧的IE版本使用 VML 回退)。 我将首先简要介绍其基础知识,然后通过两个简短而又精彩的示例来展示该库的功能:第一个是关于艺术,第二个说明如何使用不到50行代码编写一个简单的时间 - 杀手艺术游戏。

为什么是GraphicsJS

有很多可以帮助开发人员使用SVG的库:如RaphaëlSnap.svgBonsaiJS,这里只列出一些最好的。 每一个都有自己的优点和缺点,但他们的详细比较将是另一篇文章的主题。 这篇文章是关于GraphicsJS的,所以让我解释一下它为什么好以及它的特别之处。

第 2 段(可获 1.85 积分)

GraphicsJS, a lightweight and powerful SVG-based JavaScript graphics library by AnyChart

首先,GraphicsJS是轻量级的,并有一个非常灵活的JavaScript API。 它实现了许多富文本功能,以及一个虚拟DOM - 并从浏览器特定的HTML DOM实现中分离出来。

其次,它是一个新的开源JavaScript库,由交互式数据可视化领域全球领先的软件开发商之一 AnyChart 在去年秋天发布。 AnyChart已经使用GraphicsJS在其专有产品中呈现图表至少三年(自AnyChart 7.0发布以来)了,因此GraphicsJS已经完全经过测试。 (免责声明,我是AnyChart的研发主管和GraphicsJS的主要开发人员)

第 3 段(可获 1.4 积分)

第三,与AnyChart的JavaScript图表库不同,GraphicsJS可以同时在商业和非盈利项目中免费使用。 它在GitHub上并遵循Apache许可证。

第四,GraphicsJS是跨浏览器兼容的,支持Internet Explorer 6.0+,Safari 3.0+,Firefox 3.0+和Opera 9.5+。 它在旧版本的IE中渲染为VML,在所有其他浏览器中渲染为SVG。

最后,GraphicsJS允许你结合图形和动画效果。 查看它的主页的主要示例,其中包括一个动画的篝火旋转的星系下雨由程序生成的叶子可以玩的15数字推盘游戏和更多示例。 GraphicsJS在其详细的文档和其全面的API参考中包含许多其他示例。

第 4 段(可获 1.39 积分)

GraphicsJS基础

开始之前你需要引用 GraphicsJS 库并为你的图形创建一个块级HTML元素:

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>GraphicsJS Basic Example</title>    
  </head>
  <body>
    <div id="stage-container" style="width: 400px; height: 375px;"></div>

    <script src="https://cdn.anychart.com/js/latest/graphics.min.js"></script>
    <script>
      // GraphicsJS code here
    </script>
  </body>
</html>

然后,你应该创建一个stage并在其中绘制一些图形,如矩形圆形或其他形状

第 5 段(可获 0.51 积分)
// create a stage
var stage = acgraph.create('stage-container');
// draw a rectangle
var stage.rect(25, 50, 350, 300);

这是CodePen上的一个例子,我们更进一步,绘制了死亡圣器符号。

我们的第一个杰作

填充,描边和图案填充

任何形状或路径都可以使用填充设置笔画设置进行着色。 一切图形都有笔画(边框),但只有形状和封闭的路径有填充。 填充和笔画设置非常丰富,你甚至可以为填充和笔画应用直线或圆形渐变。 此外,线可以是虚线,并支持几种平铺模式的图像填充。 但所有这些都是标准化的东西,你可以在几乎任何一个库中找到。 GraphicsJS的特别之处在于它的填充(hatch)和图案(pattern)填充功能,使您不仅可以使用32(!)种填充图案中的任意一种,还可以使用形状或文本轻松创建自己的图案。

第 6 段(可获 1.89 积分)

现在,让我们看看可能发生什么! 我会画一张一个人站在房子附近的小图片,然后填充不同的图案和颜色增强它。 简单起见,让我们把它做成一个素人艺术图片(以及不尝试进入非主流艺术)。 方案如下:

// 创建一个stage
var stage = acgraph.create('stage-container');

// 画一个边框
var frame = stage.rect(25, 50, 350, 300);

// 画一个房子
var walls = stage.rect(50, 250, 200, 100);
var roof  = stage.path()
  .moveTo(50, 250)
  .lineTo(150, 180)
  .lineTo(250, 250)
  .close();

// 画一个人
var head = stage.circle(330, 280, 10);
var neck = stage.path().moveTo(330, 290).lineTo(330, 300);
var kilt = stage.triangleUp(330, 320, 20);
var rightLeg = stage.path().moveTo(320, 330).lineTo(320, 340);
var leftLeg = stage.path().moveTo(340, 330).lineTo(340, 340);
第 7 段(可获 0.69 积分)

查看CodePen上的结果

正如你所看到的,我们现在使用变量 - 所有在stage上绘制图形的方法都返回对所创建的对象的引用,这个引用可以用来修改或删除对象。

还要注意,在GraphicsJS中无处不在的链盒如何帮助缩短代码。 链盒(例如stage.path().moveTo(320, 330).lineTo(320, 340);)应该谨慎使用它们,但如果正确应用的话,它确实能使代码紧凑,并且更容易阅读。

现在,让我们把这个着色页给一个孩子,让他们给它上色。因为即使是孩子也能掌握以下技巧:

第 8 段(可获 1.25 积分)
// 给图片上色
// 漂亮的边框
frame.stroke(["red", "green", "blue"], 2, "2 2 2");
// 砖墙
walls.fill(acgraph.hatchFill('horizontalbrick'));
// 稻草屋顶
roof.fill("#e4d96f");
// 格子短裙
kilt.fill(acgraph.hatchFill('plaid'));

我们的例子看起来像现在这样。

现在我们得到了一张图片,图片中有一个穿着苏格兰短裙的高地人,他站在一座有着稻草屋顶的砖砌城堡附近。 我们甚至可以冒险说它确实是我们想要版权的一件艺术 品。 让我们使用自定义的基于文本的图案填充:

// 169是版权符号的字符代码
var  text = acgraph.text().text(String.fromCharCode(169)).opacity(0.2);
var  pattern_font = stage.pattern(text.getBounds());
pattern_font.addChild(text);
// 使用版权图案填充整个图片
frame.fill(pattern_font);
第 9 段(可获 0.78 积分)

如你所见,这是很容易做到的:你创建一个文本对象的实例,然后在stage中创建一个图案(pattern),并将一个文本对象放入图案(pattern)中。

参见CodePen上由SitePoint(@SitePoint)使用graphicsjs创建的有颜色和版权信息的房子。

在不到50行的代码中创建一个时间杀手艺术游戏

在本文的下一部分,我想向你展示如何使用GraphicsJS在不到50行的代码中创建一个饼干大师类型的游戏。

游戏的名称是“风中的街道清道夫”,玩家扮演一个在多风的秋日下午清扫街道的清道夫的角色。 游戏使用了一些GraphicsJS库中生成叶子示例的代码。

第 10 段(可获 1.61 积分)

你可以在CodePen上查看完成的游戏(或在文章的结尾)。

层(layer),层的z轴位置(zindex)和虚拟DOM

我们首先创建一个stage(如前所述),然后声明一些初始变量:

// 创建stage
var stage = acgraph.create("stage-container");

// 为树叶上色准备调色板
var palette_fill = ['#5f8c3f', '#cb9226', '#515523', '#f2ad33', '#8b0f01']; 
var palette_stroke = ['#43622c', '#8e661b', '#393b19', '#a97924', '#610b01'];

// 计数器
var leavesCounter = 0;

对于这个游戏,我们将使用 Layer - 一个对象用于在GraphicsJS中分组元素。 如果要对它们应用类似的更改(如转换),则必须对元素进行分组。 你可以在处于暂停模式时更改图层(稍后详细介绍),这可以提高性能和用户体验。

第 11 段(可获 1.13 积分)

在这个演示中,我们使用图层功能来帮助我们将树叶分组在一起,并避免它们覆盖标签(该标签告诉我们扫了多少叶子)。 为此,我们创建一个标签,然后调用stage.layer方法,创建stage绑定层。 我们为此图层分配比标签层低的zIndex属性。

// 创建一个标签来计数叶子
var counterLabel = stage.text(10,10, "Swiped: 0", {fontSize: 20});

// 用于显示叶子的图层
var gameLayer = stage.layer().zIndex(counterLabel.zIndex()-1);

在这之后,无论我们在图层中创建了多少叶子,我们可以确保他们不会覆盖文本。

第 12 段(可获 1 积分)

转换

接下来,让我们添加一个函数来绘制我们的叶子。 我们将使用方便的GraphicsJS转换API,允许你移动,缩放,旋转和剪切元素和元素组。 当与图层和虚拟DOM结合使用时,这是一个非常强大的工具。

function drawLeaf(x, y) {
  // 从调色板中选择随机颜色
  var index = Math.floor(Math.random() * 5);
  var fill = palette_fill[index];
  var stroke = palette_stroke[index];

  // 生成随机比例因子和旋转角度
  var scale = Math.round(Math.random() * 30) / 10 + 1;
  var angle = Math.round(Math.random() * 360 * 100) / 100;

  // 创建一个新的(叶子)路径
  var path = acgraph.path();

  // 画一片叶子并上色
  path.fill(fill).stroke(stroke, 1, 'none', 'round', 'round');
  var size = 18;
  path.moveTo(x, y)
    .curveTo(x + size / 2, y - size / 2, x + 3 * size / 4, y + size / 4, x + size, y)
    .curveTo(x + 3 * size / 4, y + size / 3, x + size / 3, y + size / 3, x, y);

  // 应用随机变换
  path.scale(scale, scale, x, y).rotate(angle, x, y);

  return path; 
};
第 13 段(可获 0.65 积分)

你会发现每个路径都以相同的方式被创建,然后被转换。 这会产生非常好的随机叶子图案。

处理事件

GraphicsJS中的任何对象,stage和图层都可以处理事件。 可以在 EventType API 中查看支持的事件的完整列表。 stage有四个特殊事件来控制渲染。

在这个游戏示例中,我们使用附加到叶子对象的事件侦听器,以便当用户将鼠标悬停在其上时,它们会逐个消失。 为此,将以下代码添加到drawLeaves函数的底部并放在return语句之前:

第 14 段(可获 1.23 积分)
path.listen("mouseover", function(){
  path.remove();
  counterLabel.text("Swiped: " + leavesCounter++);
  if (gameLayer.numChildren() < 200) shakeTree(300); 
});

这里我们使用了层来统计树叶的数量。

if (gameLayer.numChildren() < 200) shakeTree(300); 

请注意这里我们实际上并没有存储树叶的数量。树叶是我们从特定的层中添加和删除的路径,这使得我们可以跟踪有多少个子路径(以及留下多少)。

GraphicsJS 提供了一个 虚拟的 DOM,这是对 HTML DOM 的抽象,是一个轻量级的,与特定浏览器的 SVG/VML 实现分离的。这用在诸如大量对象和层的跟踪、组变换以及优化渲染的时候非常有用,其提供的很多方法可以让我们跟踪并控制渲染的过程。

第 15 段(可获 1.45 积分)

性能优化

虚拟的 DOM 以及事件处理程序允许 GraphicsJS 的开发者去控制渲染的过程。这篇 性能 文章会给你这方面相关问题的一些思路。

当我们在游戏中生成树叶时,我们需要暂停渲染,同时增加新的叶子,并在所有变化都完成之后进行恢复:

function shakeTree(n){
  stage.suspend(); // suspend rendering
  for (var i = 0; i < n; i++) {
    var x = Math.random() * stage.width()/2 + 50;
    var y = Math.random() * stage.height()/2 + 50;
    gameLayer.addChild(drawLeaf(x, y)); // add a leaf
  }

  stage.resume(); // resume rendering
}
第 16 段(可获 0.68 积分)

这种处理新元素的方式可以让新生成的树叶立即显示。

最后调用 shakeTree() 让所有树叶都掉落。

// shake a tree for the first time
shakeTree(500);

最终结果

查看 SitePoint 在 CodePen 上提供的代码演示 street sweeper in the wind / graphicsjs

结论

HTML5 让 Web 发生很大的变化。当它开始在最新的 Web 应用甚至是一个简单网址上应用时,我们经常会需要进行图像处理的任务。你可以考虑使用 GraphicsJS 库,虽然它不可能在任何情况下都能解决你遇见的问题。GraphicsJS 是一个开源的、可靠的,对各种浏览器广泛支持的 JavaScript 库,提供很丰富的功能使得它变得很有趣、方便,当然最重要的是有用。

第 17 段(可获 1.34 积分)

我很乐意在下面的评论中听到你对GrphicsJS的反馈。 你已经使用它了吗? 你会考虑把它用于一个新的项目吗? 我很愿意听到为什么会,或者为什么不会。 目前我正工作于一系列主要的JavaScript绘图库并写了一篇文章,比较和对比他们。 你也可以在那里随时指出你想了解的库。

延伸阅读的链接

第 18 段(可获 1.3 积分)

文章评论