G2Plot Line Chart Essentials and Advanced Customizations

Standard Line Chart Implementation

import { Line } from '@antv/g2plot';

const url = 'https://gw.alipayobjects.com/os/bmw-prod/1d565782-dde4-4bb6-8946-ea6a38ccf184.json';

async function initBasicChart() {
  const response = await fetch(url);
  const seriesData = await response.json();

  const chartInstance = new Line('chart-mount-point', {
    data: seriesData,
    padding: 'auto',
    xField: 'month',
    yField: 'indexValue',
    xAxis: {
      tickCount: 5,
    },
  });

  chartInstance.render();
}

initBasicChart();

Sample dataset structure:

[
  { "month": "2010-01", "indexValue": 1998 },
  { "month": "2010-02", "indexValue": 1850 },
  { "month": "2010-03", "indexValue": 1720 }
]

(Note: Full dataset spans multiple years as per original source)

Smooth Curve Variation

To generate a flowing line instead of sharp angles, enable the smooth property.

import { Line } from '@antv/g2plot';

const loadAndRenderSmooth = async () => {
  const res = await fetch('https://gw.alipayobjects.com/os/bmw-prod/1d565782-dde4-4bb6-8946-ea6a38ccf184.json');
  const metrics = await res.json();

  const smoothChart = new Line('container', {
    data: metrics,
    xField: 'month',
    yField: 'indexValue',
    smooth: true,
    xAxis: { tickCount: 5 },
  });

  smoothChart.render();
};

loadAndRenderSmooth();

Point Style Configuration

Customize point markers with shape, size, and interaction states.

import { Line } from '@antv/g2plot';

const localizedData = [
  { year: '1991', value: 3 },
  { year: '1992', value: 4 },
  { year: '1993', value: 3.5 },
  { year: '1994', value: 5 },
  { year: '1995', value: 4.9 },
  { year: '1996', value: 6 },
  { year: '1997', value: 7 },
  { year: '1998', value: 9 },
  { year: '1999', value: 13 },
];

const styleConfig = new Line('mount-node', {
  data: localizedData,
  xField: 'year',
  yField: 'value',
  label: {},
  point: {
    size: 5,
    shape: 'diamond',
    style: {
      fill: 'white',
      stroke: '#5B8FF9',
      lineWidth: 2,
    },
  },
  tooltip: { showMarkers: false },
  state: {
    active: {
      style: {
        shadowBlur: 4,
        stroke: '#000',
        fill: 'red',
      },
    },
  },
  interactions: [{ type: 'marker-active' }],
});

styleConfig.render();

Y-Axis Reflection

Flip the coordinate system vertically by setting reflect to 'y'. This usually requires moving the X-axis to the top.

import { Line } from '@antv/g2plot';

const flipChartData = [
  { Date: '2021-10-01', rating: 1 },
  { Date: '2021-10-02', rating: 3 },
  { Date: '2021-10-03', rating: 8 },
  { Date: '2021-10-04', rating: 12 },
  { Date: '2021-10-05', rating: 30 },
];

const reflectYChart = new Line('dom-target', {
  data: flipChartData,
  padding: 'auto',
  xField: 'Date',
  yField: 'rating',
  reflect: 'y',
  xAxis: {
    position: 'top',
  },
});

reflectYChart.render();

Sliding Zoom (Mini Map)

Implement interactive range selection using the slider configuration.

import { Line } from '@antv/g2plot';

const loadDataWithSlider = async () => {
  const result = await fetch('https://gw.alipayobjects.com/os/bmw-prod/1d565782-dde4-4bb6-8946-ea6a38ccf184.json').then(r => r.json());
  
  const zoomChart = new Line('container', {
    data: result,
    padding: 'auto',
    xField: 'month',
    yField: 'indexValue',
    xAxis: { tickCount: 5 },
    slider: {
      start: 0.1,
      end: 0.5,
    },
  });
  
  zoomChart.render();
};

loadDataWithSlider();

Custom Animated Markers

Register a custom shape for specific points to display animations like pulsing effects.

import { G2, Line } from '@antv/g2plot';

G2.registerShape('point', 'pulse-point', {
  draw(opts, group) {
    const coords = opts.x;
    const renderGroup = group.addGroup();
    if (opts.data.time === '14.20' && opts.data.date === 'today') {
      const rings = [];
      for(let i=0; i<3; i++) {
        rings.push(renderGroup.addShape('circle', {
          attrs: {
            cx: coords.x,
            cy: coords.y,
            r: 10,
            fill: opts.color,
            opacity: 0.5,
          },
        }));
      }

      const animateOpts = (ring, delay) => ({
        duration: 1800,
        easing: 'easeLinear',
        repeat: true,
        delay: delay,
      });

      rings[0].animate({ r: 20, opacity: 0 }, animateOpts(rings[0], 0));
      rings[1].animate({ r: 20, opacity: 0 }, animateOpts(rings[1], 600));
      rings[2].animate({ r: 20, opacity: 0 }, animateOpts(rings[2], 1200));

      renderGroup.addShape('circle', { attrs: { x: coords.x, y: coords.y, r: 6, fill: opts.color, opacity: 0.7 } });
      renderGroup.addShape('circle', { attrs: { x: coords.x, y: coords.y, r: 1.5, fill: opts.color } });
    }
    return renderGroup;
  },
});

const getCPUData = async () => {
  const resp = await fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/cpu-data.json');
  return resp.json();
};

(async () => {
  const cpuSeries = await getCPUData();
  const animatedPlot = new Line('canvas-node', {
    autoFit: true,
    height: 500,
    data: cpuSeries,
    meta: {
      cpu: { time: { type: 'cat' }, max: 100, min: 0 },
    },
    xField: 'time',
    yField: 'cpu',
    seriesField: 'date',
    tooltip: { showMarkers: false },
    point: { shape: 'pulse-point' },
  });
  animatedPlot.render();
})();

Conditional Styling via Annotations

Highlight regions based on statistical calculations like median.

import { Line } from '@antv/g2plot';

const conditionalRender = async () => {
  const source = await fetch('https://gw.alipayobjects.com/os/bmw-prod/1d565782-dde4-4bb6-8946-ea6a38ccf184.json').then(r => r.json());
  
  const statLine = new Line('node-area', {
    data: source,
    padding: 'auto',
    xField: 'month',
    yField: 'indexValue',
    annotations: [
      {
        type: 'regionFilter',
        start: ['min', 'median'],
        end: ['max', '0'],
        color: '#F4664A',
      },
      {
        type: 'text',
        position: ['min', 'median'],
        content: 'Median Value',
        offsetY: -4,
        style: { textBaseline: 'bottom' },
      },
      {
        type: 'line',
        start: ['min', 'median'],
        end: ['max', 'median'],
        style: { stroke: '#F4664A', lineDash: [2, 2] },
      },
    ],
  });

  statLine.render();
};

conditionalRender();

Interactive Custom Markers

Create complex hover interactions by registering a custom action for geometry elements.

import { Line, G2 } from '@antv/g2plot';
import { each, findIndex } from '@antv/util';

const { InteractionAction, registerInteraction, registerAction } = G2;

const customDataSet = [
  { year: '1991', value: 3 }, { year: '1992', value: 4 }, { year: '1993', value: 3.5 },
  { year: '1994', value: 5 }, { year: '1995', value: 4.9 }, { year: '1996', value: 6 },
  { year: '1997', value: 7 }, { year: '1998', value: 9 }, { year: '1999', value: 13 },
];

G2.registerShape('point', 'double-ring', {
  draw(ctxConfig, groupContainer) {
    const target = { x: ctxConfig.x, y: ctxConfig.y };
    const wrapper = groupContainer.addGroup();
    wrapper.addShape('circle', {
      name: 'outer-shell',
      attrs: { x: target.x, y: target.y, fill: ctxConfig.color || 'red', opacity: 0.5, r: 6 },
    });
    wrapper.addShape('circle', {
      name: 'inner-core',
      attrs: { x: target.x, y: target.y, fill: ctxConfig.color || 'red', opacity: 1, r: 2 },
    });
    return wrapper;
  },
});

class MarkerControl extends InteractionAction {
  executeActivate() {
    const viewRef = this.getView();
    const eventData = this.context.event;
    if (eventData.data) {
      const itemsList = eventData.data.items;
      const pts = viewRef.geometries.filter(g => g.type === 'point');
      pts.forEach(geom => {
        geom.elements.forEach((elem, idx) => {
          const isActive = findIndex(itemsList, item => item.data === elem.data) !== -1;
          const children = elem.shape.getChildren();
          if (isActive) {
            children[0].animate({ r: 10, opacity: 0.2 }, { duration: 1800, easing: 'easeLinear', repeat: true });
            children[1].animate({ r: 6, opacity: 0.4 }, { duration: 800, easing: 'easeLinear', repeat: true });
          } else {
            this.resetElementState(elem);
          }
        });
      });
    }
  }

  reset() {
    const viewRef = this.getView();
    const allPts = viewRef.geometries.filter(g => g.type === 'point');
    allPts.forEach(pt => pt.elements.forEach(el => this.resetElementState(el)));
  }

  resetElementState(element) {
    const [c0, c1] = element.shape.getChildren();
    c0.stopAnimate();
    c1.stopAnimate();
    const { r: r0, opacity: op0 } = c0.get('attrs');
    c0.attr({ r: r0, opacity: op0 });
    const { r: r1, opacity: op1 } = c1.get('attrs');
    c1.attr({ r: r1, opacity: op1 });
  }

  getView() {
    return this.context.view;
  }
}

registerAction('marker-action-control', MarkerControl);
registerInteraction('custom-marker-interact', {
  start: [{ trigger: 'tooltip:show', action: 'marker-action-control:active' }],
  end: [{ trigger: 'tooltip:hide', action: 'marker-action-control:reset' }],
});

const customInteractChart = new Line('mount-point-2', {
  data: customDataSet,
  xField: 'year',
  yField: 'value',
  label: {},
  point: {
    size: 5,
    shape: 'double-ring',
    style: { fill: 'white', stroke: '#5B8FF9', lineWidth: 2 },
  },
  tooltip: { showMarkers: false },
  state: {
    active: { style: { shadowBlur: 4, stroke: '#000', fill: 'red' } },
  },
  interactions: [{ type: 'custom-marker-interact' }],
});

customInteractChart.render();

Tags: g2plot line-chart visualization javascript antv

Posted on Wed, 02 Sep 2026 16:27:37 +0000 by Clarkeez