Charts

The Dashboard page continues with a donut chart that visualizes some of the same facts reported using InfoCard. We define it as a Statuses component whose width and title are defined by its containing Dashboard component. Here we'll use it standalone.

<App>
  <Statuses />
</App>

Statuses wraps EChart in a SimpleDonutChart component that accepts familiar props: data, dataKey, and nameKey. Internally it builds the ECharts option object.

  • data: The ubiquitous attribute that refers to data that may be defined literally or, as in this case, via an API call backed by a database query.
  • dataKey: The object key that holds data.
  • nameKey: The object key whose value is the data label.
<Component name="SimpleDonutChart">
  <EChart
    height="{$props.height || '100%'}"
    option="{
      {
        tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
        legend: { orient: $props.layout === 'vertical' ? 'vertical' : 'horizontal', bottom: 0 },
        series: [{
          type: 'pie',
          radius: ['40%', '70%'],
          label: { show: true, formatter: '{b}' },
          data: ($props.data || []).map(function(item) {
            return { name: item[$props.nameKey || 'name'], value: item[$props.dataKey || 'value'] }
          })
        }]
      }
    }" />
</Component>
<Component name="Statuses">
  <DataSource id="dashboardStats" url="/resources/files/dashboard-stats.json" method="GET" />
  <Card title="Statuses" height="400px" width="{$props.width}">
    <SimpleDonutChart
      data="{
        [
          {
            name: 'sent',
            value: dashboardStats.value[0].sent_invoices
          },
          {
            name: 'draft',
            value: dashboardStats.value[0].draft_invoices
          },
          {
            name: 'paid',
            value: dashboardStats.value[0].paid_invoices
          },
        ]
      }"
      dataKey="value"
      nameKey="name"
    />
  </Card>
</Component>
<App>
  <Statuses />
</App>

Statuses wraps EChart in a SimpleDonutChart component that accepts familiar props: data, dataKey, and nameKey. Internally it builds the ECharts option object.

  • data: The ubiquitous attribute that refers to data that may be defined literally or, as in this case, via an API call backed by a database query.
  • dataKey: The object key that holds data.
  • nameKey: The object key whose value is the data label.
<Component name="SimpleDonutChart">
  <EChart
    height="{$props.height || '100%'}"
    option="{
      {
        tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
        legend: { orient: $props.layout === 'vertical' ? 'vertical' : 'horizontal', bottom: 0 },
        series: [{
          type: 'pie',
          radius: ['40%', '70%'],
          label: { show: true, formatter: '{b}' },
          data: ($props.data || []).map(function(item) {
            return { name: item[$props.nameKey || 'name'], value: item[$props.dataKey || 'value'] }
          })
        }]
      }
    }" />
</Component>
<Component name="Statuses">
  <DataSource id="dashboardStats" url="/resources/files/dashboard-stats.json" method="GET" />
  <Card title="Statuses" height="400px" width="{$props.width}">
    <SimpleDonutChart
      data="{
        [
          {
            name: 'sent',
            value: dashboardStats.value[0].sent_invoices
          },
          {
            name: 'draft',
            value: dashboardStats.value[0].draft_invoices
          },
          {
            name: 'paid',
            value: dashboardStats.value[0].paid_invoices
          },
        ]
      }"
      dataKey="value"
      nameKey="name"
    />
  </Card>
</Component>

Multiseries charts

The SimpleDonutChart works with a single series of data and uses dataKey. A SimpleBarChart wrapper can display multiple series denoted by yKeys. We see that in the MonthlyStatus chart.

<App>
  <MonthlyStatus />
</App>
<Component name="SimpleBarChart">
  <EChart
    height="{$props.height || '100%'}"
    option="{
      {
        tooltip: { trigger: 'axis' },
        legend: $props.showLegend ? {} : undefined,
        grid: { containLabel: true },
        xAxis: $props.orientation === 'horizontal'
          ? { type: 'category', data: ($props.data || []).map(function(d) { return d[$props.xKey] }), axisLabel: { formatter: $props.tickFormatterX } }
          : { type: 'value', axisLabel: { formatter: $props.tickFormatterY } },
        yAxis: $props.orientation === 'horizontal'
          ? { type: 'value', axisLabel: { formatter: $props.tickFormatterY } }
          : { type: 'category', data: ($props.data || []).map(function(d) { return d[$props.xKey] }), axisLabel: { formatter: $props.tickFormatterX } },
        series: ($props.yKeys || []).map(function(k) {
          return {
            type: 'bar',
            name: k,
            stack: ($props.stacked === 'true' || $props.stacked === true) ? 'total' : undefined,
            data: ($props.data || []).map(function(d) { return d[k] })
          }
        })
      }
    }" />
</Component>
<Component name="MonthlyStatus">

    <DataSource
        id="monthlyStatus"
        url="/resources/files/monthly-status.json"
        method="GET" />

    <VStack width="{$props.width}">
        <H1>{$props.title}</H1>

        <Card height="400px">
        <SimpleBarChart
          orientation="horizontal"
          data="{monthlyStatus.value}"
          xKey="month"
          yKeys="{['paid_revenue', 'sent_revenue']}"
          stacked="true"
          showLegend="true"
          tickFormatterX="{(value) => window.formatMonth(value)}"
        />
        </Card>
    </VStack>

</Component>
<App>
  <MonthlyStatus />
</App>
<Component name="SimpleBarChart">
  <EChart
    height="{$props.height || '100%'}"
    option="{
      {
        tooltip: { trigger: 'axis' },
        legend: $props.showLegend ? {} : undefined,
        grid: { containLabel: true },
        xAxis: $props.orientation === 'horizontal'
          ? { type: 'category', data: ($props.data || []).map(function(d) { return d[$props.xKey] }), axisLabel: { formatter: $props.tickFormatterX } }
          : { type: 'value', axisLabel: { formatter: $props.tickFormatterY } },
        yAxis: $props.orientation === 'horizontal'
          ? { type: 'value', axisLabel: { formatter: $props.tickFormatterY } }
          : { type: 'category', data: ($props.data || []).map(function(d) { return d[$props.xKey] }), axisLabel: { formatter: $props.tickFormatterX } },
        series: ($props.yKeys || []).map(function(k) {
          return {
            type: 'bar',
            name: k,
            stack: ($props.stacked === 'true' || $props.stacked === true) ? 'total' : undefined,
            data: ($props.data || []).map(function(d) { return d[k] })
          }
        })
      }
    }" />
</Component>
<Component name="MonthlyStatus">

    <DataSource
        id="monthlyStatus"
        url="/resources/files/monthly-status.json"
        method="GET" />

    <VStack width="{$props.width}">
        <H1>{$props.title}</H1>

        <Card height="400px">
        <SimpleBarChart
          orientation="horizontal"
          data="{monthlyStatus.value}"
          xKey="month"
          yKeys="{['paid_revenue', 'sent_revenue']}"
          stacked="true"
          showLegend="true"
          tickFormatterX="{(value) => window.formatMonth(value)}"
        />
        </Card>
    </VStack>

</Component>