【问题标题】:Html5 line chart with a different color when out of area range超出区域范围时具有不同颜色的 Html5 折线图
【发布时间】:2014-04-16 10:16:31
【问题描述】:

我想在一个图表上绘制一个区域范围图表和一条线,我希望该线在区域范围内时为黑色,而在区域范围外时为红色,如图所示。

我使用下面的代码来绘制区域范围,但我不知道如何让它在区域范围之外绘制不同颜色的线。 http://jsfiddle.net/2cVGX/

        $(function () {

        var limits = [
                [64064, 14.3, 27.7],
                [64928, 14.5, 27.8],
                [65792, 15.5, 29.6],
                [66656, 16.7, 30.7],
                [67520, 16.5, 25.0],
                [68384, 17.8, 25.7],
                [69248, 13.5, 24.8],
                [70112, 10.5, 21.4],
                [70976, 09.2, 23.8],
                [71840, 11.6, 21.8],
                [72704, 10.7, 23.7],
                [73568, 11.0, 23.3],
                [74432, 11.6, 23.7],
                [75296, 11.8, 20.7],
                [76160, 12.6, 22.4],
                [77024, 13.6, 19.6],
                [77888, 11.4, 22.6],
                [78752, 13.2, 25.0],
                [79616, 14.2, 21.6],
                [80480, 13.1, 17.1],
                [81344, 12.2, 15.5],
                [82208, 12.0, 20.8],
                [83072, 12.0, 17.1],
                [83936, 12.7, 18.3],
                [84800, 12.4, 19.4],
                [85664, 12.6, 19.9],
                [86528, 11.9, 20.2],
                [87392, 11.0, 19.3],
                [88256, 10.8, 17.8],
                [89120, 11.8, 18.5],
                [89984, 10.8, 16.1]
        ],
            values = [
                [64064, 21.5],
                [64928, 22.1],
                [65792, 23.0],
                [66656, 23.8],
                [67520, 21.4],
                [68384, 21.3],
                [69248, 18.3],
                [70112, 15.4],
                [70976, 16.4],
                [71840, 17.7],
                [72704, 17.5],
                [73568, 17.6],
                [74432, 17.7],
                [75296, 16.8],
                [76160, 17.7],
                [77024, 16.3],
                [77888, 17.8],
                [78752, 18.1],
                [79616, 17.2],
                [80480, 14.4],
                [81344, 13.7],
                [82208, 17.7],
                [83072, 20.6],
                [83936, 20.3],
                [84800, 19.3],
                [85664, 15.8],
                [86528, 15.2],
                [87392, 14.8],
                [88256, 14.4],
                [89120, 15],
                [89984, 13.6]
            ],

            targets = [
                [64064, 22.5],
                [64928, 23.1],
                [65792, 21.0],
                [66656, 22.8],
                [67520, 20.4],
                [68384, 22.3],
                [69248, 18.4],
                [70112, 15.5],
                [70976, 16.4],
                [71840, 17.6],
                [72704, 18.6],
                [73568, 19.6],
                [74432, 18.7],
                [75296, 17.8],
                [76160, 17.7],
                [77024, 16.5],
                [77888, 16.8],
                [78752, 17.1],
                [79616, 17.5],
                [80480, 15.4],
                [81344, 14.7],
                [82208, 16.7],
                [83072, 15.6],
                [83936, 15.3],
                [84800, 15.5],
                [85664, 15.8],
                [86528, 15.2],
                [87392, 15.8],
                [88256, 15.4],
                [89120, 15.3],
                [89984, 14.6]
            ];

        $('#container').highcharts({
            title: {
                text: null
            },
            xAxis: {
                title: {
                    text: null
                },
                type: 'linear',
                labels: {
                    enabled: false
                },
                lineWidth: 0,
                tickWidth: 0
            },

            yAxis: {
                title: {
                    text: null
                },
                labels: {
                    enabled: false
                },
                gridLineWidth: 0
            },

            tooltip: {
                crosshairs: true,
                shared: true,
                valueSuffix: 'Virt'
            },

            legend: {
                enabled: false
            },

            series: [{
                id: 'valueLine',
                name: 'Value',
                type: 'spline',
                data: values,
                zIndex: 1,
                color: 'black',
                shadow: true,

                marker: {
                    fillColor: 'black',
                    lineWidth: 1,
                    radius: 2,
                    lineColor: "white",
                    enabled: false,
                    symbol: 'circle'
                }
            }, {
                id: 'targetLine',
                name: 'Target',
                type: 'spline',
                data: targets,
                linkedTo: 'valueLine',
                zIndex: 1,
                color: 'gray',
                dashStyle: 'DashDot',
                marker: {
                    fillColor: 'gray',
                    lineWidth: 1,
                    radius: 2,
                    lineColor: "white",
                    enabled: false,
                    symbol: 'circle'
                }
            }, {
                id: 'limitsArea',
                name: 'Limits',
                data: limits,
                type: 'areasplinerange',
                lineWidth: 1,
                lineColor: 'gray',
                linkedTo: 'valueLine',
                color: "lightGray",
                fillOpacity: 0.3,
                zIndex: 0
            }]

        });

    });

【问题讨论】:

  • 简而言之:不支持。当然,您可以自行实现 - 找到系列交叉的点,然后为该点创建具有特定颜色的单独系列。
  • @mKlus 我的最后一次尝试让你接近你所需要的:)
  • @PawełFus 这个变通方法的问题是你不能用样条线和areasplinerange 来做,因为红色的新样条线不会有相同的形状。这里它是用lines和arearange来实现的。 jsfiddle.net/7NFY5
  • 如何使用两个系列(黑色下的红色)并在黑色超出区域范围时删除点?这应该可以解决问题。

标签: javascript html highcharts kendo-ui


【解决方案1】:

很遗憾,它不受支持。问题是线条被绘制为单个路径,并且每个路径只能有一种颜色(渐变除外)。

一些尝试导致Fiddle1 单个点的颜色发生变化,另一个基于阈值将渐变应用于路径的笔划

function applyGraphGradient() {

    // Options
    var threshold = 19,
        colorAbove = '#F00',
        colorBelow = '#000';

    // internal
    var series = this.series[0], 
        i,
        point;

    if (this.renderer.box.tagName === 'svg') {

        var translatedThreshold = series.yAxis.translate(threshold),
            y1 = Math.round(series.yAxis.len - translatedThreshold),
            y2 = y1 + 2; // 0.01 would be fine, but IE9 requires 2

        // Apply gradient to the path
        series.graph.attr({
            stroke: {
                linearGradient: [0, y1, 0, y2],
                stops: [
                    [0, colorAbove],
                    [1, colorBelow]
                ]
            }
         });
    }


    // Apply colors to the markers
    for (i = 0; i < series.data.length; i++) {
        point = series.data[i];
        point.color = point.y < threshold ? colorBelow : colorAbove;
        if (point.graphic) {
            point.graphic.attr({
                fill: point.color
            });
        }
    }

    // prevent the old color from coming back after hover
    delete series.pointAttr.hover.fill;
    delete series.pointAttr[''].fill;

}

fiddle2,感谢question

另一种可能的解决方案是以编程方式将您的数据分成 2 个系列,一个在范围内,一个不在范围内。通过将不是红色的颜色着色,它可能看起来是一条线

            var inRange = Array();
            var outRange = Array();

            for(var i = 0; i < values.length; i++) {
                var range = limits[i];
                var value = values[i];

                if(value[1] > range[1] && value[1] < range[2]) {
                     inRange.push(value);
                     outRange.push([value[0],null]);
                }
                else {
                    outRange.push(value);
                    inRange.push([value[0],null]);
                }
            }

Example,尽管如您所见,它们并没有结合在一起

更新

设法使其正确显示

            var inRange = Array();
            var outRange = Array();

            var prev = 0; //1 = was valid, 2 = werent
            for(var i = 0; i < values.length; i++) {
                var range = limits[i];
                var value = values[i];

                if(value[1] > range[1] && value[1] < range[2]) {
                     inRange.push(value);


                    if(prev == 2) {
                        outRange.push(value);
                    }
                    else {
                        outRange.push([value[0],null]);
                    }
                    prev = 1;
                }
                else {
                    outRange.push(value);
                    inRange.push([value[0],null]);

                    if(prev == 1) {
                       outRange[i-1][5] = values[i-1][6];
                    }

                    prev = 2;
                }

                console.log(prev);
            }

Example

【讨论】:

  • 感谢您的回答。正如您在此处显示的那样,我确实设法提出了“部分”解决方案。但是,我需要“值”行仅在超出区域范围时才为红色,而不像 jsfiddle.net/2cVGX/4 中那样。
  • 我只看到 2 个选项可以做到这一点: 1. 使用渐变色(正如您在帖子中提到的)。但是,如果使用 spline/areasplinerange(如果使用 line/arearange 会更容易),我不确定如何计算交点。 2. 绘制 2 个系列,但同样,如果使用 spline/areasplinerange,不知道该怎么做,因为 2 个连接的系列看起来与 1 个系列样条不同。
  • Fiddle1、Fiddle2 和 example 是 3 个选项(第一个只是为标记着色),是的,它并不完美,但它已经尽可能接近了。尽管从理论上讲,如果您计算出线在什么点从该区域出来并在每个系列中放置一个标记,那么您将得到您所需要的。虽然如何计算这超出了我的范围:)
猜你喜欢
  • 2016-08-27
  • 1970-01-01
  • 2013-03-03
  • 2020-05-25
  • 1970-01-01
  • 1970-01-01
  • 2019-07-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多