繁体   English   中英

Highchart Legend with Checkbox, events, hover style, symbol order change

[英]Highchart Legend with Checkbox, events, hover style, symbol order change

我目前在我的应用程序的Chart组件中实现了 Highcharts,但我需要对图例进行一些更改,浏览大部分文档,使用Highcharts.wrap()创建一些函数。

首先,Legend 很简单,每个 Legend 项目都是

[Symbol] [Label] 在此处输入图像描述

但现在我需要将其更改为:

[Checkbox] [Label] [Symbol] 在此处输入图像描述

这是我到目前为止得到的:

[Checkbox] [Symbol] [Label] 在此处输入图像描述

并单击复选框复制单击图例(符号,标签),显示/隐藏系列线。

如何? 用这个:(仅显示重要部分)

const defaultOptions: Highcharts.Options = {
    ...,
    legend: {
        borderColor: "transparent",
        verticalAlign: "top",
        align: "left",
        x: 14,
        itemCheckboxStyle: {
            cursor: "pointer",
            border: "1px solid #62737a",
        },
    },
    ...,
    plotOptions: {
        series: {
            ...,
            showCheckbox: true,
            selected: true,
            events: {
                checkboxClick: function () {
                    this.setVisible(!this.visible);
                },
            },
        },
        ...,
    },
...,
}

如果我们只使用showCheckbox: true ,那么复选框将在每个 label 的右侧很远,并不理想。 所以这是需要的:(如果可能的话,我还想知道在这种情况下如何避免 TS 上的任何错误的提示,没有评论)。

Highcharts.wrap(Highcharts.Legend.prototype, "positionCheckboxes", legendCheckboxPosition);
function legendCheckboxPosition(
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    this: any,
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    p: any,
    scrollOffset: number
) {
    const alignAttr = this.group.alignAttr;
    const clipHeight = this.clipHeight || this.legendHeight;
    let translateY: number;

    if (alignAttr) {
        translateY = alignAttr.translateY;
        Highcharts.each(
            this.allItems,
            function (item: {
                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                checkbox: any;
                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                legendItem: { getBBox: (arg0: boolean) => any };
                // eslint-disable-next-line @typescript-eslint/no-explicit-any
                checkboxOffset: any;
            }) {
                const checkbox = item.checkbox;
                const bBox = item.legendItem.getBBox(true);
                let top;

                if (checkbox) {
                    top = translateY + checkbox.y + (scrollOffset || 0) + 2;
                    Highcharts.css(checkbox, {
                        left:
                            alignAttr.translateX +
                            item.checkboxOffset +
                            checkbox.x -
                            100 -
                            bBox.width +
                            17 +
                            "px",
                        top: top + "px",
                        display: top > translateY - 6 && top < translateY + clipHeight - 6 ? "" : "none",
                    });
                }
            }
        );
    }
}

但是完成此操作后,我仍然需要进行一些更改,它们是:

  1. 更改SymbolLabel的顺序legends选项中应该有一个rtl属性,它应该更改SymbolLabel的顺序,但是如果我这样做,它会反转,但它也会反转图例的顺序不知何故,我会展示:->没有rtl 没有 rtl 选项为真

-> 使用rtl: truelegends选项中: 在此处输入图像描述

我理解的复选框距离,因为它需要更改我的legendCheckboxPosition function,我真正的问题是更改图例的顺序,就像我使用legend.reversed: true一样。我发现我可以使用reversed属性要解决这个问题,但我想知道这是否是其他问题的错误..因为在文档中rtl属性仅更改SymbolLabel的顺序,而不是图例的顺序。

这就是我需要的: 在此处输入图像描述

  1. 我需要在复选框的:hover中添加一个样式,我尝试使用legend.itemCheckboxStyle但这不允许我添加hover效果...(悬停复选框时我需要放置一个框阴影)
  • 一个问题已解决:另一个问题是单击图例项(与复选框分开)时单击图例项时,它会显示/隐藏系列,但不会更改复选框选择。 我知道复选框选择由series.selected属性确定,并且我在plotOptions.series.events中有legendItemClick事件,但在里面我没有this.setSelected ,只有this.setVisible function。 我尝试使用它,但它似乎冻结了图表,没有做任何事情。 仅在图例项中单击时如何更改复选框选择?

编辑:设法通过将此事件添加到options.plotOptions.series.events来解决此问题:

legendItemClick: function () {
    const seriesIndex = this.index;
    this.chart.series[seriesIndex].select();
},

嗯..这是我的问题,希望你们能帮助我解决它。

安排图例元素的一种可能方法是在legend.labelFormatter中编辑图例并添加 Unicode 行字符。 要使右侧的复选框也可以在legend.itemCheckboxStyle中设置样式。

  legend: {
    symbolWidth: 0,
    useHTML: true,
    labelFormatter: function() {
      return `<div>${this.name}<span style="color: green;">&#9473;</span></div>`;
    },
    itemDistance: 50,
    itemCheckboxStyle: {
      "width": "13px",
      "height": "13px",
      "margin-left": "-130px",
      "position": "absolute"
    }
  },

API 参考文献:

https://api.highcharts.com/highcharts/legend.itemCheckboxStyle

演示: https://jsfiddle.net/BlackLabel/sbcL7rp9/3/

经过大量的研究和实验,我设法让这一切正常工作。

选项(默认选项和事件,还切换加载可见性)

const series = GetSeries(opts, null);
...
// Check if Series is supposed to be hidden from load (from the checkbox selected prop), if it is, hide it
series.forEach((serie) => {
    if (serie.selected !== undefined && serie.selected === false) serie.visible = false;
});

const defaultOptions: Highcharts.Options = {
    ...,
    legend: {
        borderColor: "transparent",
        verticalAlign: "top",
        align: "left",
        x: 14,
    },
    ...,
    plotOptions: {
        series: {
            ...
            showCheckbox: true,
            selected: true,
            events: {
                checkboxClick: function () {
                    this.setVisible(!this.visible);
                },
                legendItemClick: function () {
                    const seriesIndex = this.index;
                    this.chart.series[seriesIndex].select();
                },
            },
        },
        ...
    },
    ...
};

return mergeObjects(defaultOptions, opts);
}

并且很多解决扩展 Highcharts

// Adjust position of the Highchart Legend Checkbox, and switch label and symbol in the legend
function legendPositionAdjustments(
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    this: any,
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    p: any,
    scrollOffset: number
) {
    const pixelsToREM = (value: number) => {
        return value / 16;
    };
    const alignAttr = this.group.alignAttr;
    const clipHeight = this.clipHeight || this.legendHeight;
    let translateY: number;
const legendMainElement = this.box.parentGroup.element;
// Adjust the main legend element to be closer to the checkbox
if (legendMainElement) {
    Highcharts.attr(legendMainElement, "transform", "translate(19, 10)");
}
if (alignAttr) {
    translateY = alignAttr.translateY;
    this.allItems.forEach(function (item: {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        checkbox: any;
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        legendItem: { getBBox: (arg0: boolean) => any };
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        checkboxOffset: any;
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        legendGroup: any;
    }) {
        const bBox = item.legendItem.getBBox(true);

        // Change position of Label and Symbol in the Highcharts Legend
        const legendItemElement = item.legendGroup.element;
        const legendItemPath = legendItemElement.querySelector("path.highcharts-graph");
        const legendItemPoint = legendItemElement.querySelector("path.highcharts-point");
        const legendItemText = legendItemElement.querySelector("text");
        if (legendItemPath) {
            Highcharts.attr(legendItemPath, "transform", `translate(${bBox.width + 3}, 0)`);
        }
        if (legendItemPoint) {
            Highcharts.attr(legendItemPoint, "transform", `translate(${bBox.width + 3}, 0)`);
        }
        if (legendItemText) {
            Highcharts.attr(legendItemText, "x", 0);
        }

        // Adjust the position of the checkbox to the left side of the Highcharts Legend
        const checkbox = item.checkbox;
        let top;
        let left;
        if (checkbox) {
            top = translateY + checkbox.y + (scrollOffset || 0) + 4;
            left = alignAttr.translateX + item.checkboxOffset + checkbox.x - 100 - bBox.width + 17;
            Highcharts.css(checkbox, {
                left: pixelsToREM(left) + "rem",
                top: pixelsToREM(top) + "rem",
                display: top > translateY - 6 && top < translateY + clipHeight - 6 ? "" : "none",
            });
        }
    });
}
}

// This function is called when triggering show/hide of series, always calling with visibility = true
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
function colorizeLegendRegardlessOfVisibility(this: any, proceed: any, item: any, visible: any) {
    proceed.call(this, item, true);
}

这将:

  • 当系列被隐藏或图例失焦时,避免更改图例和符号的颜色
  • 更正 position 图例左侧的复选框
  • 符号和label的开关位置,在SVG中

希望对以后遇到类似问题的人有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM