Как поместить тень внутри гистограммы в высокие графики? - PullRequest
1 голос
/ 22 июня 2019

Как поместить тень внутри гистограммы, например, вставку в прямоугольник (css) на диаграммах, как показано на рисунке ниже.
Спасибо. Хорошего дня ~

введите описание изображения здесь

enter image description here

Ответы [ 2 ]

0 голосов
/ 24 июня 2019

К сожалению, в Highcharts отсутствует встроенная тень в ядре. Однако это можно сделать, добавив пользовательскую логику в метод Highcharts.SVGElement.prototype.shadow. Проверьте код и демоверсию, размещенную ниже, и дайте мне знать, если что-то неясно для вас.

Кроме того, чтобы добавить частичную заливку к столбцам с внутренней тенью, необходимо создать пользовательские элементы столбца и вставить их в DOM между тенями и конкретными точками.

Код:

function insertAfter(newNode, referenceNode) {
  referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

(function(H) {
  H.SVGElement.prototype.shadow = function(shadowOptions, group, cutOff) {
    var shadows = [],
      i, shadow, element = this.element,
      strokeWidth, shadowWidth, shadowElementOpacity,
      // compensate for inverted plot area
      transform,
      elemBBox = element.getBBox(),
      translateX,
      translateY;

    if (!shadowOptions) {
      this.destroyShadows();
    } else if (!this.shadows) {
      shadowWidth = H.pick(shadowOptions.width, 3);
      shadowElementOpacity = (shadowOptions.opacity || 0.15) /
        shadowWidth;
      transform = this.parentInverted ?
        '(' + H.pick(shadowOptions.offsetY, 1) * -1 + ', ' +
        H.pick(shadowOptions.offsetX, 1) * -1 + ')' :
        '(' + H.pick(shadowOptions.offsetX, 1) + ', ' +
        H.pick(shadowOptions.offsetY, 1) + ')';

      if (!shadowOptions.inside) {
        for (i = 1; i <= shadowWidth; i++) {
          shadow = element.cloneNode(0);
          strokeWidth = (shadowWidth * 2) + 1 - (2 * i);
          H.attr(shadow, {
            stroke: (shadowOptions.color ||
              '#000000'),
            'stroke-opacity': shadowElementOpacity * i,
            'stroke-width': strokeWidth,
            transform: 'translate' + transform,
            fill: 'none'
          });
          shadow.setAttribute('class', (shadow.getAttribute('class') || '') + ' highcharts-shadow');
          if (cutOff) {
            H.attr(shadow, 'height', Math.max(H.attr(shadow, 'height') - strokeWidth, 0));
            shadow.cutHeight = strokeWidth;
          }
          if (group) {
            group.element.appendChild(shadow);
          } else if (element.parentNode) {
            element.parentNode.insertBefore(shadow, element);
          }
          shadows.push(shadow);
        }
      } else {

        for (i = shadowWidth; i >= 1; i--) {
          shadow = element.cloneNode(0);
          translateX = i / 2 - shadowOptions.offsetY;
          translateY = i / 2 - shadowOptions.offsetX;

          H.attr(shadow, {
            stroke: (shadowOptions.color ||
              '#000000'),
            'stroke-opacity': shadowElementOpacity * (shadowWidth - i + 1),
            'stroke-width': i,
            transform: 'translate(' + translateX + ',' + translateY + ')',
            fill: 'none'
          });

          H.css(shadow, {
            width: elemBBox.width - i,
            height: elemBBox.height - i,
          });

          shadow.setAttribute('class', (shadow.getAttribute('class') || '') + ' highcharts-shadow');
          if (cutOff) {
            H.attr(shadow, 'height', Math.max(H.attr(shadow, 'height') - strokeWidth, 0));
            shadow.cutHeight = strokeWidth;
          }

          if (group) {
            group.element.appendChild(shadow);
          } else if (element.parentNode) {
            insertAfter(shadow, element);
          }
          shadows.push(shadow);
        }
      }

      this.shadows = shadows;
    }
    return this;
  };
})(Highcharts)

Highcharts.chart('container', {
  chart: {
    type: 'column',
    inverted: true,
    events: {
      render: function() {
        var chart = this,
          yAxis = chart.yAxis[0],
          partialFillWidth,
          elem,
          bBox;

        if (chart.customElements && chart.customElements.length) {
          chart.customElements.forEach(custElem => {
            custElem.parentNode.removeChild(custElem);
          })

          chart.customElements.length = 0;
        } else {
          chart.customElements = [];
        }

        chart.series[0].points.forEach(point => {
          bBox = point.graphic.getBBox();
          elem = point.graphic.element.cloneNode(0);
          partialFillWidth = yAxis.toPixels(point.partialFill);

          Highcharts.attr(elem, {
            fill: point.partialFillColor,
            transform: 'translate(0, ' + (bBox.height - (point.partialFill / point.y) * bBox.height) + ')'
          });

          Highcharts.css(elem, {
            height: (point.partialFill / point.y) * bBox.height
          });

          insertAfter(elem, point.graphic.element);
          chart.customElements.push(elem);
        });
      }
    }
  },
  title: {
    text: 'Efficiency Optimization by Branch'
  },
  xAxis: {
    categories: [
      'Seattle HQ',
      'San Francisco',
      'Tokyo'
    ]
  },
  yAxis: [{
    min: 0,
    title: {
      text: 'Employees'
    }
  }, {
    title: {
      text: 'Profit (millions)'
    },
    opposite: true
  }],
  legend: {
    shadow: false
  },
  tooltip: {
    shared: true
  },
  plotOptions: {
    column: {
      grouping: false,
      shadow: false,
      borderWidth: 0,
      pointPadding: 0,
      groupPadding: 0
    }
  },
  series: [{
    color: '#efefef',
    id: 'main',
    data: [{
      y: 120,
      partialFill: 100,
      partialFillColor: '#bbb'
    }, {
      y: 50,
      partialFill: 10,
      partialFillColor: '#bbb'
    }, {
      y: 70,
      partialFill: 20,
      partialFillColor: '#bbb'
    }],
    pointPadding: 0.4,
    shadow: {
      color: 'rgba(0, 0, 0, 0.5)',
      opacity: 0.3,
      width: 5,
      offsetX: 0,
      offsetY: 0,
      inside: true
    }
  }]
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container"></div>

Демо-версия:

Ссылка API:

0 голосов
/ 24 июня 2019

Вы можете использовать две серии перекрытий, одну со свойством shadow по умолчанию и перевести их на несколько пикселей в событии load:

Highcharts.chart('container', {
    chart: {
        ...,
        events: {
            load: function() {
                this.series[0].points[0].graphic.attr({
                    translateX: -2
                });

                this.series[1].points[0].graphic.attr({
                    translateX: -2
                });
            }
        }
    },
    ...,
    series: [{
        ...,
        data: [100],
        shadow: {
            color: 'gray',
            opacity: 0.8,
            width: 2
        }
    }, {
        data: [50]
    }]
});

Демонстрация в реальном времени: http://jsfiddle.net/BlackLabel/b7hp0r6s/

Справочник по API: https://api.highcharts.com/highcharts/series.bar.shadow

...