Skip to content
Search

TOAST UI Chart

lastmod 2023-06-13created 2022-04-0112 edits

Spread your data on TOAST UI Chart. TOAST UI Chart is Beautiful Statistical Data Visualization library.

Auto Size

Setting the chart.width or chart.height option to auto sets it automatically to the size of the chart container. If the chart container's size is set to a relative value, the chart size will change automatically with the browser window size. Also, when used together with the responsive option, you can freely set options that fit the chart size without separately calling the updateOptions API every time the window size changes.

<div id="chart" style="width: 90vw; height: 90vh">
const options = {
  chart: { width: 'auto', height:'auto' }
  responsive: {
    rules: [
      ...
    ]
  }
};

const el = document.getElementById('chart');
const chart = toastui.Chart.areaChart({ el, data, options });

Vue.js LineChart Component

<template>
  <div ref="el" :style="style"></div>
</template>

<script lang="ts">
import {Vue, Component, Prop, Ref, Watch, Emit} from 'vue-property-decorator';
import ToastChart, {
  LineChart as ToastLineChart,
  LineChartOptions,
  LineSeriesData,
} from '@toast-ui/chart';
import type {LineSeriesDataType} from '@toast-ui/chart/types/options';
import '@toast-ui/chart/dist/toastui-chart.min.css';

const CLICK_LEGEND_LABEL = 'clickLegendLabel';
const CLICK_LEGEND_CHECKBOX = 'clickLegendCheckbox';
const SELECT_SERIES = 'selectSeries';
const UNSELECT_SERIES = 'unselectSeries';
const HOVER_SERIES = 'hoverSeries';
const UNHOVER_SERIES = 'unhoverSeries';
const ZOOM = 'zoom';
const RESET_ZOOM = 'resetZoom';

@Component
export default class LineChart extends Vue {
  @Prop({type: Object, required: true})
  readonly data!: LineSeriesData;

  @Prop({type: Object, default: () => new Object()})
  readonly options!: LineChartOptions;

  @Prop({type: [Number, String], default: '100%'})
  readonly width?: number | string;

  @Prop({type: [Number, String], default: '40vh'})
  readonly height?: number | string;

  @Prop({type: [Number, String], default: '12%'})
  readonly minWidth?: number | string;

  @Prop({type: [Number, String], default: '12vh'})
  readonly minHeight?: number | string;

  @Prop({type: [Number, String]})
  readonly maxWidth?: number | string;

  @Prop({type: [Number, String]})
  readonly maxHeight?: number | string;

  @Ref()
  readonly el!: HTMLDivElement;

  chart!: ToastLineChart;

  @Watch('data', {deep: true})
  watchData(newData) {
    this.chart.setData(newData);
  }

  @Watch('options', {deep: true})
  watchOptions(newOptions) {
    this.chart.setOptions(newOptions);
  }

  mounted() {
    this.chart = ToastChart.lineChart({
      el: this.el,
      data: this.data,
      options: this.options,
    });

    this.chart.on(CLICK_LEGEND_LABEL, e => this.clickLegendLabel(e));
    this.chart.on(CLICK_LEGEND_CHECKBOX, e => this.clickLegendCheckbox(e));
    this.chart.on(SELECT_SERIES, e => this.selectSeries(e));
    this.chart.on(UNSELECT_SERIES, e => this.unselectSeries(e));
    this.chart.on(HOVER_SERIES, e => this.hoverSeries(e));
    this.chart.on(UNHOVER_SERIES, e => this.unhoverSeries(e));
    this.chart.on(ZOOM, e => this.zoom(e));
    this.chart.on(RESET_ZOOM, e => this.resetZoom(e));
  }

  beforeDestroy() {
    this.chart.destroy();
  }

  get style() {
    let result = '';
    if (this.width) {
      result += `width: ${this.width};`;
    }
    if (this.height) {
      result += `height: ${this.height};`;
    }
    if (this.minWidth) {
      result += `min-width: ${this.minWidth};`;
    }
    if (this.minHeight) {
      result += `min-height: ${this.minHeight};`;
    }
    if (this.maxWidth) {
      result += `max-width: ${this.maxWidth};`;
    }
    if (this.maxHeight) {
      result += `max-height: ${this.maxHeight};`;
    }
    return result;
  }

  @Emit(CLICK_LEGEND_LABEL)
  clickLegendLabel(event) {
    return event;
  }

  @Emit(CLICK_LEGEND_CHECKBOX)
  clickLegendCheckbox(event) {
    return event;
  }

  @Emit(SELECT_SERIES)
  selectSeries(event) {
    return event;
  }

  @Emit(UNSELECT_SERIES)
  unselectSeries(event) {
    return event;
  }

  @Emit(HOVER_SERIES)
  hoverSeries(event) {
    return event;
  }

  @Emit(UNHOVER_SERIES)
  unhoverSeries(event) {
    return event;
  }

  @Emit(ZOOM)
  zoom(event) {
    return event;
  }

  @Emit(RESET_ZOOM)
  resetZoom(event) {
    return event;
  }

  addData(data: Array<LineSeriesDataType>, category?: string) {
    this.chart.addData(data, category);
  }
}
</script>

Live chart usage

<i18n lang="yaml">
en:
  title: 'ANSWER PLUGIN'

ko:
  title: '엔서 플러그인'
</i18n>

<template>
  <v-container>
    <v-row>
      <line-chart
        ref="chart"
        :data="chartProps.data"
        :options="chartProps.options"
      ></line-chart>
    </v-row>
  </v-container>
</template>

<script lang="ts">
import {Vue, Component, Ref} from 'vue-property-decorator';
import LineChart from '@/chart/LineChart.vue';

@Component({
  components: {
    LineChart,
  },
})
export default class SensorView extends Vue {
  @Ref()
  chart!: LineChart;

  chartProps = {
    options: {
      usageStatistics: false,
      chart: {
        width: 'auto',
        height: 'auto',
        title: '24-hr Average Temperature',
      },
      yAxis: {
        title: 'Temperature (Celsius)',
        pointOnColumn: true,
      },
      xAxis: {
        title: 'Years',
      },
      series: {
        shift: true,
        showDot: false,
        // zoomable: true,
        spline: true,
      },
    },
    data: {
      categories: ['2020', '2021', '2022', '2023'],
      series: [
        {
          name: 'Seoul',
          data: [-3.5, -1.1, 4.0, 11.3],
        },
        {
          name: 'Seattle',
          data: [3.8, 5.6, 7.0, 9.1],
        },
        {
          name: 'Sydney',
          data: [22.1, 22.0, 20.9, 18.3],
        },
        {
          name: 'Moskva',
          data: [-10.3, -9.1, -4.1, 4.4],
        },
        {
          name: 'Jungfrau',
          data: [-13.2, -13.7, -13.1, -10.3],
        },
      ],
    },
  };

  category = 2024;

  created() {
    window.setInterval(() => {
      const seoul = Math.round(Math.random() * 100);
      const seattle = Math.round(Math.random() * 100);
      const sydney = Math.round(Math.random() * 100);
      const moskva = Math.round(Math.random() * 100);
      const jungfrau = Math.round(Math.random() * 100);

      const data = [seoul, seattle, sydney, moskva, jungfrau];
      const category = this.category.toString();

      this.chart.addData(data, category);
      this.category++;
    }, 1000);
  }
}
</script>

Troubleshooting

X-axis entries disappearing one by one with addData in a live chart

You will initially create the chart diagram with code like this:

const chart = ToastChart.lineChart({
  el: this.el,
  data: this.data,
  options: this.options,
});

Here, there is data on the third line, and you must not change this value. When adding values, add them only with addData.

See also

Favorite site

author Zer0 sitemap