Add symbol to custom legend layout - Highcharts React

自闭症网瘾萝莉.ら 提交于 2020-12-15 07:53:07

问题


I have managed to create a custom legend to display the series under each category in the legend. I am able to access the name, however I am not able to get the symbol to render along with the name in the legend. Please advice.

import React, { Component } from "react";
import * as Highcharts from "highcharts";
import HighchartsReact from "highcharts-react-official";
import HC_more from "highcharts/highcharts-more";
import HC_exporting from "highcharts/modules/exporting";
import HC_series_label from "highcharts/modules/series-label";
import HC_boost from "highcharts/modules/boost";
import ReactDOM from "react-dom";
import { map, uniq, slice, filter, keyBy, uniqueId, at } from "lodash";
import { Menu, MenuDivider, MenuItem } from "@blueprintjs/core";
import { Row, Col } from "react-bootstrap";
import * as htmlToImage from "html-to-image";
import { saveAs } from "file-saver";

HC_more(Highcharts);
HC_exporting(Highcharts);
HC_series_label(Highcharts);
HC_boost(Highcharts);

const colors = [
  "#800000",
  "#9A6324",
  "#808000",
  "#469990",
  "#000075",
  "#e6194b",
  "#f58231",
  "#ffe119",
  "#bfef45",
  "#3cb44b",
  "#42d4f4",
  "#4363d8",
  "#911eb4",
  "#f032e6"
];

class Chart extends Component {
  constructor(props) {
    super(props);
    const scenariosData = uniq(map(props.data.Series, "scenario"));
    this.state = {
      scenariosData
    };
    this.afterChart = this.afterChart.bind(this);
  }

  componentDidMount() {
    const scenariosData = uniq(map(this.props.data.Series, "scenario"));
    const mappedList = map(
      uniq(map(this.props.data.Series, "scenario")),
      (item) => {
        return {
          name: item,
          ids: map(filter(this.props.data.Series, ["scenario", item]), (data) =>
            data.id.toString()
          )
        };
      }
    );
    this.setState(
      {
        scenariosData,
        mappedList
      },
      () => {
        if (this.state.scenariosData.length === 1) {
          const legendAreaContainer = document.querySelector("#legendArea");
          ReactDOM.unmountComponentAtNode(legendAreaContainer);
        } else {
          if (scenariosData.length > 1) {
            const mappedNewList = keyBy(
              this.internalChart.series,
              "userOptions.id"
            );
            const groupedData = map(mappedList, ({ ids, ...item }) => ({
              ...item,
              data: at(mappedNewList, ids)
            }));
            this.internalChart.series.forEach((item) => {
              const menu = (
                // <Row>
                //   {map(this.state.mappedList, (scenario) => {
                //     return (
                //       <Col key={uniqueId()}>
                //         <Menu className="text-center">
                //           <MenuDivider title={scenario.name} />
                //           {scenario.ids.map((i) => {
                //             return (
                //               <MenuItem
                //                 key={uniqueId()}
                //                 text={`${i} - ${
                //                   this.props.data.Series.find(
                //                     (j) => j.id === Number(i)
                //                   ).segment
                //                 }`}
                //                 style={{
                //                   opacity: item.opacity,
                //                   color: colors[Number(i)]
                //                 }}
                //                 onClick={() => {
                //                   alert(item.userOptions.id === Number(i));
                //                   item.setVisible(!item.visible);
                //                   item.opacity = item.visible ? 1 : 0.3;
                //                 }}
                //               />
                //             );
                //           })}
                //         </Menu>
                //       </Col>
                //     );
                //   })}
                // </Row>
                <div className="row">
                  {map(groupedData, (scenario) => {
                    return (
                      <div key={uniqueId()} className="col">
                        <Menu className="text-center">
                          <MenuDivider title={scenario.name} />
                          {scenario.data.map((item) => {
                            return (
                              <MenuItem
                                key={uniqueId()}
                                text={
                                  <div
                                    style={{
                                      backgroundColor: item.color,
                                      opacity: item.visible ? 1 : 0.3
                                    }}
                                  >
                                    <div id="symbol">{item.name}</div>
                                  </div>
                                }
                                labelElement={item.userOptions.id}
                                onClick={() => {
                                  item.setVisible(!item.visible);
                                }}
                              />
                            );
                          })}
                        </Menu>
                      </div>
                    );
                  })}
                </div>
              );
              ReactDOM.render(menu, document.getElementById("legendArea"));
            });
          }
        }
      }
    );
  }

  componentDidUpdate(prevProps) {
    if (prevProps.data !== this.props.data) {
      const scenariosData = uniq(map(this.props.data.Series, "scenario"));
      const mappedList = map(
        uniq(map(this.props.data.Series, "scenario")),
        (item) => {
          return {
            name: item,
            ids: map(
              filter(this.props.data.Series, ["scenario", item]),
              (data) => data.id.toString()
            )
          };
        }
      );
      this.setState(
        {
          scenariosData,
          mappedList
        },
        () => {
          if (this.state.scenariosData.length === 1) {
            const legendAreaContainer = document.querySelector("#legendArea");
            ReactDOM.unmountComponentAtNode(legendAreaContainer);
          } else {
            if (scenariosData.length > 1) {
              const mappedNewList = keyBy(
                this.internalChart.series,
                "userOptions.id"
              );
              const groupedData = map(
                this.state.mappedList,
                ({ ids, ...item }) => ({
                  ...item,
                  data: at(mappedNewList, ids)
                })
              );
              console.log("groupedData", groupedData);
              this.internalChart.series.forEach((item) => {
                const menu = (
                  <div className="row">
                    {map(groupedData, (scenario) => {
                      return (
                        <div key={uniqueId()} className="col">
                          <Menu className="text-center">
                            <MenuDivider title={scenario.name} />
                            {scenario.data.map((item) => {
                              return (
                                <MenuItem
                                  key={uniqueId()}
                                  text={
                                    <div
                                      style={{
                                        backgroundColor: item.color,
                                        opacity: item.visible ? 1 : 0.3
                                      }}
                                    >
                                      <div id="symbol">{item.name}</div>
                                    </div>
                                  }
                                  labelElement={item.userOptions.id}
                                  onClick={() => {
                                    item.setVisible(!item.visible);
                                  }}
                                />
                              );
                            })}
                          </Menu>
                        </div>
                      );
                    })}
                  </div>
                );
                ReactDOM.render(menu, document.getElementById("legendArea"));
              });
            }
          }
        }
      );
    }
  }

  afterChart(chart) {
    this.internalChart = chart;
    this.forceUpdate();
  }

  render() {
    const options = {
      chart: {
        zoomType: "x",
        resetZoomButton: {
          position: {
            align: "left", // by default
            verticalAlign: "top", // by default
            x: -10,
            y: 10
          }
        },
        type: "line",
        height: this.props.height ? this.props.height : `60%`,
        events: {}
      },
      exporting: {
        menuItemDefinitions: {
          // Custom definition
          label: {
            onclick: function () {
              htmlToImage
                .toBlob(document.getElementById("chartContainer"))
                .then(function (blob) {
                  saveAs(blob, "my-node.png");
                });
            },
            text: "Download png"
          }
        },
        buttons: {
          contextButton: {
            menuItems: ["label"]
          }
        }
      },
      title: {
        text: this.props.title
      },
      subtitle: {
        text: ""
      },
      yAxis: {
        title: {
          text: null
        },
        labels: {
          formatter: function () {
            const self = this;
            return Highcharts.numberFormat(self.value / 1, 0, ".");
          },
          style: {
            fontSize: "13px"
          }
        }
      },
      legend:
        this.state.scenariosData.length > 1
          ? {
              enabled: false
            }
          : {
              enabled: true,
              itemStyle: {
                fontSize: "15px"
              }
            },
      credits: {
        enabled: false
      },
      xAxis: {
        categories: map(this.props.data.Dates, (item) => item.Date),
        labels: {
          style: {
            fontSize: "13px"
          }
        }
      },
      plotOptions: {
        series: {
          boostThreshold: 2000,
          label: {
            enabled: false,
            connectorAllowed: false
          },
          marker: {
            enabled: false
          }
        }
      },
      tooltip: {
        pointFormatter: function () {
          return Highcharts.numberFormat(this.options.y / 1, 0, ".");
        }
      },
      series: map(slice(this.props.data.Series, 0, 15), (item, index) => {
        return {
          name: this.state.scenariosData.length > 1 ? item.segment : item.name,
          data: item.values,
          type: this.props.chartType,
          id: item.id.toString(),
          color: colors[item.id - 1]
        };
      })
    };
    return (
      <div id="chartContainer">
        <HighchartsReact
          highcharts={Highcharts}
          options={options}
          callback={this.afterChart}
          {...this.props}
        />
        <div id="legendArea" />
      </div>
    );
  }
}

export default Chart;

Please advice.

This is my codesandbox link: https://codesandbox.io/s/intelligent-fog-cds4u?file=/src/Chart.jsx:0-12135

Expected Legend:


回答1:


I am not sure how the final layout should look like so I added just the symbol without any centering in your columns, please take a look:

https://codesandbox.io/s/bitter-currying-ibkdv

<div id="symbol">
  {" "}
  <div
    style={{
      backgroundColor: item.color,
      width: "20px",
      height: "20px",
      float: "left",
      borderRadius: "10px"
    }}
  ></div>
  {item.name}
</div>


来源:https://stackoverflow.com/questions/64811381/add-symbol-to-custom-legend-layout-highcharts-react

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!