paths js_如何使用Paths.js创建基于模板的高性能图表

paths js

在最近一篇文章中,我们讨论了浏览器中数据可视化的最新状态,尤其是SVG库。 在那里,我们专注于Snap.svg ,但我们引入了Paths.js作为可行的替代方案-与模板引擎或数据绑定库一起使用。 公平地说,正如我们将在以下各节中展示的那样,Paths还具有更多功能,并带有实际用例来指导您了解其逻辑。

介绍

Paths的主要目的是通过直观的界面帮助前端开发人员生成具有更好性能的SVG路径。 顾名思义,尽管具有诸如rectcircle类的图元,但所有内容都可以简化为路径。 这种方法统一了不同的图表,提供了一个一致的界面,在该界面上,绘制命令始终返回准备绘制的路径列表。 通过用数据绑定库(例如Ractive.jsAngularReact )替换静态模板引擎(例如Mustache或Handlebars),您甚至可以免费获得动画图形。

关于Paths.js最好的事情可能是它提供了三个增量API,并且抽象级别不断提高。 最低级别是可链接的API,可生成任意SVG路径。 除此之外,还定义了简单几何形状(例如多边形或圆形扇区)的路径。 最高级别的API允许生成一些简单的图形,这些图形可以与数据集合一起提供。 (查看此演示以查看可用的原语。)

实际上,请注意:路径的最佳功能是您可以使用Node.js在服务器端一样使用该库,因为它不直接依赖任何库1 。 这样,您可以将图表结构和详细信息的生成移到服务器上。 除了加速应用程序外,您还可以避免将原始数据完全发送到客户端,从而节省了延迟并减少了与客户端共享的信息量。

为什么选择路径?

使用Paths.js而不是D3或Snap.svg的最大优点是后者是必须的,而当与模板引擎或(甚至更好的)数据绑定框架配对使用时,Paths固有地支持声明式编程。

在像Ractive或React这样的框架中使用Paths又会带来另一个优势。 实际上,这些框架使用特定的优化来减少每次需要修改DOM时所需的重排和重绘次数。 他们保留DOM的“影子”副本,以某种“批处理模式”对其执行更新,并最终以最少的更改次数更新真实的DOM。

这些框架与众不同的另一个领域是事件处理。 默认情况下,它们使用事件委托,在将相同事件附加到一系列元素的情况下提高性能。 解决方案只是将这些事件处理程序附加到元素的某个通用容器上,但是当使用命令式方法时(这会带来可怕的后果,例如无响应的页面),却很容易忽略这种模式。

最后,Paths是轻量级的和模块化的:您可以仅加载实际需要的组件,专注于图表,也可以加载SVG。 路径是那些专注于某些事物并试图对其进行优化的库之一。 通常,您可以将许多此类库组合在一起以执行复杂的任务。 另一方面,D3有许多额外的实用程序方法-如果您需要它们,这很好,因为您将所需的一切都集中在一个地方,但如果不需要,则有点繁重。

使用路径

如前所述,您可以在Node.js或浏览器中使用路径。 在后一种情况下,您可以将其作为AMD模块或独立库进行加载。

节点上的路径

如果要在服务器上使用它,请首先通过在控制台上键入以下命令来安装它(假设您已正确安装了节点,并且该节点位于全局路径中):

npm install paths-js

安装后,您可以加载各个模块:

var Pie = require('paths-js/pie');

浏览器上的路径:AMD模块

Paths.js与Bower一起分发,您可以从命令行安装它:

bower install paths-js

或者,当然,只需从GitHub上的存储库手动下载它。

路径被构造为各种AMD模块,并且可以与AMD模块装载程序一起装载。 使用RequireJS (假设您已使用Bower安装了Paths),这是如何配置它的方法:

require.config({
  'paths': 'components/paths-js/dist/amd'
});

实际路径将取决于Bower配置,或者对于手动下载,取决于文件夹的结构。 (请注意放置上面链接的amd文件夹的位置。)

正确配置后,您可以轻松地需要各个模块:

var Pie = require('paths/pie');

浏览器上的路径:独立脚本

如果您不想使用AMD模块,则可以安全地将Paths作为独立脚本包括在内:所需文件为dist/global/paths.js 。 一旦将其包含在页面中, paths对象将在全局范围内可用,因此各个模块将分别用作paths.Piepaths.Polygon等。 除了冗长之外,您还失去了仅导入所需模块的能力–但是,如果需要其中许多模块,则其影响可忽略不计。

低级API

免费学习PHP!

全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。

原价$ 11.95 您的完全免费

如上所述,最低级别的API目标是创建路径。 创建目标就像调用一个构造函数Path()一样容易。 整个API都是可链接的,因此您可以通过根据先前调用的结果调用方法来创建复杂的路径。 Path对象提供了逐步扩展当前路径的方法。 保留对路径中最后一个点的引用,并且可以从该点添加直线或曲线,从而模仿路径的SVG语法。 您将需要的主要方法是:

  1. moveto(x, y) :将光标移动到传递的坐标。
  2. lineto(x, y) :绘制一条从路径末端到这些坐标的线。
  3. curveto(x1, y1, x2, y2, x, y) :以当前点到(x,y)绘制三次贝塞尔曲线,使用(x1,y1)作为曲线起点处的控制点,并且(x2, y2)作为曲线末端的控制点。
  4. smoothcurveto(x2, y2, x, y) :绘制从当前点到(x,y)的三次贝塞尔曲线,根据第二个和上一个命令(如果有)隐式计算第一个控制点。
  5. arc('rx', 'ry', 'xrot', 'large_arc_flag', 'sweep_flag', 'x', 'y') :从当前点到(x,y)绘制一个椭圆弧,控制椭圆半径和通过其他参数旋转。
  6. closepath() :关闭路径,将其变成多边形。

所有可用的方法也都支持“冗长”的API,因此命名参数(以配置对象的形式)可以无缝地传递给每个参数。 例如,上面的moveto方法可以称为Paths().moveto({x: 10, y: 3})Paths().moveto(10, 3) 。 参数名称遵循SVG规范。

有更多可用的方法,并且通常与SVG Paths命令一一对应。 例如, qcurveto(x1, y1, x, y)smoothqcurveto(x, y)与二次曲线的curveto smoothcurveto类似。

通常,这与模板引擎一起使用会更好,但并非绝对必要。 您可以使用命令式的路径,如以下示例所示。 但是,这不是最佳实践:

<title>PathsJs test</title>
    <style type="text/css">
      .ocean {
        fill: blue;
      }
    </style>

    <svg width="640px" height="480px"><path id="testpath" class="ocean"></path></svg>

    <script type="text/javascript" src="lib/paths.js"></script>
var Path = require('paths/path');
var path = Path()
  .moveto(10, 20)
  .lineto(30, 50)
  .lineto(25, 28)
  .qcurveto(27, 30, 32, 27)
  .closepath();
document.getElementById("testpath").setAttribute("d", path.print());

Path对象的print()方法将构造的路径转换为相应的SVG数据字符串,就像它出现在path的d (数据)属性中一样。 一旦获得该值,就可以使用CSS选择器和getElementById / getElementsBy*方法在任何路径上手动设置适当的属性。

当然,使用模板引擎将极大地影响我们需要编写的样板代码的数量:

<svg width="640px" height="480px"><path d="{{ path.print() }}" fill="blue"></path></svg>

这样就无需手动为#testpath设置d属性,甚至无需为path元素分配ID。 是使用“路径”创建SVG图纸的最佳实践样式。

中级API

尽管功能强大,但实际上您几乎不需要低级API。 原因是Paths提供了一个基于API的API,具有更高的抽象级别,可让您使用直观的语法直接创建多边形和形状。

在查看示例之前,了解此API的工作原理非常重要。 我们已经说明了此库产生的所有内容都是一条路径。 实际上,每个中级API方法都会返回一个带有两个字段的对象:

{
  path: <path object="">
  centroid: [<x>, <y>]
}

path字段包含一个符合低级API的Path对象,因此可以扩展:可以照常使用其print()方法检索描述该路径的data属性的字符串。

相反, centroid场与生成的路径并不正式相关,但是,它仍然非常有用:根据经验,它被计算为图形中心的点,可用于例如定位形状的标签。

为了理解两个抽象级别之间的区别,我们将使用Polygon对象创建与上一节几乎相同的Polygon

<svg width="640px" height="480px"><path id="testpath" class="ocean"></path><path id="testpath2" class="ocean" transform="translate(100)"></path></svg>
var Polygon = require('paths/polygon');
var polygon2 = Polygon({
  points: [[10, 20], [30, 50], [25, 28], [32, 27]],
  closed: true
});
document.getElementById("testpath2").setAttribute("d", polygon2.path.print());

如果您测试此代码,您会发现两个形状乍一看非常相似。 不同之处在于,第一个使用低级API构建,其一侧用二次曲线而不是线段构建。 实际上,低级API的优点是允许您将不同类型的线以相同的形状混合。

对于中级API,没有这样一种方法可以让您方便地混合它们。 但是不要担心,什么也不会丢失:正如我们所说的,您始终可以编辑Polygon(...)返回的Path

<svg width="640px" height="480px"><path id="testpath" class="ocean"></path><path id="testpath2" class="ocean" transform="translate(100)"></path><path id="testpath3" class="ocean" transform="translate(50)"></path></svg>
var polygon3 = Polygon({
  points: [[10, 20], [30, 50], [25, 28]],
  closed: false
});
console.log(polygon3.path.print())
var polygon3Path = polygon3.path
              .qcurveto(27, 30, 32, 27)
              .closepath();
document.getElementById("testpath3").setAttribute("d", polygon3Path.print());

可用于第二级接口的对象的完整列表是:

  • 多边形 :关闭和打开的多边形。
  • 半规则多边形多边形的一种特殊情况:允许创建三角形,正方形,五边形等(规则多边形及其不规则变体)。 它是相对于中心定义的,并且从中心到点的线段之间的角度都相同,而这些点的距离可以是恒定的(规则多边形),也可以是变化的(不规则多边形)。
  • 矩形 :另一种特殊类型的多边形,尽管这次更直观。
  • 贝塞尔曲线:绘制一条平滑的贝塞尔曲线,穿过一系列顶点。 返回的路径始终是开放的。
  • 部门 :循环部门。
  • 连接器 :定义为两个给定点之间的S形路径。 (了解它的最佳方法是尝试一下。)

几个示例可以更好地显示半正多边形:

半正多边形

三角形(等边)

var SemiRegularPolygon = require('paths/semi-regular-polygon');
var triangle = SemiRegularPolygon({
  center: [50, 50],
  radii: [20, 20, 20]
});
document.getElementById("triangle").setAttribute("d", triangle.path.print());

三角形(等腰)

var triangleIrregular = SemiRegularPolygon({
  center: [50, 50],
  radii: [20, 30, 30]
});

广场

var square = SemiRegularPolygon({
  center: [50, 50],
  radii: [20, 20, 20, 20]
});

五角大楼

var pentagon = SemiRegularPolygon({
  center: [50, 50],
  radii: [20, 20, 20, 20, 20]
});

五角大楼(不规则)

var pentagonIrregular = SemiRegularPolygon({
  center: [50, 50],
  radii: [25, 20, 40, 30, 20]
});

高级API

这是Paths提供的最高级别的API。 其方法的目的是允许创建从要可视化的数据集开始的完整图表。 一如既往,一切都转化为道路! 特别是,所有这些方法都将返回一个对象,其中包含一个curves字段,一个具有为每个数据点创建的形状的数组。 curves中的形状是具有一些相关字段的对象:

  • item :对相应数据项的引用。
  • index :数据数组中相应数据项的索引。
  • 一个或多个包含形状对象的字段(例如sector用于饼图, linearea用于折线图)。

根据每个图表,返回的对象除curves外可能还有其他字段。 但是每个图表方法都在输入中接受一个compute参数。 该参数允许用户传入许多函数,以根据输入数据计算额外的字段。 (计算颜色将是一个典型示例。)

使用这些高级方法时,模板引擎几乎是必需的,因为它们为开发人员节省了大量样板代码。 它们还通过自动执行复杂图表形状集上的迭代来简化图表创建。

但是,与往常一样,并非严格需要它们。 让我们看一个没有它们怎么做的例子:

<svg id="chart-test" width="200px" height="200px"></svg>
var somePalette = ['blue', 'green', 'red', 'yellow', 'orange'],
    Pie = require('paths/pie'),
    pie = Pie({
      data: [
        { name: 'Italy', population: 59859996 },
        { name: 'Mexico', population: 118395054 },
        { name: 'France', population: 65806000 },
        { name: 'Argentina', population: 40117096 },
        { name: 'Japan', population: 127290000 }
      ],
      accessor: function(x) { return x.population; },
      compute: {
        color: function(i) { return somePalette[i]; }
      },
      center: [50, 50],
      r: 30,
      R: 50
    }),
    chartSvg = document.getElementById("chart-test"),
    chartFragment = document.createDocumentFragment(),
    dx = parseInt(chartSvg.getAttribute('width'), 10) / 2,
    dy = parseInt(chartSvg.getAttribute('height'), 10) / 2;

pie.curves.forEach(function (d, i){
  var path = document.createElementNS('http://www.w3.org/2000/svg',"path");
  path.setAttributeNS(null, 'd', d.sector.path.print());
  path.setAttributeNS(null, 'style', 'fill:' + d.color);
  var label = document.createElementNS('http://www.w3.org/2000/svg',"text");
  label.textContent = d.item.name;
  label.setAttributeNS(null, 'x', d.sector.centroid[0]);
  label.setAttributeNS(null, 'y', d.sector.centroid[1]);

  chartFragment.appendChild(path);
  chartFragment.appendChild(label);
});

chartSvg.appendChild(chartFragment);

在上面的代码中,我们使用代码片段收集所有扇区,然后才将它们实际添加到页面中,因此仅触发一次重排,而不是每个扇区触发两次(对于路径一次,对于标签一次)。 文档片段元素可以一次性插入,而如果我们使用svg:g元素对它们进行分组,则每个节点将被单独插入。 (此外,结果SVG中可能会有多余的组。)文档片段的更大优势是,如果我们需要克隆整个图表并将其多次添加到页面中,则每个克隆操作都需要一个常量节点插入数,而不是线性数。

现在,让我们将之前的代码与使用Ractive创建与上述相同的图进行比较:

<div id="pie-chart"></div><script id="myChartTemplate" type="text/ractive">
  <svg width=375 height=400>
      {{# pie }}
        {{# curves:num }}
            <path on-click="expand" d="{{ sector.path.print() }}" fill="{{ color }}" ></path>
            <text text-anchor="middle" x="d.sector.centroid[0]" y="d.sector.centroid[1]">{{ item.name }}</text>
          </g>
        {{/ curves }}
      {{/ end of pie}}
  </svg>
</script>
var Pie = require('paths/pie');
  var ractive = new Ractive({
        el: 'pie-chart',
        template: '#myChartTemplate',
        data: {
          pie: Pie({
                    data: [
                      { name: 'Italy', population: 59859996 },
                      { name: 'Mexico', population: 118395054 },
                      { name: 'France', population: 65806000 },
                      { name: 'Argentina', population: 40117096 },
                      { name: 'Japan', population: 127290000 }
                    ],
                    accessor: function(x) { return x.population; },
                    compute: {
                      color: function(i) { return somePalette[i]; }
                    },
                    center: [50, 50],
                    r: 30,
                    R: 50
                  })
        }
      });

结果看起来更好,更干净,并且通过查看标记,图表的结构立即可见。

当前有9种不同类型的图表可用:

  • 饼形图
  • 条形图 :允许并排绘制多个直方图。
  • 股票图表 :用折线图表示一个或多个时间序列。
  • 平滑折线图 :类似于股票图表,但是它使用平滑的Bezier曲线对数据点之间的线进行插值。
  • 雷达图
  • 树形图
  • 瀑布图 :条形图,可细分数值。
  • 力定向图 :图形形式的物理模拟,除非顶点通过边连接,否则顶点彼此排斥。
  • Sankey图 :流程图,其中箭头与流量成比例。

您可以查看路径[showcase](http://andreaferretti.github.io/paths-js-demo/),以查看这些图表的外观。 此处展示的所有示例都利用Ractive轻松创建了很棒的动画。

结论

此时,您可能会问路径是否确实是您的正确选择。 当然,对此没有简单的答案。 这取决于。 如果您需要现成的窗口小部件和图表,可能不需要-使用HighchartsFlotchartsDimple可能会更好。

但是,我们不能足够强调在数据可视化中采用声明式编程的优势。 如果您必须使用Paths,则可能不值得花精力学习新的库。

在需要创建具有个性化样式或动画的自定义图表或响应用户交互的自定义​​行为的情况下,路径非常有用。 但是Paths是真正的游戏规则改变者,您需要在服务器上生成图形。 路径使您非常容易在逻辑中生成标记并将其作为JSON或字符串发送到客户端。

最后,这里有一些链接可供进一步阅读:


  1. Paths.js仅依赖于EcmaScript 5核心方法,这对于较旧的浏览器来说是一个问题。 该polyfill添加了必要的支持。

翻译自: https://www.sitepoint.com/create-performant-template-based-charts-paths-js/

paths js

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值