返回博客首页
← 所有文章

深入了解 NativeScript UI 的图表

2017 年 1 月 24 日 - 作者:TJ VanToll

注意: 本文于 2019 年 7 月 23 日更新,以确保所有示例都适用于 NativeScript 6.0

开发人员构建应用程序的主要原因之一是管理和可视化数据。 NativeScript UI 使得为您的数据构建强大的图表和图形变得轻而易举,它提供了一系列简单的 JavaScript 和标记 API,用于创建在 iOS 和 Android 应用程序中看起来很棒的数据可视化。

让我们通过将一些数据可视化在我最喜欢的主题——神奇宝贝——上来看看图表是如何工作的!在本文结束时,您将了解如何在自己的应用程序中构建下面的折线图、条形图和饼图。

让我们开始吧。

charts-in-action

这是深入探讨每个 NativeScript UI 组件的一系列文章中的第二篇文章。如果您是 NativeScript 或 NativeScript UI 的新手,您可能希望从本系列的 第一篇文章 开始,以了解有关组件套件的基本介绍。

RadChart 入门

入门很简单,只需运行几个命令来创建应用程序并安装 NativeScript UI 插件

tns create pokemon --js
cd pokemon
tns plugin add nativescript-ui-chart

设置完毕后,让我们创建一个简单的 Hello World 折线图,我们可以在其基础上构建。打开您新应用程序的 main-page.xml 文件,并将它的内容替换为下面的代码。

<Page 
  xmlns="http://schemas.nativescript.org/tns.xsd"
  xmlns:chart="nativescript-ui-chart"
  class="page" loaded="pageLoaded">
  <ActionBar class="action-bar" title="Pokémon Data"></ActionBar>
  <StackLayout class="p-20">     <chart:RadCartesianChart class="m-t-10" height="500">       <chart:RadCartesianChart.series>         <chart:LineSeries           items="{{ data }}"           categoryProperty="key"           valueProperty="value">           <chart:LineSeries.horizontalAxis>             <chart:CategoricalAxis />           </chart:LineSeries.horizontalAxis>           <chart:LineSeries.verticalAxis>             <chart:LinearAxis />           </chart:LineSeries.verticalAxis>         </chart:LineSeries>       </chart:RadCartesianChart.series>     </chart:RadCartesianChart>   </StackLayout> </Page>

提示p-20m-t-10 类名来自 NativeScript 核心主题,分别应用 padding: 20margin-top: 10。有关更多详细信息,请参阅 NativeScript 主题文档

接下来,打开您应用程序的 main-page.js 文件,并将它的内容替换为下面的代码

var frameModule = require("tns-core-modules/ui/frame");
var Observable = require("tns-core-modules/data/observable").Observable;
var pageData = new Observable(); pageData.data = [ { key: "One", value: 10 }, { key: "Two", value: 20 }, { key: "Three", value: 30 } ]; exports.pageLoaded = function(args) { var page = args.object; page.bindingContext = pageData; };

保存这些文件并在运行应用程序后,您将获得在 iOS 和 Android 上看起来像这样的图表。

emulators-basic-view

虽然这段代码不会产生世界上最令人兴奋的图表,但您只需用几十行代码就在 Android 和 iOS 上构建了完全原生图表,这还是挺酷的。

而我们才刚刚开始。让我们分解上面的代码,开始讨论这些图表的可配置程度。

分解图表的工作原理

使用 NativeScript UI,您可以从一系列可组合的 API 构建图表,这些 API 控制常见的图表功能,例如轴、图例和标签。以下是您用于构建上一节图表的相关代码。

<chart:RadCartesianChart class="m-t-10" height="500">
  <chart:RadCartesianChart.series>
    <chart:LineSeries
      items="{{ data }}"
      categoryProperty="key"
      valueProperty="value">
      <chart:LineSeries.horizontalAxis>
        <chart:CategoricalAxis />
      </chart:LineSeries.horizontalAxis>
      <chart:LineSeries.verticalAxis>
        <chart:LinearAxis />
      </chart:LineSeries.verticalAxis>
    </chart:LineSeries>
  </chart:RadCartesianChart.series>
</chart:RadCartesianChart>

从总体上看,NativeScript UI 中有两种不同的图表类型 - RadCatesignCharts 用于绘制具有 X 和 Y 轴的数据点,而 RadPieCharts 用于绘制在径向坐标系中的数据点。上面的示例使用 RadCartesianChart,因为它使用 X/Y 坐标,本教程后面的示例将展示 RadPieChart 的工作原理。

在您选择 RadCartesianChart 和 RadPieChart 之间后,您接下来必须提供一个 系列,或更具体地说是可视化您提供的数据点的一种方式。最常见的系列是 BarSeries、LineSeries 和 AreaSeries,尽管还有其他选项满足更利基的可视化需求。您还可以 堆叠多个系列,如果您有多个数据集想要在同一个图表中表示。

我们的示例目前使用了一个简单的 LineSeries,它的三个属性——itemskeyvalue——指向一个名为 dataObservable 对象。在下面的代码中,请注意 categoryProperty 属性如何与 data 对象的 key 属性对齐,以及 valueProperty 属性如何与 data 对象的 value 属性对齐。

<chart:LineSeries
  items="{{ data }}"
  categoryProperty="key"
  valueProperty="value">
  <chart:LineSeries.horizontalAxis>
    <chart:CategoricalAxis />
  </chart:LineSeries.horizontalAxis>
  <chart:LineSeries.verticalAxis>
    <chart:LinearAxis />
  </chart:LineSeries.verticalAxis>
</chart:LineSeries>

 

var pageData = new Observable();
pageData.data = [
  { key: "One", value: 10 },
  { key: "Two", value: 20 },
  { key: "Three", value: 30 }
];


在 NativeScript UI 中构建图表的最后一步是声明您的图表轴。在我们这个示例中,这在下面的代码中完成。

<chart:LineSeries.horizontalAxis>
  <chart:CategoricalAxis />
</chart:LineSeries.horizontalAxis>
<chart:LineSeries.verticalAxis>
  <chart:LinearAxis />
</chart:LineSeries.verticalAxis>


RadCartesianCharts 要求您为图表指定两个轴,一个水平轴和一个垂直轴。您有选择每个轴要指定的内容,您可以参考 有关轴的 NativeScript UI 文档 以了解完整的列表,但对于大多数情况,您将使用上面的代码中使用的 CategorialAxis 和 LinearAxis。

CategoricalAxis 是一种简单的显示您 categoryProperty 的方法,这也是“One”、“Two”和“Three”出现在下图水平轴上的原因。LinearAxis 线性显示您的 valueProperty 数据,这也是 102030 的值在线性地在下面的图像中的垂直轴上绘制的原因。

emulators-basic-view

总结一下,从总体上看,NativeScript UI 图表要求您执行以下步骤

  • 1) 在 RadCartesianChart 和 RadPieChart 之间进行选择。
  • 2) 为您的数据可视化指定一个系列。
  • 3) 如果您使用的是 RadCartesianChart,请提供一个用于您的水平轴或垂直轴的轴声明。

这些步骤绝对是一个简化,因为这些图表中有很多强大的功能和定制选项,但这应该可以帮助您开始学习基础知识。有了这些背景知识,让我们看看如何将这些规则应用于可视化一些实际数据。

构建折线图

我们将从折线图开始,因为我们在上一节中已经开始了一个,但我们将添加一些更现实的数据和配置选项。

首先,一个有趣的事实:您知道神奇宝贝动画片(电视剧)有超过 940 集吗?仅仅为了让您了解这个数字有多荒谬,目前《辛普森一家》大约有 600 集,该剧已经播出了 28 年。该节目的规模是如此疯狂,以至于我想可视化一下剧集的节奏——也就是说,我想看看该节目每季发布了多少集。

幸运的是,这些数据非常方便地 列在维基百科上 因此,让我们看看如何将这些数据导入图表。将以下代码粘贴到您的 main-page.xml 文件中。

<Page 
  xmlns="http://schemas.nativescript.org/tns.xsd"
  xmlns:chart="nativescript-ui-chart"
  class="page" loaded="pageLoaded">

  <ActionBar class="action-bar" title="Pokémon Data"></ActionBar>

  <StackLayout class="p-20">
    <Label class="h1" text="Anime"></Label>
    <Label class="body" textWrap="true" text="The following is a graph of the number of episodes in each Pokémon anime series over time."></Label>

    <chart:RadCartesianChart class="m-t-10" height="500">
      <chart:RadCartesianChart.series>
        <chart:LineSeries
          items="{{ animeData }}"
          categoryProperty="season"
          valueProperty="count">
          <chart:LineSeries.horizontalAxis>
            <chart:CategoricalAxis labelFitMode="Rotate" />
          </chart:LineSeries.horizontalAxis>
          <chart:LineSeries.verticalAxis>
            <chart:LinearAxis labelLayoutMode="Outer" />
          </chart:LineSeries.verticalAxis>
        </chart:LineSeries>
      </chart:RadCartesianChart.series>
    </chart:RadCartesianChart>
  </StackLayout>
</Page>


并将以下代码粘贴到您的 main-page.js 文件中。

var frameModule = require("tns-core-modules/ui/frame");
var Observable = require("tns-core-modules/data/observable").Observable;


var pageData = new Observable();
pageData.animeData = [
{ season: "1", count: 82 }, { season: "2", count: 36 }, { season: "3", count: 41 },
{ season: "4", count: 52 }, { season: "5", count: 65 }, { season: "6", count: 40 },
{ season: "7", count: 52 }, { season: "8", count: 54 }, { season: "9", count: 47 },
{ season: "10", count: 52 }, { season: "11", count: 52 }, { season: "12", count: 53 },
{ season: "13", count: 34 }, { season: "14", count: 48 }, { season: "15", count: 49 },
{ season: "16", count: 45 }, { season: "17", count: 48 }, { season: "18", count: 45 },
{ season: "19", count: 47 }
];

exports.pageLoaded = function(args) {
var page = args.object;
page.bindingContext = pageData;
};


完成后,您将获得一个看起来像这样的折线图

nativescript-line-chart

神奇宝贝系列似乎一直在尝试不同的季节长度,然后最终决定每季大约 45 集是最合适的。

就实现而言,代码与之前的基本示例几乎相同,只是提供了一些真实数据。有一些新的属性被用来定制轴,特别是 labelFitModelabelLayoutMode

<chart:LineSeries.horizontalAxis>
  <chart:CategoricalAxis labelFitMode="Rotate" />
</chart:LineSeries.horizontalAxis>
<chart:LineSeries.verticalAxis>
  <chart:LinearAxis labelLayoutMode="Outer" />
</chart:LineSeries.verticalAxis>


在本例中,labelFitMode="Rotate" 旋转水平轴上的标签,以便它们能更好地适应,而 labelLayoutMode="Outer" 在图表本身外部渲染垂直轴上的标签。但这只是您可用的自定义选项中的一小部分。

我们在这篇文章中看到的所有 API 都有详细的 API 文档,您可以参考它们以了解可用的所有属性列表。例如,以下是 CategoricalAxisLinearAxis 的文档页面,您可以随时从 文档主页 中搜索您需要的内容。

现在,让我们将我们的讨论转向另一种常见的图表类型,看看如何使用 NativeScript UI 来可视化条形图中的数据。

构建条形图

使用 UI for NativeScipt,实现条形图非常类似于实现折线图。您仍然使用 RadCartesianChart,但必须从 LineSeries 切换到 BarSeries。让我们看一个具体的例子来展示实际的差异。

对于条形图,我想展示另一个神奇宝贝数据。800 多个神奇宝贝角色中,每一个都有一个类型——火、水、电等等,这种类型在选择战斗中使用哪只神奇宝贝时很重要。火属性攻击对草属性神奇宝贝有效,水属性对火属性神奇宝贝有效,等等。但实际上比这复杂得多,因为目前有 18 种属性,如果您想有效地战斗,需要记住一套令人眼花缭乱的规则。由于这种规模,我想可视化一下目前神奇宝贝类型的分布,条形图非常适合这一点。

要实际体验一下,请将以下代码粘贴到您的 main-page.xml 文件中。

<Page 
  xmlns="http://schemas.nativescript.org/tns.xsd"
  xmlns:chart="nativescript-ui-chart"
  class="page" loaded="pageLoaded">

  <ActionBar class="action-bar" title="Pokémon Data"></ActionBar>

  <StackLayout class="p-20">
    <Label class="h1" text="Types"></Label>
    <Label class="body" textWrap="true" text="The following is a count of the total number of Pokémon of a given type."></Label>

    <chart:RadCartesianChart class="m-t-5" height="500">
      <chart:RadCartesianChart.series>
        <chart:BarSeries
          items="{{ typeData }}"
          categoryProperty="type"
          valueProperty="count"
          showLabels="false">
          <chart:BarSeries.horizontalAxis>
            <chart:LinearAxis labelFitMode="Rotate" />
          </chart:BarSeries.horizontalAxis>
          <chart:BarSeries.verticalAxis>
            <chart:CategoricalAxis />
          </chart:BarSeries.verticalAxis>
        </chart:BarSeries>
      </chart:RadCartesianChart.series>
    </chart:RadCartesianChart>
  </StackLayout>
</Page>


然后,将以下代码用于您的 main-page.js 文件。

var frameModule = require("tns-core-modules/ui/frame");
var Observable = require("tns-core-modules/data/observable").Observable;

var pageData = new Observable();
pageData.typeData = [
  { type:"Poison", count: 59 }, { type:"Grass", count: 84 }, { type: "Fire",count: 56 },
  { type: "Flying", count: 90 }, { type:"Water", count: 118 },{ type: "Bug", count: 66 },
  { type: "Normal", count: 97 }, { type: "Electric", count: 42 }, { type: "Ground", count: 60 },
  { type: "Fairy", count: 35 }, { type:"Fighting", count: 44 }, { type: "Psychic", count: 74 },
  { type: "Rock", count: 55 }, { type:"Steel", count: 41 }, { type: "Ice", count: 33 },
  { type: "Ghost", count: 35 }, { type: "Dragon", count: 38}, { type:"Dark", count: 44 }
];

exports.pageLoaded = function(args) {
  var page = args.object;
  page.bindingContext = pageData;
};


保存这些文件后,您应该会看到一个看起来像这样的图表。

nativescript-bar-chart

看来,水属性神奇宝贝是最常见的。谁知道呢?

但更重要的是,请注意这个示例与之前的条形图示例有多么相似——唯一的真正区别是使用了 BarSeries 而不是 LineSeries。事实上,如果您将 main-page.xml 中所有提到的“BarSeries”替换为“LineSeries”,您将能够用线代替来显示完全相同的数据。

nativescript-line-chart-2

希望这能让你对 NativeScript 图表的可配置程度有一个了解。一旦您了解了几个基本 API 的工作原理,您就可以用惊人地少的代码创建非常强大的数据可视化。为了举一个这样的例子,请考虑以下配置图表轴的代码片段。

<chart:BarSeries.horizontalAxis>
  <chart:LinearAxis labelFitMode="Rotate" />
</chart:BarSeries.horizontalAxis>
<chart:BarSeries.verticalAxis>
  <chart:CategoricalAxis />
</chart:BarSeries.verticalAxis>


这段代码表示在 Y 轴上渲染图表的分类轴(或标签),在 X 轴上渲染图表的数值轴。如果您想交换两者,您只需交换这两行代码即可。具体来说,如果您将上面的代码改为使用以下方法。

<chart:BarSeries.horizontalAxis>
  <chart:CategoricalAxis labelFitMode="Rotate" />
</chart:BarSeries.horizontalAxis>
<chart:BarSeries.verticalAxis>
  <chart:LinearAxis />
</chart:BarSeries.verticalAxis>


该应用程序将渲染轴翻转的图表。

nativescript-charts-flipped

现在,仅仅因为您可以以多种方式渲染图表并不意味着您应该这样做。例如,您可以看到上面的图表中,X 轴上的标签不怎么适合。

NativeScript UI 的目标是为您提供大量的配置选项,以构建适合您数据的图表。我在本文中展示了一些配置选项,您可以参考 RadCartesianChart 文档 以了解您可以执行的所有操作的完整列表。

但现在,让我们看最后一个例子,展示如何使用 NativeScript UI 构建饼图。

构建饼图

当您想要将数据的各个部分与整体进行比较时,以及当您只有相对少的数据点时,饼图效果很好。要了解如何使用 NativeScript UI 创建这些图表,让我们看另一个神奇宝贝示例。

目前神奇宝贝世界有 802 只神奇宝贝,这些生物被分成了七个“世代”。第一世代于 1996 年创造了 151 只神奇宝贝,第七世代在去年 11 月增加了 81 只新神奇宝贝。

为了我们的目的,我想可视化每个世代对整体神奇宝贝数量的比例。要看到实际效果,请将以下代码粘贴到您的应用程序的 main-page.xml 文件中。

<chart:RadPieChart height="300">
  <chart:RadPieChart.series>
    <chart:PieSeries
      selectionMode="None"
      items="{{ generationData }}"
      outerRadiusFactor="0.8"
      valueProperty="count"
      legendLabel="generation"
      showLabels="true">
    </chart:PieSeries>
  </chart:RadPieChart.series>
  <chart:RadPieChart.legend>
    <chart:RadLegendView
      position="Right"
      width="110" />
  </chart:RadPieChart.legend>
</chart:RadPieChart>

然后,将以下代码用于您的应用程序的 main-page.js 文件。

var frameModule = require("tns-core-modules/ui/frame");
var Observable = require("tns-core-modules/data/observable").Observable;


var pageData = new Observable();
pageData.generationData = [
{ generation: "One", count: 151 },
{ generation: "Two", count: 100 },
{ generation: "Three", count: 135 },
{ generation: "Four", count: 107 },
{ generation: "Five", count: 156 },
{ generation: "Six", count: 72 },
{ generation: "Seven", count: 81 }
];

exports.pageLoaded = function(args) {
var page = args.object;
page.bindingContext = pageData; };


使用此代码,您将获得一个看起来像这样的饼图。

nativescript-pie-chart

让我们回到代码中,解释一下所有这些是如何工作的。请记住,在 RadCartesianCharts 中,您配置的主要内容是系列和两个轴。在 RadPieCharts 中,您不再拥有轴,但您仍然拥有系列,以及可选的图例。以下是代码的高级视图。

<chart:RadPieChart>
  <chart:RadPieChart.series>
    <chart:PieSeries />
  </chart:PieSeries>
  </chart:RadPieChart.series>
  <chart:RadPieChart.legend>
    <chart:RadLegendView />
  </chart:RadPieChart.legend>
</chart:RadPieChart>


RadChart API 支持两种系列,PieSeries 和 DonutSeries,以及单个图例 RadLegendView。每个都有一系列属性,您可以使用这些属性来配置图表的外观和行为。以下是我们示例中使用的属性。

  • PieSeries
    • selectionMode:确定用户是否能够选择饼图中的部分。在本例中,这不是我们想要的,因此我们将属性设置为 "None"
    • items:指向页面 Observable 对象上包含驱动图表数据的 JavaScript 属性。
    • outerRadiusFactor:控制生成的饼图的大小。大于 1 的值会增加图表的半径,小于 1 的值会减小图表的半径。
    • valuePropertyitems 对象上包含要在图表中显示的值的 JavaScript 属性。
    • legendLabelitems 对象上包含要在图表图例中显示的标签的 JavaScript 属性。
    • showLabels:是否在饼图上显示标签。
  • RadLegendView
    • position:将图例放置在饼图的哪个位置。"Bottom""Top""Left""Right""Floating" 是有效值。
    • width:图例的宽度。
<chart:RadPieChart>
  <chart:RadPieChart.series>
    <chart:PieSeries
      selectionMode="None"
      items="{{ generationData }}"
      outerRadiusFactor="0.8"
      valueProperty="count"
      legendLabel="generation"
      showLabels="true">
    </chart:PieSeries>
  </chart:RadPieChart.series>
  <chart:RadPieChart.legend>
    <chart:RadLegendView
      position="Right"
      width="110" />
  </chart:RadPieChart.legend>
</chart:RadPieChart>


您可以参考 NativeScript UI API 文档 以获取可用于自定义各种图表以满足您的需求的所有可用属性和值的完整列表。

总结

无论您需要可视化销售数据、人口普查数据还是神奇宝贝世界中的数字,NativeScript UI 图表都应该提供满足您需求的 API。在本文中,我们探讨了如何构建折线图、柱状图和饼图,但 NativeScript UI 还提供了 气泡图散点图样条图区域图烛台图(无论是什么)以及更多其他 API。