是否可以更改 Highcharts 中动画数字的颜色

Is it possible to change the color of animating digits in Highcharts

我有一个动态更新的标签,显示 Y 位置在变化时的动画。 我想根据变化的方向改变那些在变化过程中动画的数字的颜色和大小。 例如,如果数字更改为 150.41 --> 179.22 ,我希望“50.41”在过渡到“79.22”时字体更大,颜色为绿色,第一个数字“1”应保持原样。这是我的 fiddle http://jsfiddle.net/nrzxysjd/

 series.addPoint([x, y], true, true);

            d = pathLine.d.split(' ');
            d[2] = yAxis.toPixels(y);
            d[5] = yAxis.toPixels(y);

            plotbandLabel.animate({
              y: yAxis.toPixels(y) - labelOffset
            }, {
              duration: 500,
              step: function() {
                this.attr({
                  text: yAxis.toValue(this.y + labelOffset).toFixed(2),
                  zIndex: 999999999
                })
              },
              complete: function() {
                this.attr({
                  text: y.toFixed(2),
                  zIndex: 999999999
                })
              }
            });

            pathLine.animate({
              d: d
            }, 500);
          }, 1000);
        }/*,

首先需要在标签中启用HTML:

plotbandLabel = this.renderer.label(
    (66).toFixed(2),
    chart.plotLeft + chart.plotWidth,
    yAxis.toPixels(66) - labelOffset,
    'rect',
    null,
    true // here
)

然后当你添加一个新点时,你需要计算与最后一个点的增量,并相应地选择 CSS 样式:

let delta = y - series.yData[series.yData.length - 1],
style = { 'color': 'black', 'font-weight': 400 };
if (delta > 0) {
    style['color'] = 'green';
    style['font-weight'] = 700;
}
plotbandLabel.css(style);

这会设置整个标签的样式。现在您需要覆盖第一个数字的样式:

plotbandLabel.animate({
    y: yAxis.toPixels(y) - labelOffset
}, {
    duration: 500,
    step: function () {
         //turn the value to string and split it into 2 parts
        let t = '' + yAxis.toValue(this.y + labelOffset).toFixed(2),
            firstLetter = t[0],
            otherletters = t.substr(1);

        this.attr({
            //put the 1st digit into its own span
            //and override the label style with inline style
            text: '<span style="color:black;font-weight:400">' 
                  + firstLetter + '</span>' + otherletters,
            zIndex: 999999999
        })
    },
    complete: function () {
        let t = '' + y.toFixed(2),
            firstLetter = t[0],
            otherletters = t.substr(1);
        this.attr({
            text: '<span style="color:black;font-weight:400">' 
                  + firstLetter + '</span>' + otherletters,
            zIndex: 999999999
        })
    }
});

工作示例:

$(function() {
var chart, yAxis, plotbandLabel, pathLine
            labelOffset = 15;

  Highcharts.setOptions({
    global: {
      useUTC: false
    }
  });

  // Create the chart
  $('#container').highcharts('StockChart', {
    chart: {
      events: {
        load: function() {
          chart = this;
          yAxis = chart.yAxis[0]
            var series = chart.series[0],
            lastPoint = series.points[series.points.length - 1],
            initialValue = yAxis.toPixels(lastPoint.y),
            //plotbandLabel,
            plotLine,
            newY,
            d;

          /*var svgGroup = this.renderer.g()
            .attr({
              zIndex: 99
            }).add()*/

          pathLine = this.renderer.path([
              'M',
              chart.plotLeft, initialValue,
              'L',
              chart.plotWidth + chart.plotLeft,
              initialValue
            ])
            .attr({
              'stroke-width': 0,
              stroke: 'red'
            })
            .add();

          plotbandLabel = this.renderer.label(
            (66).toFixed(2),
            chart.plotLeft + chart.plotWidth,
            yAxis.toPixels(66) - labelOffset,
            'rect',
            null,
            true
          ).attr({
              align: 'right',
              fill: 'rgba(255, 0, 0, 0)',
              padding: 8,
              zIndex: 999
            })
            .add();
                 

          setInterval(function() {
            var x = (new Date()).getTime(),
              y = Math.round(Math.random() * 100 + 100),
      
             delta = y - series.yData[series.yData.length - 1],
             style = { 'color': 'black', 'font-weight': 400 };
            if (delta > 0) {
             style['color'] = 'green';
              style['font-weight'] = 700;
            }
            /*else if (delta < 0) {
             style['color'] = 'red';
              style['font-weight'] = 700;
            }*/
            
            plotbandLabel.css(style);
            series.addPoint([x, y], true, true);

            d = pathLine.d.split(' ');
            d[2] = yAxis.toPixels(y);
            d[5] = yAxis.toPixels(y);

            plotbandLabel.animate({
              y: yAxis.toPixels(y) - labelOffset
            }, {
              duration: 500,
              step: function() {
               let t = '' + yAxis.toValue(this.y + labelOffset).toFixed(2), 
                firstLetter = t[0], 
                otherletters = t.substr(1);
                
                this.attr({
                  text: '<span style="color:black;font-weight:400">'+firstLetter+'</span>' 
                  +  otherletters ,
                  zIndex: 999999999
                })
              },
              complete: function() {
               let t = '' + y.toFixed(2), 
                firstLetter = t[0], 
                otherletters = t.substr(1);
                this.attr({
                  text: '<span style="color:black;font-weight:400">'+firstLetter+'</span>' 
                  +  otherletters ,
                  zIndex: 999999999
                })
              }
            });

            pathLine.animate({
              d: d
            }, 500);
          }, 1000);
        }
      }
    },
    rangeSelector: {
      buttons: [{
        count: 1,
        type: 'minute',
        text: '1M'
      }, {
        count: 5,
        type: 'minute',
        text: '5M'
      }, {
        type: 'all',
        text: 'All'
      }],
      inputEnabled: false,
      selected: 0
    },
    title: {
      text: 'Live random data'
    },
    yAxis: [{
      opposite: false,
      title: {
        enabled: false
      }
    }],
    exporting: {
      enabled: false
    },
    series: [{
      name: 'Random data',
      data: (function() {
        // generate an array of random data
        var data = [],
          time = (new Date()).getTime(),
          i;

        for (i = -999; i <= 0; i += 1) {
          data.push([
            time + i * 1000,
            Math.round(Math.random() * 100)
          ]);
        }
        return data;
      }())
    }]
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/stock/highstock.src.js"></script>

<div id="container" style="height: 400px; min-width: 310px">
  <div id="lastprice" style="position:absolute;x:0">
  </div>
</div>

更新:

var x = (new Date()).getTime(),
    y = Math.round(Math.random() * 100 + 100),
    prevVal = series.yData[series.yData.length - 1],
    //create string representations of current and old values of y
    y_str = '' + y.toFixed(2),
    prevVal_str = '' + prevVal.toFixed(2),
    delta = y - prevVal,
    style = { 'color': 'black', 'font-weight': 400 };
if (delta > 0) {
    style['color'] = 'green';
    style['font-weight'] = 700;
}
else if (delta < 0) {
    style['color'] = 'red';
    style['font-weight'] = 700;
}

//add padding of 0's to values so they will be the same length [1]
let max_len = Math.max(y_str.length, prevVal_str.length), padding = '';
for (let i = 0; i < max_len ;i++) padding += '0';
y_str = (padding + y_str).slice(max_len);
prevVal_str = (padding + prevVal_str).slice(max_len);
//find how many first digits did not change
for (var i = 0; i < max_len; i++) if (y_str[i] !== prevVal_str[i]) break;
//add some custom field to the label to store the number of first digits
plotbandLabel.num_digits_not_changed = i;

[1] 填充代码基于 this 答案

在动画中使用num_digits_not_changed

plotbandLabel.animate({
    y: yAxis.toPixels(y) - labelOffset
}, {
    duration: 500,
    step: function() {
        let t = '' + yAxis.toValue(this.y + labelOffset).toFixed(2),
            firstLetter = t.substr(0, this.num_digits_not_changed),
            otherletters = t.substr(this.num_digits_not_changed);

        this.attr({
            text: '<span style="color:black;font-weight:400">'+firstLetter+'</span>'
            +  otherletters ,
            zIndex: 999999999
        })
    },
    complete: function() {
        let t = '' + y.toFixed(2),
            firstLetter = t.substr(0, this.num_digits_not_changed),
            otherletters = t.substr(this.num_digits_not_changed);
        this.attr({
            text: '<span style="color:black;font-weight:400">'+firstLetter+'</span>'
            +  otherletters ,
            zIndex: 999999999
        })
    }
});

工作演示:

$(function() {
var chart, yAxis, plotbandLabel, pathLine
            labelOffset = 15;

  Highcharts.setOptions({
    global: {
      useUTC: false
    }
  });

  // Create the chart
  $('#container').highcharts('StockChart', {
    chart: {
      events: {
        load: function() {
          chart = this;
          yAxis = chart.yAxis[0]
            var series = chart.series[0],
            lastPoint = series.points[series.points.length - 1],
            initialValue = yAxis.toPixels(lastPoint.y),
            //plotbandLabel,
            plotLine,
            newY,
            d;

          /*var svgGroup = this.renderer.g()
            .attr({
              zIndex: 99
            }).add()*/

          pathLine = this.renderer.path([
              'M',
              chart.plotLeft, initialValue,
              'L',
              chart.plotWidth + chart.plotLeft,
              initialValue
            ])
            .attr({
              'stroke-width': 0,
              stroke: 'red'
            })
            .add();

          plotbandLabel = this.renderer.label(
            (66).toFixed(2),
            chart.plotLeft + chart.plotWidth,
            yAxis.toPixels(66) - labelOffset,
            'rect',
            null,
            true
          ).attr({
              align: 'right',
              fill: 'rgba(255, 0, 0, 0)',
              padding: 8,
              zIndex: 999
            })
            .add();
                 

          setInterval(function() {
            var x = (new Date()).getTime(),
              y = Math.round(Math.random() * 100 + 100),
      prevVal = series.yData[series.yData.length - 1],
            y_str = '' + y.toFixed(2),
            prevVal_str = '' + prevVal.toFixed(2),
             delta = y - prevVal,
             style = { 'color': 'black', 'font-weight': 400 };
            if (delta > 0) {
             style['color'] = 'green';
              style['font-weight'] = 700;
            }
            else if (delta < 0) {
             style['color'] = 'red';
              style['font-weight'] = 700;
            }
            
            let max_len = Math.max(y_str.length, prevVal_str.length), padding = '';
            for (let i = 0; i < max_len ;i++) padding += '0';
            y_str = (padding + y_str).slice(max_len);
            prevVal_str = (padding + prevVal_str).slice(max_len);
            for (var i = 0; i < max_len; i++) if (y_str[i] !== prevVal_str[i]) break;
            //console.log('number of first digits which did not change: ' + i);
            
            plotbandLabel.num_digits_not_changed = i;
            
            plotbandLabel.css(style);
            series.addPoint([x, y], true, true);

            d = pathLine.d.split(' ');
            d[2] = yAxis.toPixels(y);
            d[5] = yAxis.toPixels(y);

            plotbandLabel.animate({
              y: yAxis.toPixels(y) - labelOffset
            }, {
              duration: 500,
              step: function() {
               let t = '' + yAxis.toValue(this.y + labelOffset).toFixed(2), 
                firstLetter = t.substr(0, this.num_digits_not_changed), 
                otherletters = t.substr(this.num_digits_not_changed);
                
                this.attr({
                  text: '<span style="color:black;font-weight:400">'+firstLetter+'</span>' 
                  +  otherletters ,
                  zIndex: 999999999
                })
              },
              complete: function() {
               let t = '' + y.toFixed(2), 
                firstLetter = t.substr(0, this.num_digits_not_changed), 
                otherletters = t.substr(this.num_digits_not_changed);
                this.attr({
                  text: '<span style="color:black;font-weight:400">'+firstLetter+'</span>' 
                  +  otherletters ,
                  zIndex: 999999999
                })
              }
            });

            pathLine.animate({
              d: d
            }, 500);
          }, 1000);
        }
      }
    },
    rangeSelector: {
      buttons: [{
        count: 1,
        type: 'minute',
        text: '1M'
      }, {
        count: 5,
        type: 'minute',
        text: '5M'
      }, {
        type: 'all',
        text: 'All'
      }],
      inputEnabled: false,
      selected: 0
    },
    title: {
      text: 'Live random data'
    },
    yAxis: [{
      opposite: false,
      title: {
        enabled: false
      }
    }],
    exporting: {
      enabled: false
    },
    series: [{
      name: 'Random data',
      data: (function() {
        // generate an array of random data
        var data = [],
          time = (new Date()).getTime(),
          i;

        for (i = -999; i <= 0; i += 1) {
          data.push([
            time + i * 1000,
            Math.round(Math.random() * 100)
          ]);
        }
        return data;
      }())
    }]
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/stock/highstock.src.js"></script>

<div id="container" style="height: 400px; min-width: 310px">
  <div id="lastprice" style="position:absolute;x:0">
  </div>
</div>