在Highcharts仪表图中,如何将绘图带标签置于中心位置?

时间:2017-06-08 13:08:57

标签: javascript css highcharts

我试图在量表图形的情节带内显示标签,但我无法弄清楚如何正确对齐文字。知道如何在标题带的中间放置标签吗?或者是否有更简单/替代的方式来创建此效果?

PS。我使用"样式模式" Highcharts版本。



longjmp

$(function() {

  // Make sure the gauges have correct height on initial load
  calculateGaugeHeight();

  // And make sure the height is re-calculated on window resize
  $(window).on('load resize', function() {
    calculateGaugeHeight();
  });

  var settings = {
    gaugeMinValue: 0,
    gaugeMaxValue: 8000,
    gaugeStartValue: 3000,
    gaugeStartAngle: -180,
    gaugeEndAngle: 180,
    gaugeUpdateInterval: 500 // ms
  };

  var options = {
    tooltip: {
      enabled: false
    },
    chart: {
      type: 'gauge'
    },

    title: false,

    pane: {
      startAngle: settings.gaugeStartAngle,
      endAngle: settings.gaugeEndAngle
    },

    plotOptions: {
      gauge: {
        dial: {
          radius: 0
        },
        pivot: {
          radius: 0
        },
        dataLabels: {
          borderWidth: 0,
          padding: 0,
          verticalAlign: 'middle',
          style: false,
          formatter: function() {
            var output = '<div class="gauge-data">';
            output += '<span class="gauge-value">' + this.y + '</span>';
            output += '</div>';

            return output;
          },
          useHTML: true
        }
      },
      pie: {
        dataLabels: false,
        animation: false,
        startAngle: settings.gaugeStartAngle,
        endAngle: settings.gaugeEndAngle,
        center: ['50%', '50%'],
        states: {
          hover: {
            enabled: false
          }
        }
      }
    },

    // the value axis
    yAxis: {
      offset: 0,
      min: settings.gaugeMinValue,
      max: settings.gaugeMaxValue,

      title: false,
      labels: false,

      tickAmount: 0,

      plotBands: [{
        thickness: 25,
        outerRadius: "100%",
        from: settings.gaugeMinValue,
        to: settings.gaugeStartValue,
        label: {}
      }, {
        thickness: 25,
        outerRadius: "100%",
        from: settings.gaugeStartValue,
        to: settings.gaugeMaxValue,
        label: {}
      }]
    },

    series: [{
      type: 'gauge',
      data: [settings.gaugeStartValue],
    }, {
      type: 'pie',
      innerSize: '87%',
      className: 'pizza',
      data: [{
        y: settings.gaugeStartValue,
        name: 'Data 1',
        className: 'customSeries1'
      }, {
        y: settings.gaugeMaxValue - settings.gaugeStartValue,
        name: 'Data 2',
        className: 'customSeries2'
      }]
    }],

    navigation: {
      buttonOptions: {
        enabled: false
      }
    },

    credits: false
  };

  $('#gauge1').highcharts(options, buildGraph);

  function buildGraph(chart) {
    if (!chart.renderer.forExport) {
      setInterval(function() {

        var gaugePoint = chart.series[0].points[0],
          piePoint = chart.series[1],
          yAxis = chart.yAxis[0],
          newVal,
          inc = Math.round((Math.random() - 0.5) * 1500);

        newVal = gaugePoint.y + inc;
        if (newVal < settings.gaugeMinValue || newVal > settings.gaugeMaxValue) {
          newVal = gaugePoint.y - inc;
        }

        // Update number gauge value
        gaugePoint.update(newVal);

        // Update pie with current value
        piePoint.points[0].update(newVal);
        piePoint.points[1].update(settings.gaugeMaxValue - newVal);

        yAxis.update({
          plotBands: [{
            thickness: 25,
            outerRadius: "100%",
            from: settings.gaugeMinValue,
            to: newVal,
            label: {
              text: 'Text 1',
              y: 15,
              x: 55,
              rotation: 290
            }
          }, {
            thickness: 25,
            outerRadius: "100%",
            from: newVal,
            to: settings.gaugeMaxValue,
            label: {
              text: 'Text 2',
              y: chart.plotSizeY / 2,
              x: chart.plotSizeX * 0.87,
              rotation: 290
            }
          }]
        });
      }, settings.gaugeUpdateInterval);
    }
  }

  function calculateGaugeHeight() {
    var div = $('.gauge');
    div.height(div.width());
  }
});
&#13;
/**
     * @license Highcharts
     *
     * (c) 2009-2016 Torstein Honsi
     *
     * License: www.highcharts.com/license
     */

.highcharts-container {
  position: relative;
  overflow: hidden;
  width: 100%;
  height: 100%;
  text-align: left;
  line-height: normal;
  z-index: 0;
  /* #1072 */
  -webkit-tap-highlight-color: transparent;
  font-family: "Lucida Grande", "Lucida Sans Unicode", Arial, Helvetica, sans-serif;
  font-size: 12px;
}

.highcharts-root text {
  stroke-width: 0;
}

.highcharts-strong {
  font-weight: bold;
}

.highcharts-emphasized {
  font-style: italic;
}

.highcharts-background {
  fill: #ffffff;
}

.highcharts-plot-border,
.highcharts-plot-background {
  fill: none;
}

.highcharts-label-box {
  fill: none;
}

.highcharts-button-box {
  fill: inherit;
}


/* Titles */

.highcharts-title {
  fill: #333333;
  font-size: 1.5em;
}

.highcharts-subtitle {
  fill: #666666;
}


/* Axes */

.highcharts-axis-line {
  fill: none;
  stroke: #ccd6eb;
}

.highcharts-yaxis .highcharts-axis-line {
  stroke-width: 0;
}

.highcharts-axis-title {
  fill: #666666;
}

.highcharts-axis-labels {
  fill: #666666;
  cursor: default;
  font-size: 0.9em;
}

.highcharts-grid-line {
  fill: none;
  stroke: #e6e6e6;
}

.highcharts-xaxis-grid .highcharts-grid-line {
  stroke-width: 0;
}

.highcharts-tick {
  stroke: #ccd6eb;
}

.highcharts-yaxis .highcharts-tick {
  stroke-width: 0;
}

.highcharts-minor-grid-line {
  stroke: #f2f2f2;
}

.highcharts-crosshair-thin {
  stroke-width: 1px;
  stroke: #cccccc;
}

.highcharts-crosshair-category {
  stroke: #ccd6eb;
  stroke-opacity: 0.25;
}


/* Credits */

.highcharts-credits {
  cursor: pointer;
  fill: #999999;
  font-size: 0.7em;
  transition: fill 250ms, font-size 250ms;
}

.highcharts-credits:hover {
  fill: black;
  font-size: 1em;
}


/* Tooltip */

.highcharts-tooltip {
  cursor: default;
  pointer-events: none;
  white-space: nowrap;
  transition: stroke 150ms;
}

.highcharts-tooltip text {
  fill: #333333;
}

.highcharts-tooltip .highcharts-header {
  font-size: 0.85em;
}

.highcharts-tooltip-box {
  stroke-width: 1px;
  fill: #f7f7f7;
  fill-opacity: 0.85;
}

.highcharts-selection-marker {
  fill: #335cad;
  fill-opacity: 0.25;
}

.highcharts-graph {
  fill: none;
  stroke-width: 2px;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.highcharts-state-hover .highcharts-graph {
  stroke-width: 3;
}

.highcharts-state-hover path {
  transition: stroke-width 50;
  /* quick in */
}

.highcharts-state-normal path {
  transition: stroke-width 250ms;
  /* slow out */
}


/* Legend hover affects points and series */

g.highcharts-series,
.highcharts-point,
.highcharts-markers,
.highcharts-data-labels {
  transition: opacity 250ms;
}

.highcharts-legend-series-active g.highcharts-series:not(.highcharts-series-hover),
.highcharts-legend-point-active .highcharts-point:not(.highcharts-point-hover),
.highcharts-legend-series-active .highcharts-markers:not(.highcharts-series-hover),
.highcharts-legend-series-active .highcharts-data-labels:not(.highcharts-series-hover) {
  opacity: 0.2;
}


/* Series options */


/* Default colors */

.highcharts-color-0 {
  fill: #7cb5ec;
  stroke: #7cb5ec;
}

.highcharts-color-1 {
  fill: #434348;
  stroke: #434348;
}

.highcharts-color-2 {
  fill: #90ed7d;
  stroke: #90ed7d;
}

.highcharts-color-3 {
  fill: #f7a35c;
  stroke: #f7a35c;
}

.highcharts-color-4 {
  fill: #8085e9;
  stroke: #8085e9;
}

.highcharts-color-5 {
  fill: #f15c80;
  stroke: #f15c80;
}

.highcharts-color-6 {
  fill: #e4d354;
  stroke: #e4d354;
}

.highcharts-color-7 {
  fill: #2b908f;
  stroke: #2b908f;
}

.highcharts-color-8 {
  fill: #f45b5b;
  stroke: #f45b5b;
}

.highcharts-color-9 {
  fill: #91e8e1;
  stroke: #91e8e1;
}

.highcharts-area {
  fill-opacity: 0.75;
  stroke-width: 0;
}

.highcharts-markers {
  stroke-width: 1px;
  stroke: #ffffff;
}

.highcharts-point {
  stroke-width: 1px;
}

.highcharts-dense-data .highcharts-point {
  stroke-width: 0;
}

.highcharts-data-label {
  font-size: 0.9em;
  font-weight: bold;
}

.highcharts-data-label-box {
  fill: none;
  stroke-width: 0;
}

.highcharts-data-label text {
  fill: #333333;
}

.highcharts-data-label-connector {
  fill: none;
}

.highcharts-halo {
  fill-opacity: 0.25;
  stroke-width: 0;
}

.highcharts-point-select {
  fill: #cccccc;
  stroke: #000000;
}

.highcharts-column-series rect.highcharts-point {
  stroke: #ffffff;
}

.highcharts-column-series .highcharts-point {
  transition: fill-opacity 250ms;
}

.highcharts-column-series .highcharts-point-hover {
  fill-opacity: 0.75;
  transition: fill-opacity 50ms;
}

.highcharts-pie-series .highcharts-point {
  stroke-linejoin: round;
  stroke: #ffffff;
}

.highcharts-pie-series .highcharts-point-hover {
  fill-opacity: 0.75;
  transition: fill-opacity 50ms;
}

.highcharts-pie-series .highcharts-point-select {
  fill: inherit;
  stroke: inherit;
}

.highcharts-funnel-series .highcharts-point {
  stroke-linejoin: round;
  stroke: #ffffff;
}

.highcharts-funnel-series .highcharts-point-hover {
  fill-opacity: 0.75;
  transition: fill-opacity 50ms;
}

.highcharts-funnel-series .highcharts-point-select {
  fill: inherit;
  stroke: inherit;
}

.highcharts-pyramid-series .highcharts-point {
  stroke-linejoin: round;
  stroke: #ffffff;
}

.highcharts-pyramid-series .highcharts-point-hover {
  fill-opacity: 0.75;
  transition: fill-opacity 50ms;
}

.highcharts-pyramid-series .highcharts-point-select {
  fill: inherit;
  stroke: inherit;
}

.highcharts-solidgauge-series .highcharts-point {
  stroke-width: 0;
}

.highcharts-treemap-series .highcharts-point {
  stroke-width: 1px;
  stroke: #e6e6e6;
  transition: stroke 250ms, fill 250ms, fill-opacity 250ms;
}

.highcharts-treemap-series .highcharts-point-hover {
  stroke: #999999;
  transition: stroke 25ms, fill 25ms, fill-opacity 25ms;
}

.highcharts-treemap-series .highcharts-above-level {
  display: none;
}

.highcharts-treemap-series .highcharts-internal-node {
  fill: none;
}

.highcharts-treemap-series .highcharts-internal-node-interactive {
  fill-opacity: 0.15;
  cursor: pointer;
}

.highcharts-treemap-series .highcharts-internal-node-interactive:hover {
  fill-opacity: 0.75;
}


/* Legend */

.highcharts-legend-box {
  fill: none;
  stroke-width: 0;
}

.highcharts-legend-item text {
  fill: #333333;
  font-weight: bold;
  cursor: pointer;
  stroke-width: 0;
}

.highcharts-legend-item:hover text {
  fill: #000000;
}

.highcharts-legend-item-hidden * {
  fill: #cccccc !important;
  stroke: #cccccc !important;
  transition: fill 250ms;
}

.highcharts-legend-nav-active {
  fill: #003399;
  cursor: pointer;
}

.highcharts-legend-nav-inactive {
  fill: #cccccc;
}

.highcharts-legend-title-box {
  fill: none;
  stroke-width: 0;
}


/* Loading */

.highcharts-loading {
  position: absolute;
  background-color: #ffffff;
  opacity: 0.5;
  text-align: center;
  z-index: 10;
  transition: opacity 250ms;
}

.highcharts-loading-hidden {
  height: 0 !important;
  opacity: 0;
  overflow: hidden;
  transition: opacity 250ms, height 250ms step-end;
}

.highcharts-loading-inner {
  font-weight: bold;
  position: relative;
  top: 45%;
}


/* Plot bands and polar pane backgrounds */

.highcharts-plot-band,
.highcharts-pane {
  fill: #000000;
  fill-opacity: 0.05;
}

.highcharts-plot-line {
  fill: none;
  stroke: #999999;
  stroke-width: 1px;
}


/* Highcharts More */

.highcharts-boxplot-box {
  fill: #ffffff;
}

.highcharts-boxplot-median {
  stroke-width: 2px;
}

.highcharts-bubble-series .highcharts-point {
  fill-opacity: 0.5;
}

.highcharts-errorbar-series .highcharts-point {
  stroke: #000000;
}

.highcharts-gauge-series .highcharts-data-label-box {
  stroke: #cccccc;
  stroke-width: 1px;
}

.highcharts-gauge-series .highcharts-dial {
  fill: #000000;
  stroke-width: 0;
}

.highcharts-polygon-series .highcharts-graph {
  fill: inherit;
  stroke-width: 0;
}

.highcharts-waterfall-series .highcharts-graph {
  stroke: #333333;
  stroke-dasharray: 1, 3;
}


/* Highstock */

.highcharts-navigator-mask-outside {
  fill-opacity: 0;
}

.highcharts-navigator-mask-inside {
  fill: #6685c2;
  /* navigator.maskFill option */
  fill-opacity: 0.25;
  cursor: ew-resize;
}

.highcharts-navigator-outline {
  stroke: #cccccc;
  fill: none;
}

.highcharts-navigator-handle {
  stroke: #cccccc;
  fill: #f2f2f2;
  cursor: ew-resize;
}

.highcharts-navigator-series {
  fill: #335cad;
  stroke: #335cad;
}

.highcharts-navigator-series .highcharts-graph {
  stroke-width: 1px;
}

.highcharts-navigator-series .highcharts-area {
  fill-opacity: 0.05;
}

.highcharts-navigator-xaxis .highcharts-axis-line {
  stroke-width: 0;
}

.highcharts-navigator-xaxis .highcharts-grid-line {
  stroke-width: 1px;
  stroke: #e6e6e6;
}

.highcharts-navigator-xaxis.highcharts-axis-labels {
  fill: #999999;
}

.highcharts-navigator-yaxis .highcharts-grid-line {
  stroke-width: 0;
}

.highcharts-scrollbar-thumb {
  fill: #cccccc;
  stroke: #cccccc;
  stroke-width: 1px;
}

.highcharts-scrollbar-button {
  fill: #e6e6e6;
  stroke: #cccccc;
  stroke-width: 1px;
}

.highcharts-scrollbar-arrow {
  fill: #666666;
}

.highcharts-scrollbar-rifles {
  stroke: #666666;
  stroke-width: 1px;
}

.highcharts-scrollbar-track {
  fill: #f2f2f2;
  stroke: #f2f2f2;
  stroke-width: 1px;
}

.highcharts-button {
  fill: #f7f7f7;
  stroke: #cccccc;
  cursor: default;
  stroke-width: 1px;
  transition: fill 250ms;
}

.highcharts-button text {
  fill: #333333;
}

.highcharts-button-hover {
  transition: fill 0ms;
  fill: #e6e6e6;
  stroke: #333333;
}

.highcharts-button-pressed {
  font-weight: bold;
  fill: #e6ebf5;
  stroke: #335cad;
}

.highcharts-button-disabled text {
  fill: #cccccc;
}

.highcharts-range-selector-buttons .highcharts-button {
  stroke-width: 0;
}

.highcharts-range-label rect {
  fill: none;
}

.highcharts-range-label text {
  fill: #666666;
}

.highcharts-range-input rect {
  fill: none;
}

.highcharts-range-input text {
  fill: #333333;
}

input.highcharts-range-selector {
  position: absolute;
  border: 0;
  width: 1px;
  /* Chrome needs a pixel to see it */
  height: 1px;
  padding: 0;
  text-align: center;
  left: -9em;
  /* #4798 */
}

.highcharts-crosshair-label text {
  fill: #ffffff;
  font-size: 1.1em;
}

.highcharts-crosshair-label .highcharts-label-box {
  fill: inherit;
}

.highcharts-candlestick-series .highcharts-point {
  stroke: #000000;
  stroke-width: 1px;
}

.highcharts-candlestick-series .highcharts-point-up {
  fill: #ffffff;
}

.highcharts-ohlc-series .highcharts-point-hover {
  stroke-width: 3px;
}

.highcharts-flags-series .highcharts-point {
  stroke: #999999;
  fill: #ffffff;
}

.highcharts-flags-series .highcharts-point-hover {
  stroke: #000000;
  fill: #ccd6eb;
}

.highcharts-flags-series .highcharts-point text {
  fill: #000000;
  font-size: 0.9em;
  font-weight: bold;
}


/* Highmaps */

.highcharts-map-series .highcharts-point {
  transition: fill 500ms, fill-opacity 500ms, stroke-width 250ms;
  stroke: #cccccc;
}

.highcharts-map-series .highcharts-point-hover {
  transition: fill 0ms, fill-opacity 0ms;
  fill-opacity: 0.5;
  stroke-width: 2px;
}

.highcharts-mapline-series .highcharts-point {
  fill: none;
}

.highcharts-heatmap-series .highcharts-point {
  stroke-width: 0;
}

.highcharts-map-navigation {
  font-size: 1.3em;
  font-weight: bold;
  text-align: center;
}

.highcharts-coloraxis {
  stroke-width: 0;
}

.highcharts-coloraxis-marker {
  fill: #999999;
}

.highcharts-null-point {
  fill: #f7f7f7;
}


/* 3d charts */

.highcharts-3d-frame {
  fill: transparent;
}


/* Exporting module */

.highcharts-contextbutton {
  fill: #ffffff;
  /* needed to capture hover */
  stroke: none;
  stroke-linecap: round;
}

.highcharts-contextbutton:hover {
  fill: #e6e6e6;
  stroke: #e6e6e6;
}

.highcharts-button-symbol {
  stroke: #666666;
  stroke-width: 3px;
}

.highcharts-menu {
  border: 1px solid #999999;
  background: #ffffff;
  padding: 5px 0;
  box-shadow: 3px 3px 10px #888;
}

.highcharts-menu-item {
  padding: 0.5em 1em;
  background: none;
  color: #333333;
  cursor: pointer;
  transition: background 250ms, color 250ms;
}

.highcharts-menu-item:hover {
  background: #335cad;
  color: #ffffff;
}


/* Drilldown module */

.highcharts-drilldown-point {
  cursor: pointer;
}

.highcharts-drilldown-data-label text,
.highcharts-drilldown-axis-label {
  cursor: pointer;
  fill: #003399;
  font-weight: bold;
  text-decoration: underline;
}


/* No-data module */

.highcharts-no-data text {
  font-weight: bold;
  font-size: 12px;
  fill: #666666;
}

.chart-container {
  background: transparent;
}

.highcharts-background {
  fill: transparent;
}

.highcharts-plot-background {
  background-color: transparent;
}

.highcharts-pie-series .customSeries1 {
  border-radius: 20px;
  fill: #007272;
}

.highcharts-pie-series .customSeries2 {
  fill: #e76a0b;
  border-radius: 20px;
}

.highcharts-tooltip-box {
  stroke-width: 0;
}

.highcharts-plot-band {
  fill: white;
  fill-opacity: 1;
  stroke-width: 1px;
  stroke: lightgray;
}

.highcharts-minor-grid-line,
.highcharts-grid-line {
  stroke-width: 0;
}

.highcharts-pane {
  fill: white
}

.highcharts-plot-band-label {
  font-size: 12px;
  text-transform: uppercase;
}

.container {
  width: 100%;
  max-width: 400px;
}
&#13;
&#13;
&#13;

谢谢!

https://jsfiddle.net/remisture/4e2frewz/9/

1 个答案:

答案 0 :(得分:1)

您可以使用svg textPath元素在绘图带上放置文本。如果将startOffset属性设置为25%(参见下面如何计算正确的startOffset值),文本将根据绘图带居中。

渲染text和textPath的功能可以是这样的:

function renderText(textStr, plotBand, i) {
  const id = `plot-band-${i}`
  const chart = plotBand.axis.chart
  const path = plotBand.svgElem
  const textRendered = chart.textRendered
  path.attr('id', id)

  if (!textRendered[i]) {
    const text = chart.renderer.createElement('text')
      .attr({
        zIndex: 99,
        dy: 20,
       'text-anchor': 'middle'
      })
      .css({
        color: '#4572A7',
        fontSize: '16px'
      }).add()


    const textPath = chart.renderer.createElement('textPath').attr({
      startOffset: '25%'
    }).add(text)

    textPath.element.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#' + id)

    const textNode = document.createTextNode(textStr)
    textPath.element.appendChild(textNode)
    textRendered[i] = true
  }
}

在加载时创建一个数组。它将阻止呈现多个文本:

chart: {
  type: 'gauge',
  events: {
    load: function() {
      this.textRendered = []
    }
  }
},

在超时内调用该函数:

yAxis.plotLinesAndBands.forEach((plotBand, i) => {
  renderText('Custom Text', plotBand, i)
})

示例和输出

https://jsfiddle.net/g0acwkLr/

highcharts textpath plotband

更新:计算startOffset

25%startOffset是一个“足够好”的值 - 你可以看到,如果情节带很厚 - 文本不会完全放在中心。

如果情节带只是一条线,startOffset 50%将完美地运作。

50%

但是情节带有它的宽度 - 如果宽度为0,则25%将恰好是情节带上线的中心

startOffset:50%

50% plot band

startOffset:25%

25% plot band

startOffset:带有薄图带的25%

25% thin

要计算完全正确的startOffset,您可以测量上部绘图带线和总绘图带线并计算其关系

function calculateStartOffset(wrapper) {
  const len = wrapper.element.getTotalLength()

  const tempPath = document.createElementNS('http://www.w3.org/2000/svg', 'path')
  tempPath.setAttribute('d', wrapper.d.replace(/\sL.*/, '')) // upper line
  const len2 = tempPath.getTotalLength()

  return Math.round(len2 / 2 / len * 100)    
}

示例:https://jsfiddle.net/g0acwkLr/4/