g2 5.0 靶子

257 阅读3分钟

突发奇想,想要记录最近自己射箭的成绩,并且分析自己在哪些地方有些不对的地方,好调整姿势。

靶子

首先我们需要一个靶子。在射箭中,靶子的种类很多,有标准 10 的靶子,也有 3 * 5 的靶子。先使用标准的靶子进行记录。

image.png

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

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  autoFit: true,
});

chart.coordinate({
  type: 'radial',
  endAngle: Math.PI,
  startAngle: -Math.PI,
});

chart
  .rect()
  .data([
    { name: [0, 1], color: '#f5f5f5' },
    { name: [1, 2], color: '#f5f5f5' },
    { name: [2, 3], color: '#000' },
    { name: [3, 4], color: '#000' },
    { name: [4, 5], color: '#64eef5' },
    { name: [5, 6], color: '#64eef5' },
    { name: [6, 7], color: 'red' },
    { name: [7, 8], color: 'red' },
    { name: [8, 9], color: '#f0f564' },
    { name: [9, 10], color: '#f0f564' },
  ])
  .encode('x', 'name')
  .encode('y', Math.PI)
  .style('fill', 'color')
  .style('stroke', '#fff')
  .style('inset', 10)
  .scale('x', {
    range: [1, 0]
  })
  .axis('x', false)
  .axis('y', false)
  .label({
    text: 'name',
    position: 'outside',
    dx: -4,
    formatter: (v) => {
      return v[1];
    },
    transform: [
      {
        type: 'contrastReverse',
      },
    ],
  });

chart.render();

打的数据

然后创建一个通过 r 距离点中心点半径, angle 和角度, 通过 mask.point 记录成绩的位置。

image.png

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

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  autoFit: true,
});

const data = new Array(100).fill().map(() => ({
  // 射击 随机距离中心点的距离
  r: Math.random() * 9 + 1,
  // 射击 角度
  angle: Math.random() * Math.PI,
}));

chart.coordinate({
  type: 'radial',
  startAngle: -Math.PI,
  endAngle: Math.PI,
});

chart
  .point()
  .data(data)
  .encode('x', 'r')
  .encode('y', 'angle')
  .axis('y', {
    line: true,
    grid: true,
  })
  .axis('x', {
    title: false,
  })

chart.render();

结合一下

image.png 这样就直观的看到最近的成绩

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

const chart = new Chart({
  container: 'container',
  theme: 'classic',
  autoFit: true,
});
// 随机数据,搞不到数据
const data = new Array(100).fill().map(() => {
  let r = Math.random() * 9 + 1;
  if (r < 8) {
    r = Math.random() * 9 + 1;
  }
  if (r < 5) {
    r = Math.random() * 9 + 1;
  }

  let angle = Math.random() * Math.PI;

  if (angle > Math.PI / 2) {
    angle = Math.random() * Math.PI;
  }

  if (angle > Math.PI / 2) {
    angle = Math.random() * Math.PI;
  }

  return {
    // 射击 随机距离中心点的距离
    r,
    // 射击 角度
    angle,
  }
});

chart.coordinate({
  type: 'radial',
  startAngle: -Math.PI,
  endAngle: Math.PI,
});

chart
  .rect()
  .data([
    { name: [0, 1], color: '#f5f5f5' },
    { name: [1, 2], color: '#f5f5f5' },
    { name: [2, 3], color: '#000' },
    { name: [3, 4], color: '#000' },
    { name: [4, 5], color: '#64eef5' },
    { name: [5, 6], color: '#64eef5' },
    { name: [6, 7], color: 'red' },
    { name: [7, 8], color: 'red' },
    { name: [8, 9], color: '#f0f564' },
    { name: [9, 10], color: '#f0f564' },
  ])
  .encode('x', 'name')
  .encode('y', Math.PI)
  .style('fill', 'color')
  .style('stroke', '#fff')
  .style('inset', 10)
  .scale('x', {
    range: [1, 0]
  })
  .axis('x', false)
  .axis('y', false)
  .tooltip(false)
  .label({
    text: 'name',
    position: 'outside',
    dx: -4,
    formatter: (v) => {
      return v[1];
    },
    style: {
      fontSize: 16,
    },
    transform: [
      {
        type: 'contrastReverse',
      },
    ],
  });

chart
  .point()
  .data(data)
  .encode('x', 'r')
  .encode('y', 'angle')
  .axis('y', false)
  .axis('x', false)
  .style({
    fill: '#fff',
  })

chart.render();

记录每组成绩

通过 Feact 复合视图,进行成绩的记录

image.png

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

// 随机数据,搞不到数据
const getData = (id) => new Array(12).fill().map(() => {
  let r = Math.random() * 9 + 1;
  if (r < 8) {
    r = Math.random() * 9 + 1;
  }
  if (r < 5) {
    r = Math.random() * 9 + 1;
  }

  let angle = Math.random() * Math.PI;

  if (angle > Math.PI / 2) {
    angle = Math.random() * Math.PI;
  }

  if (angle > Math.PI / 2) {
    angle = Math.random() * Math.PI;
  }

  return {
    id,
    // 射击 随机距离中心点的距离
    r,
    // 射击 角度
    angle,
  }
});

const data = new Array(3).fill().map((v, idx) => {
  return getData(idx + 1)
}).flat();

const chart = new Chart({
  container: 'container',
  theme: 'classic',
});

const facetRect = chart
  .facetRect()
  .data(data)
  .encode('x', 'id')
  .axis('x', {
    labelFormatter: (v) => {
      const d = data.reduce((value, item) => {
        if (item.id === v) {
          value += Math.floor(item.r);
        }
        return value;
      }, 0)
      return `${d}分`;
    },
    labelOpacity: 1,
    labelFontSize: 16,
    title: false,
  });

facetRect
  .rect()
  .coordinate({ type: 'theta' })
  .data([
    { name: [0, 1], color: '#f5f5f5' },
    { name: [1, 2], color: '#f5f5f5' },
    { name: [2, 3], color: '#000' },
    { name: [3, 4], color: '#000' },
    { name: [4, 5], color: '#64eef5' },
    { name: [5, 6], color: '#64eef5' },
    { name: [6, 7], color: 'red' },
    { name: [7, 8], color: 'red' },
    { name: [8, 9], color: '#f0f564' },
    { name: [9, 10], color: '#f0f564' },
  ])
  .encode('x', 'name')
  .encode('y', Math.PI)
  .style('fill', 'color')
  .style('stroke', '#fff')
  .style('inset', 10)
  .axis('x', false)
  .axis('y', false)
  .tooltip(false);

facetRect
  .point()
  .coordinate({ type: 'theta' })
  .encode('x', 'r')
  .encode('y', 'angle')
  .axis('y', false)
  .axis('x', false)
  .style({
    fill: '#fff',
  });

chart.render();