도넛 (게이지)에 대한 사용자 정의 배경 제한


9

( Chartjs-tsgauge ) 기반 게이지 차트를 사용하고 있습니다. 게이지 한계와 별도로 차트의 배경색을 설정하고 싶습니다. 내가 사용한 플러그인에 배경에 대한 코드가 없기 때문에 Charts.JS가 배경을 렌더링 하는 방법에 대한 문제 . 예를 들어, 한계가있는 게이지가 있습니다 [0, 20, 40, 60, 80, 100]. [0-30]녹색, [30-70]노란색 및 [70-100]빨간색 으로 설정하고 싶습니다 . 현재 코드 : CodePEN

여기 내 현재 옵션이 있습니다.

var ctx = document.getElementById("canvas").getContext("2d");
new Chart(ctx, {
    type: "tsgauge",
    data: {
        datasets: [{
            backgroundColor: ["#0fdc63", "#fd9704", "#ff7143"],
            borderWidth: 0,
            gaugeData: {
                value: 7777,
                valueColor: "#ff7143"
            },
            gaugeLimits: [0, 3000, 7000, 10000]
        }]
    },
    options: {
            events: [],
            showMarkers: true
    }
});

그리고 여기 배경색을 설정하는 방법이 있습니다.

new Chart(ctx, {
    type: "tsgauge",
    data: {
        datasets: [{
            backgroundColor: ["#0fdc63", "#fd9704", "#ff7143"],
            borderWidth: 0,
            gaugeData: {
                value: 50,
                valueColor: "#ff7143"
            },
            gaugeLimits: [0, 20, 40, 60, 80, 100],
            gaugeColors: [{
                min: 0,
                max: 30,
                color: ""
                }, {
                min: 30,
                max: 70,
                color: ""
             },{
                min:70,
                max:100,
                color: ""
             }]
         }]
    },
    options: {
        events: [],
        showMarkers: true
    }
});

현재 Chart.JS색상 0i에 제한 0i있습니다. 또한 원하는 색상으로 다른 더미 차트를 그리는 것을 생각하고 실제 차트 위에 놓았습니다.


안녕하세요, 나는 당신을 도와주고 싶지만 당신이하고 싶은 것을 완전히 따르지 않는다고 생각합니다. 차트 뒤에서 어떤 배경을 참조하고 있습니까?
SirPeople

답변:


3

이전 솔루션

이를 달성하기 위해 데이터 세트를 약간 변경할 수 있습니다.

backgroundColor: ["green", "green", "green", "yellow", "yellow", "yellow", "yellow", "red", "red", "red"],
gaugeLimits: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100],

당신이 이후 gagueLimits의 범위로 분할 20하면 (30)의 한계에 액세스 할 수 없습니다 현재, 그래서,

그래서 제가 여기서 한 것은 guageLimits분할 된 범위로 정교 10해지고 지금 30은 접근 할 수 있습니다.70 .

이제 색상에 대해 각각의 guageLimits색상은backgroundColor 배열의 합니다. 그에 따라 설정하고 위의 배열을 확인하십시오. 해당 색상을 비울 수 없으므로 다음 색상 범위에 도달 할 때까지 동일한 색상을 사용해야 할 수 있습니다.

업데이트 된 솔루션

귀하의 요구 사항이 이제 해결되었습니다.

  • 게이지 레이블이 너무 아늑하지 않기를 원하므로 한계가 20입니다.
  • 색상 범위를 30과 70 포인트로 분리하려고합니다.

기술적으로 색상 범위를 특정 지점으로 설정하려면 gaugeLimits배열에서 해당 값을 가져야 하므로 축소 된 gaugeLimits배열은 다음과 같습니다.

gaugeLimits: [0, 20, 30, 40, 60, 70, 80, 100],

배열에 점이 지정되어 있으므로 색상을 적절하게 설정할 수 없습니다. 따라서 backgroundColor배열은 다음과 같습니다.

backgroundColor: ["#0fdc63", "#0fdc63", "#fd9704", "#fd9704", "#fd9704", "#ff7143", "#ff7143"]

이제 마지막 트릭

여전히 스케일에서 30과 70을 숨겨야 showMarkers합니다. 코드에서 토글을 시도했지만 보이는 숫자 스케일을 완전히 사용하거나 사용하지 않는 것처럼 보입니다. 문자열 배열을 제공하려고 시도했지만 허용합니다.boolean


Chartjs-tsgauge 는 사용 가능한 옵션에 대한 많은 문서를 제공하지 않으므로 코드를 알아markerFormatFn

기능은 매개 변수로 기능을 수행하며 각 마커 항목으로 수행 할 작업을 알려주는 기능을 제공 할 수 있습니다.

그래서 나머지없이 20으로 나눌 수있는 숫자 만 표시하는 함수를 제공하는 아이디어를 생각해 냈습니다. 그렇지 않으면 빈 문자열을 반환합니다. 여기서는 다음과 같습니다.

markerFormatFn: n => n % 20 === 0 ? n.toString() : '',

스 니펫을 확인하십시오.

//Gauge Plugin
(function() {
  if (!window.Chart) {
    return;
  }

  function GaugeChartHelper() {}
  GaugeChartHelper.prototype.setup = function(chart, config) {
    this.chart = chart;
    this.ctx = chart.ctx;
    this.limits = config.data.datasets[0].gaugeLimits;
    this.data = config.data.datasets[0].gaugeData;
    var options = chart.options;
    this.fontSize = options.defaultFontSize;
    this.fontStyle = options.defaultFontFamily;
    this.fontColor = options.defaultFontColor;
    this.ctx.textBaseline = "alphabetic";
    this.arrowAngle = 25 * Math.PI / 180;
    this.arrowColor = config.options.indicatorColor || options.arrowColor;
    this.showMarkers =
      typeof config.options.showMarkers === "undefined" ?
      true :
      config.options.showMarkers;
    if (config.options.markerFormatFn) {
      this.markerFormatFn = config.options.markerFormatFn;
    } else {
      this.markerFormatFn = function(value) {
        return value;
      };
    }
  };
  GaugeChartHelper.prototype.applyGaugeConfig = function(chartConfig) {
    this.calcLimits();
    chartConfig.data.datasets[0].data = this.doughnutData;
    var ctx = this.ctx;
    var labelsWidth = this.limits.map(
      function(label) {
        var text = this.markerFormatFn(label);
        return ctx.measureText(text).width;
      }.bind(this)
    );
    var padding = Math.max.apply(this, labelsWidth) + this.chart.width / 35;
    var heightRatio = this.chart.height / 50;
    chartConfig.options.layout.padding = {
      top: this.fontSize + heightRatio,
      left: padding,
      right: padding,
      bottom: heightRatio * 2
    };
  };
  GaugeChartHelper.prototype.calcLimits = function() {
    var limits = this.limits;
    var data = [];
    var total = 0;
    for (var i = 1, ln = limits.length; i < ln; i++) {
      var dataValue = Math.abs(limits[i] - limits[i - 1]);
      total += dataValue;
      data.push(dataValue);
    }
    this.doughnutData = data;
    var minValue = limits[0];
    var maxValue = limits[limits.length - 1];
    this.isRevers = minValue > maxValue;
    this.minValue = this.isRevers ? maxValue : minValue;
    this.totalValue = total;
  };
  GaugeChartHelper.prototype.updateGaugeDimensions = function() {
    var chartArea = this.chart.chartArea;
    this.gaugeRadius = this.chart.innerRadius;
    this.gaugeCenterX = (chartArea.left + chartArea.right) / 2;
    this.gaugeCenterY =
      (chartArea.top + chartArea.bottom + this.chart.outerRadius) / 2;
    this.arrowLength = this.chart.radiusLength * 2;
  };
  GaugeChartHelper.prototype.getCoordOnCircle = function(r, alpha) {
    return {
      x: r * Math.cos(alpha),
      y: r * Math.sin(alpha)
    };
  };
  GaugeChartHelper.prototype.getAngleOfValue = function(value) {
    var result = 0;
    var gaugeValue = value - this.minValue;
    if (gaugeValue <= 0) {
      result = 0;
    } else if (gaugeValue >= this.totalValue) {
      result = Math.PI;
    } else {
      result = Math.PI * gaugeValue / this.totalValue;
    }
    if (this.isRevers) {
      return Math.PI - result;
    } else {
      return result;
    }
  };
  GaugeChartHelper.prototype.renderLimitLabel = function(value) {
    var ctx = this.ctx;
    var angle = this.getAngleOfValue(value);
    var coord = this.getCoordOnCircle(
      this.chart.outerRadius + this.chart.radiusLength / 2,
      angle
    );
    var align;
    var diff = angle - Math.PI / 2;
    if (diff > 0) {
      align = "left";
    } else if (diff < 0) {
      align = "right";
    } else {
      align = "center";
    }
    ctx.textAlign = align;
    ctx.font = this.fontSize + "px " + this.fontStyle;
    ctx.fillStyle = this.fontColor;
    var text = this.markerFormatFn(value);
    ctx.fillText(
      text,
      this.gaugeCenterX - coord.x,
      this.gaugeCenterY - coord.y
    );
  };
  GaugeChartHelper.prototype.renderLimits = function() {
    for (var i = 0, ln = this.limits.length; i < ln; i++) {
      this.renderLimitLabel(this.limits[i]);
    }
  };
  GaugeChartHelper.prototype.renderValueLabel = function() {
    var label = this.data.value.toString();
    var ctx = this.ctx;
    ctx.font = "30px " + this.fontStyle;
    var stringWidth = ctx.measureText(label).width;
    var elementWidth = 0.75 * this.gaugeRadius * 2;
    var widthRatio = elementWidth / stringWidth;
    var newFontSize = Math.floor(30 * widthRatio);
    var fontSizeToUse = Math.min(newFontSize, this.gaugeRadius);
    ctx.textAlign = "center";
    ctx.font = fontSizeToUse + "px " + this.fontStyle;
    ctx.fillStyle = this.data.valueColor || this.fontColor;
    ctx.fillText(label, this.gaugeCenterX, this.gaugeCenterY);
  };
  GaugeChartHelper.prototype.renderValueArrow = function(value) {
    var angle = this.getAngleOfValue(
      typeof value === "number" ? value : this.data.value
    );
    this.ctx.globalCompositeOperation = "source-over";
    this.renderArrow(
      this.gaugeRadius,
      angle,
      this.arrowLength,
      this.arrowAngle,
      this.arrowColor
    );
  };
  GaugeChartHelper.prototype.renderSmallValueArrow = function(value) {
    var angle = this.getAngleOfValue(value);
    this.ctx.globalCompositeOperation = "source-over";
    this.renderArrow(
      this.gaugeRadius - 1,
      angle,
      this.arrowLength - 1,
      this.arrowAngle,
      this.arrowColor
    );
  };
  GaugeChartHelper.prototype.clearValueArrow = function(value) {
    var angle = this.getAngleOfValue(value);
    this.ctx.lineWidth = 2;
    this.ctx.globalCompositeOperation = "destination-out";
    this.renderArrow(
      this.gaugeRadius - 1,
      angle,
      this.arrowLength + 1,
      this.arrowAngle,
      "#FFFFFF"
    );
    this.ctx.stroke();
  };
  GaugeChartHelper.prototype.renderArrow = function(
    radius,
    angle,
    arrowLength,
    arrowAngle,
    arrowColor
  ) {
    var coord = this.getCoordOnCircle(radius, angle);
    var arrowPoint = {
      x: this.gaugeCenterX - coord.x,
      y: this.gaugeCenterY - coord.y
    };
    var ctx = this.ctx;
    ctx.fillStyle = arrowColor;
    ctx.beginPath();
    ctx.moveTo(arrowPoint.x, arrowPoint.y);
    coord = this.getCoordOnCircle(arrowLength, angle + arrowAngle);
    ctx.lineTo(arrowPoint.x + coord.x, arrowPoint.y + coord.y);
    coord = this.getCoordOnCircle(arrowLength, angle - arrowAngle);
    ctx.lineTo(arrowPoint.x + coord.x, arrowPoint.y + coord.y);
    ctx.closePath();
    ctx.fill();
  };
  GaugeChartHelper.prototype.animateArrow = function() {
    var stepCount = 30;
    var animateTimeout = 300;
    var gaugeValue = this.data.value - this.minValue;
    var step = gaugeValue / stepCount;
    var i = 0;
    var currentValue = this.minValue;
    var interval = setInterval(
      function() {
        i++;
        this.clearValueArrow(currentValue);
        if (i > stepCount) {
          clearInterval(interval);
          this.renderValueArrow();
        } else {
          currentValue += step;
          this.renderSmallValueArrow(currentValue);
        }
      }.bind(this),
      animateTimeout / stepCount
    );
  };
  Chart.defaults.tsgauge = {
    animation: {
      animateRotate: true,
      animateScale: false
    },
    cutoutPercentage: 95,
    rotation: Math.PI,
    circumference: Math.PI,
    legend: {
      display: false
    },
    scales: {},
    arrowColor: "#444"
  };
  Chart.controllers.tsgauge = Chart.controllers.doughnut.extend({
    initialize: function(chart) {
      var gaugeHelper = (this.gaugeHelper = new GaugeChartHelper());
      gaugeHelper.setup(chart, chart.config);
      gaugeHelper.applyGaugeConfig(chart.config);
      chart.config.options.animation.onComplete = function(chartElement) {
        gaugeHelper.updateGaugeDimensions();
        gaugeHelper.animateArrow();
      };
      Chart.controllers.doughnut.prototype.initialize.apply(this, arguments);
    },
    draw: function() {
      Chart.controllers.doughnut.prototype.draw.apply(this, arguments);
      var gaugeHelper = this.gaugeHelper;
      gaugeHelper.updateGaugeDimensions();
      gaugeHelper.renderValueLabel();
      if (gaugeHelper.showMarkers) {
        gaugeHelper.renderLimits();
      }
      gaugeHelper.renderSmallValueArrow(gaugeHelper.minValue);
    }
  });
})();

//Chart setup

var ctx = document.getElementById("chart3").getContext("2d");
new Chart(ctx, {
  type: "tsgauge",
  data: {
    datasets: [{
      backgroundColor: ["#0fdc63", "#0fdc63", "#fd9704", "#fd9704", "#fd9704", "#ff7143", "#ff7143"],
      borderWidth: 0,
      gaugeData: {
        value: 50,
        valueColor: "#ff7143"
      },
      gaugeLimits: [0, 20, 30, 40, 60, 70, 80, 100],
    }]
  },
  options: {
    events: [],
    showMarkers: true,
    markerFormatFn: n => n % 20 === 0 ? n.toString() : '',
  }
});
.gauge {
  width: 500px;
  height: 400px;
}
<link href="https://cdn.jsdelivr.net/npm/chart.js@2.9.2/dist/Chart.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.2/dist/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>


<div class="gauge">
  <canvas id="chart3"></canvas>
</div>


"이제 색상에 대해 각각의 guageLimits는 backgroundColor 배열의 색상이 필요합니다." 현재 guageLimits를 그릴 때 색인을 확인하고 backgroundColor [index]를 배경색으로 사용합니다. 질문에서 볼 수있는 것처럼 게이지 색상 속성에 따라 배경을 그려보고 싶습니다. 그리고 왜 Whould를 원하는지 궁금하다면? "10-15-20-25-30-35 ... 등"과 같이 차트에 너무 많은 레이블을 표시하고 싶지 않기 때문입니다.
kenarsuleyman

@kenarsuleyman 작동 했습니까? 그렇다면 답변을 수락 된 것으로 표시 할 수 있습니다. :)
Towkir

예, 완벽하게 작동합니다. 그 노력에 정말 감사합니다. 나는 다른 직업으로 바빠서 미안했다.
kenarsuleyman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.