Charts | Crossroads Digital Design Kit

Charts

Charts

Simple charts can be rendered using an <svg> element. The following example shows a basic SVG chart within an Angular context.

While the markup can be written and manipulated directly, this example makes use of a third-party library, SVG.js, to demonstrate how the bars could be animated when the page loads.

When you need a more complex interactivity with a chart, we recommend using the third-party charting tool called NGX-Charts.

<!DOCTYPE html>
<html>

<head>
  <base href="." />
  <title>SVG Chart Example</title>

  {% stylesheet_link_tag application %}

  <script src="//unpkg.com/zone.js/dist/zone.js"></script>
  <script src="//unpkg.com/zone.js/dist/long-stack-trace-zone.js"></script>
  <script src="//unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script>
  <script src="//unpkg.com/systemjs@0.19.31/dist/system.js"></script>
  <script src="config.js"></script>

  <script src="//cdn.jsdelivr.net/npm/svg.js@2.6.3/dist/svg.min.js"></script>
  <script src="//cdn.jsdelivr.net/npm/svg.pathmorphing.js@0.1.1/dist/svg.pathmorphing.min.js"></script>

  <script>
    System.import('app')
      .catch(console.error.bind(console));

  </script>
  <script src="https://use.typekit.net/ccb3vpa.js"></script>
  <script>
    try {
      Typekit.load({
        async: true
      });
    } catch (e) {}

  </script>

  <script src="/examples/shared/theme_toggler.js"></script>
</head>

<body>

  <style>
    @keyframes rotateInitLoadingSpinner {
      100% {
        transform: rotate(360deg);
      }
    }

    .preloader {
      position: absolute;
      display: block;
      top: 48px;
      left: calc(50% - 37.5px);
      width: 75px;
      height: 75px;
      margin: 0 auto;
      background: transparent;
      animation: rotateInitLoadingSpinner 700ms linear infinite;
    }

    .preloader-wrapper {
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
    }

  </style>

  <my-app>
    <div class="preloader-wrapper">
      <svg viewBox="0 0 102 101" class="preloader">
        <g fill="none" fill-rule="evenodd">
          <g transform="translate(1 1)" stroke-width="2">
            <ellipse stroke="#eee" cx="50" cy="49.421" rx="50" ry="49.421"></ellipse>
            <path d="M50 98.842c27.614 0 50-22.127 50-49.42C100 22.125 77.614 0 50 0" stroke-opacity=".631" stroke="#3B6E8F"></path>
          </g>
        </g>
      </svg>
    </div>
  </my-app>
</body>

</html>
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { ChartComponent } from './chart.component';

@NgModule({
  imports: [
    BrowserModule
  ],
  declarations: [
    AppComponent,
    ChartComponent
  ],
  bootstrap: [
    AppComponent
  ]
})
export class AppModule {}
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html'
})
export class AppComponent {

  constructor() {}

}
<div class="container soft-ends">
  <div class="row">
    <svg-chart></svg-chart>
  </div>
</div>
import { Component, OnInit } from '@angular/core';

declare const SVG;

@Component({
  selector: 'svg-chart',
  templateUrl: './chart.component.html'
})
export class ChartComponent implements OnInit {

  bars = {
    thing1: {
      value: 2.7,
      top: 228
    },
    thing2: {
      value: 2.4,
      top: 171
    },
    thing3: {
      value: 1.8,
      top: 114
    },
    thing4: {
      value: 1.2,
      top: 57
    },
    thing5: {
      value: 0.6,
      top: 0
    }
  };

  svg: any;

  constructor() {}

  ngOnInit() {
    this.svg = SVG.get('my-chart');
    this.initBarPaths();
  }

  private initBarPaths() {
    for (let name in this.bars) {
      if (name) {
        const bar = this.bars[name];
        const svgBar = this.getBar(name);
        svgBar.attr({ d: this.getPathArray(bar, 0) });
        svgBar.animate(750, '<>', 0).plot(this.getPathArray(bar));
      }
    }
  }

  private getPathArray(bar, value = bar.value) {
    const right = (value * 206) - 4;
    const top = bar.top;
    return new SVG.PathArray([
      ['M', 0, top],
      ['L', right, top],
      ['C', right + 2, top, right + 4, top + 2, right + 4, top + 4],
      ['L', right + 4, top + 45],
      ['C', right + 4, top + 47, right + 2, top + 49, right, top + 49],
      ['L', 0, top + 49],
      ['L', 0, 0]
    ]);
  }

  private getBar(name) {
    return this.svg.select(`#${name}-path`);
  }
}
<svg id="my-chart" viewBox="0 0 750 313" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
    <!-- Grid Lines -->
    <g transform="translate(81.5, 0.5)" stroke="#E7E7E7" stroke-linecap="square">
      <path d="M0,0 L0,276.6"></path>
      <path d="M206,0 L206,276.6"></path>
      <path d="M412,0 L412,276.6"></path>
      <path d="M618,0 L618,276.6"></path>
    </g>
    <!-- Y-Axis Labels -->
    <g transform="translate(64, 0)" font-size="14" fill="#737373" font-weight="300" text-anchor="end">
      <text y="257">Thing #1</text>
      <text y="200">Thing #2</text>
      <text y="143">Thing #3</text>
      <text y="86">Thing #4</text>
      <text y="29">Thing #5</text>
    </g>
    <!-- Bars -->
    <g id="bar-group" fill="#57AFA9" transform="translate(82, 0)">
      <path id="thing1-path"></path>
      <path id="thing2-path"></path>
      <path id="thing3-path"></path>
      <path id="thing4-path"></path>
      <path id="thing5-path"></path>
    </g>
    <!-- X-Axis Labels -->
    <g transform="translate(81.5, 310)" fill="#737373" font-size="14" font-weight="300" text-anchor="middle">
      <text x="0">0</text>
      <text x="206">1</text>
      <text x="412">2</text>
      <text x="618">3</text>
    </g>
  </g>
</svg>