带复选框的 highcharts 图例、事件、悬停样式、符号顺序更改

np8igboo  于 2022-11-10  发布在  Highcharts
关注(0)|答案(2)|浏览(330)

我目前在我的应用程序中的Chart组件中实现了Highcharts,但我需要对Legend进行一些更改,浏览了大部分文档,使用Highcharts.wrap()创建了一些函数。
第一,传说很简单,每个传说物品都
[Symbol] [Label]. x1c 0d1x
但现在我需要把它改成:
[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,复选框将位于每个标签的右侧,这并不理想。因此,需要这样做:(* 如果可能的话,我还想知道在这种情况下如何避免任何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

  • 〉在legends选项中使用rtl: true:x1c4d 1x指令集
    复选框的距离我理解,因为它需要更改我的legendCheckboxPosition函数,这里我真实的的问题是图例的顺序被更改了,比如如果我使用legend.reversed: true..我发现我可以使用reversed属性来修复这个问题,但我想知道这是否是其他方面的错误..因为在文档中,rtl属性只更改了SymbolLabel的顺序,而不是传说秩序。
    这就是我所需要的:

1.我需要在复选框的:hover中放置一个样式,我尝试使用legend.itemCheckboxStyle,但它不允许我添加悬停效果...(我需要在悬停复选框时放置一个框阴影)

*解决了一个问题:另一个问题是在单击图例项时(与复选框分开)单击图例项时,它显示/隐藏序列,但不会更改复选框选择。我知道复选框选择由series.selected属性确定,并且我在plotOptions.series.events中有legendItemClick事件,但在plotOptions.series.events中没有this.setSelected函数。只有this.setVisible函数。我试着使用它,但它似乎冻结了图表,没有做任何事情。如何改变复选框的选择时,只在图例项目点击?
编辑:通过将此事件添加到options.plotOptions.series.events,设法解决此问题:

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

那是我的问题希望你们能帮我解决

oipij1gg

oipij1gg1#

排列图例元素的一种可能方法是在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/

qyyhg6bp

qyyhg6bp2#

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

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

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);
}

这将:

  • 当系列隐藏或图例未聚焦时,避免更改图例和符号的颜色
  • 将复选框正确定位到图例的左侧
  • 切换SVG中符号和标签的位置

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

相关问题