VisActor / VChart

VChart, more than just a cross-platform charting library, but also an expressive data storyteller.
https://www.visactor.io/vchart
MIT License
775 stars 45 forks source link

[Feature] indicator component can be updated by api or `updateSpec` #2776

Closed xile611 closed 2 days ago

xile611 commented 4 weeks ago

What problem does this feature solve?

the update problem of indicator

const pieData = [
        { type: 'oxygen', value: '46.60' },
        { type: 'silicon', value: '27.72' },
        { type: 'aluminum', value: '8.13' },
        { type: 'iron', value: '5' },
        { type: 'calcium', value: '3.63' },
        { type: 'sodium', value: '2.83' },
        { type: 'potassium', value: '2.59' },
        { type: 'others', value: '3.5' }
      ];
const spec = {
  type: 'pie',
  data: [
    {
      id: 'id0',
      values: pieData
    }
  ],
  outerRadius: 0.8,
  innerRadius: 0.5,
  padAngle: 0.6,
  valueField: 'value',
  categoryField: 'type',
  pie: {
    style: {
      stroke: (datum, chart) => {
        return [chart.globalScale('color', datum.type), false, false, false];
      },
      lineWidth: 0,
      strokeOpacity: 0.5
    },
    state: {
      cutomizedLegendHover: {
        lineWidth: 20,
        outerBorder: {
          visible: true,
          distance: 0.5,
          stroke: '#fff'
        }
      },

      hover: {
        lineWidth: 20,
        outerBorder: {
          visible: true,
          distance: 0.5,
          stroke: '#fff'
        }
      },
      selected: {
        lineWidth: 20,
        outerBorder: {
          visible: true,
          distance: 0.5,
          stroke: '#fff'
        }
      }
    }
  },
  title: {
    visible: true,
    text: 'Statistics of Surface Element Content'
  },
  legends: {
    visible: true,
    orient: 'left'
  },
  label: {
    visible: true,
    layout: {
      strategy: 'priority',
      tangentConstraint: false
    },
    position: 'inside'
  },
  tooltip: {
    mark: {
      content: [
        {
          key: datum => datum['type'],
          value: datum => datum['value'] + '%'
        }
      ]
    }
  },
  indicator: {
    visible: true,
    trigger: 'select',
    title: {
      visible: true,
      style: {
        fontSize: 18,
        text: data => {
          if (data) {
            const value = data['type'];
            return value ? value : null;
          }
          return '总和';
        }
      }
    },
    content: [
      {
        visible: true,
        style: {
          fontSize: 18,
          text: (data, b, c) => {
            if (data) {
              const value = data['value'];
              return value ? `${value}%` : null;
            }

            return pieData.reduce((sum, entry) => {
              return sum + +(entry.value);
            }, 0);
          }
        }
      }
    ]
  }
};

const vchart = new VChart(spec, { dom: CONTAINER_ID, enableHtmlAttribute: true });
vchart.renderSync();
const firstType = spec.data[0].values[0].type;

if (firstType) {
  vchart.updateState({
    cutomizedLegendHover: {
      filter: datum => datum.type === firstType
    }
  });
}

vchart.on('legendItemHover', e => {
  const activeId = e && e.value && e.value.data && e.value.data.id;

  if (activeId) {
    vchart.updateState({
      cutomizedLegendHover: {
        filter: datum => datum.type === activeId
      }
    });
  }
});

vchart.on('legendItemUnHover', e => {
  vchart.updateState({
    cutomizedLegendHover: {
      filter: datum => false
    }
  });
});

vchart.on('legendSelectedDataChange',  e => {
  const selected = vchart.getLegendSelectedDataByIndex() || [];
  const sum = selected.reduce((sum, s) => {
    return sum + +data.find(entry => entry.type === s)?.value ?? 0;
  }, 0);

  vchart.updateSpec({
    ...spec,
    indicator: {
      visible: true,
      trigger: 'select',
      title: {
        visible: true,
        style: {
          fontSize: 18,
          text: data => {
            if (data) {
              const value = data['type'];
              return value ? value : null;
            }
            return '总和';
          }
        }
      },
      content: [
        {
          visible: true,
          style: {
            fontSize: 18,
            text: (data, b, c) => {
              if (data) {
                const value = data['value'];
                return value ? `${value}%` : null;
              }

              return sum;
            }
          }
        }
      ]
    }
  });
});

// Just for the convenience of console debugging, DO NOT COPY!
window['vchart'] = vchart;

img_v3_02bh_c572f129-fbe9-4858-9a86-2859775ad2fg

What does the proposed API look like?

interface IVChart {
  updateDatumOfIndicator: (datum) => {
   //
  }
}