interaction/multi-view/focus-context

Example page

import { Chart } from '@antv/g2';

document.getElementById('container').innerHTML = `
<div id="focus" ></div>
<div id="context"></div>
`;

// Render focus View.
const focus = new Chart({
  container: 'focus',
  height: 360,
  paddingLeft: 60,
});

const dataSource = {
  type: 'fetch',
  value:
    'https://gw.alipayobjects.com/os/bmw-prod/551d80c6-a6be-4f3c-a82a-abd739e12977.csv',
};

focus.options({
  type: 'area',
  data: dataSource,
  encode: { x: 'date', y: 'close' },
  animate: false,
  axis: {
    x: { grid: false, title: false, tickCount: 5 },
    y: { grid: false, tickCount: 5 },
  },
  interaction: { tooltip: false, brushXFilter: true },
});

focus.render();

// Render context View.
const context = new Chart({
  container: 'context',
  paddingTop: 0,
  paddingBottom: 0,
  height: 90,
  paddingLeft: 60,
});

context.options({
  type: 'area',
  data: dataSource,
  encode: { x: 'date', y: 'close' },
  animate: false,
  axis: false,
  interaction: {
    tooltip: false,
    brushXHighlight: {
      series: true,
      maskOpacity: 0.3,
      maskFill: '#777',
      maskHandleWRender: createPathRender((x, y, width, height) => ({
        d: 'M-0.5,31.5c-2.5,0,-4.5,2,-4.5,4.5v30c0,2.5,2,4.5,4.5,4.5V31.5z',
        transform: `translate(${x + width / 2}, ${y - height / 2})`,
      })),
      maskHandleERender: createPathRender((x, y, width, height) => ({
        d: 'M0.5,31.5c2.5,0,4.5,2,4.5,4.5v30c0,2.5,-2,4.5,-4.5,4.5V31.5z',
        transform: `translate(${x + width / 2}, ${y - height / 2})`,
      })),
      maskHandleEFill: '#D3D8E0',
      maskHandleWFill: '#D3D8E0',
    },
  },
});

context.render();

function createPathRender(compute) {
  return (group, options, document) => {
    if (!group.handle) {
      const path = document.createElement('path');
      group.handle = path;
      group.appendChild(group.handle);
    }
    const { handle } = group;
    const { x, y, width, height, ...rest } = options;
    if (width === undefined || height === undefined) return handle;
    handle.attr({ ...compute(x, y, width, height), ...rest });
    return handle;
  };
}

// Add event listeners  to communicate.
focus.on('brush:filter', (e) => {
  const { nativeEvent } = e;
  if (!nativeEvent) return;
  const { selection } = e.data;
  const { x: scaleX } = focus.getScale();
  const [[x1, x2]] = selection;
  const domainX = scaleX.getOptions().domain;
  if (x1 === domainX[0] && x2 === domainX[1]) {
    context.emit('brush:remove', {});
  } else {
    context.emit('brush:highlight', { data: { selection } });
  }
});

context.on('brush:highlight', (e) => {
  const { nativeEvent, data } = e;
  if (!nativeEvent) return;
  const { selection } = data;
  focus.emit('brush:filter', { data: { selection } });
});

context.on('brush:remove', (e) => {
  const { nativeEvent } = e;
  if (!nativeEvent) return;
  const { x: scaleX, y: scaleY } = context.getScale();
  const selection = [scaleX.getOptions().domain, scaleY.getOptions().domain];
  focus.emit('brush:filter', { data: { selection } });
});