ChartJS-未绘制Y轴线

时间:2019-07-09 18:15:02

标签: javascript css charts chart.js

我正在使用ChartJS制作图表。一切都进行得很顺利,但有一个例外:尽管正在绘制X轴线(沿图表底部水平延伸的线),但是Y轴线(沿图表垂直方向延伸的线)却没有,尽管我已经应用了几乎相同的配置。

我对此进行了广泛的尝试,无法弄清楚我在做什么错。

我快要尝试做些棘手的事情了(基本上,在尝试使用容器确定其长度和位置后,绝对要在图表上方放置一条线-有点噩梦),但是我想看看这里是否有人对ChartJS更加熟悉,可能会对我做错了。

Here's the CodePen(其余文章下方的JS)。

下面是the styling documentation,我正在尝试使其正常运行。 (请参见zeroLineWidth和zeroLineColor值)。

有什么想法我做错了什么,或者如何解决这个问题?

// Colors
const squidInk = '#232F3E'; // Background and hover circle interior
const mermaid = '#00A4B4'; // Gridlines
const siren = '#0099D9'; // Line and points
const darkGrey = '#3A444F'; // Fill below line - NOTE: doesn't seem to be one of main colors
const white = '#FFF'; // Font white - in one place to change globally (sync w CSS)

const mobileBreakpoint = 768;

const isMobile = window.innerWidth <= mobileBreakpoint;

// Helper for below tooltip generation
const getTooltipStyles = (tooltipModel, position) => ({
  opacity: 1,
  position: 'absolute',
  left: position.left + window.pageXOffset + tooltipModel.caretX + 'px',
  top: position.top + window.pageYOffset + tooltipModel.caretY + 'px',
  fontFamily: tooltipModel._bodyFontFamily,
  fontSize: tooltipModel.bodyFontSize + 'px',
  fontStyle: tooltipModel._bodyFontStyle,
  padding: tooltipModel.yPadding + 'px ' + tooltipModel.xPadding + 'px',
  pointerEvents: 'none'
});

// Chart points (y-coords; there are 20).
// Loosely approximates the data in the designs.
const points = [
   4,  4,  8, 19, 22,
  25, 27, 27, 28, 30,
  32, 34, 40, 44, 46,
  48, 52, 53, 55, 57
];

// The value of the data key in the Chart config.
// Contains points in the main (only) dataset, 
// and related configuration.
const data = {
  // Years from 1997 to 2016. 
  // Hide all but first and last label on mobile
  labels: points.map((_, ind) => 
    isMobile && ![0, points.length - 1].includes(ind) 
      ? '' 
      : 1997 + ind
  ),
  datasets: [{ 
    data: points,
    fill: true,
    backgroundColor: darkGrey,
    borderColor: siren,
    borderWidth: 4,
    pointHitRadius: 20,
    pointRadius: isMobile ? 0 : 2,
    pointHoverRadius: isMobile ? 0 : 10,
    pointHoverBackgroundColor: squidInk,
    pointHoverBorderWidth: 3
  }]
};

// Function to replace the tooltip with custom HTML.
// NOTE: This needs to be a function, not a const, because of how
// `this` is bound.
function customTooltip (tooltipModel) {
  if (isMobile) {
    return '';
  }

  // Tooltip Element
  let tooltipEl = document.getElementById('chartjs-tooltip');

  // Create element on first render
  if (!tooltipEl) {
    tooltipEl = document.createElement('div');
    tooltipEl.id = 'chartjs-tooltip';
    tooltipEl.innerHTML = '<div></div>';
    document.body.appendChild(tooltipEl);
  }

  // Hide if no tooltip
  if (tooltipModel.opacity === 0) {
    tooltipEl.style.opacity = 0;
    return;
  }

  // Set caret Position
  tooltipEl.classList.remove('above', 'below', 'no-transform');
  tooltipEl.classList.add(
    tooltipModel.yAlign 
      ? tooltipModel.yAlign
      : 'no-transform'
  );

  // Set Text
  if (tooltipModel.body) {
    const titleLines = tooltipModel.title || [];
    const bodyLines = tooltipModel.body.map(bodyItem => bodyItem.lines);

    // Text for hover percentages
    const percentExternal = bodyLines[0];
    const percentSellers = 100 - percentExternal;

    // These spans are styled in the CSS
    const innerHtml = `
      <span class="percent-tooltip external">${percentExternal}%</span>
      <span class="percent-tooltip sellers">${percentSellers}%</span>
    `;

    const root = tooltipEl.querySelector('div');
    root.innerHTML = innerHtml;
  }

  // `this` will be the overall tooltip
  const position = this._chart.canvas.getBoundingClientRect();

  // Apply positional styles to the tooltip (cleaned up and put above for clarity)
  const styles = getTooltipStyles(tooltipModel, position);
  Object.keys(styles).forEach(k => tooltipEl.style[k] = styles[k]);
};

// High-level chart options
const options = { 
  legend: {
    display: false
  },
  tooltips: {
    enabled: false,
    custom: customTooltip // Custom tooltip func (above)
  },
  scales: {
    yAxes: [{
      ticks: {
        // Include a percentage sign in the ticks.
        // Hide zero label on mobile.
        callback: value => isMobile ? (value ? `${value}%` : '') : `${value}%`,
        fontColor: white,
        max: 100,
        stepSize: isMobile ? 50 : 25
      },
      scaleLabel: {
        display: !isMobile,
        labelString: '% OF MERCHANDISE SALES',
        fontColor: white
      },
      gridLines: {
        color: mermaid,
        zeroLineColor: white,
        zeroLineWidth: 2,
        drawBorder: false
      }
    }],
    xAxes: [{
      gridLines: {
        drawOnChartArea: false,
        // The x zero-line isn't painting! Maybe because it's not at zero (but at 1997)?
        // NOTE: I tried fixing this by messing with the data, so that the x-axis included 0, but that didn't work.
        zeroLineColor: white,
        zeroLineWidth: 2
      },
      ticks: {
        fontColor: white
      }
    }]
  }
};

// Find the div to insert the chart into
const ctx = document.getElementById('chart').getContext('2d');

// And generate the chart
const chart = new Chart(ctx, {
  type: 'line',
  data,
  options,
});

1 个答案:

答案 0 :(得分:1)

不确定为什么选项zeroLineColor适用于一个轴,而不适用于另一个轴。

但是我们可以为网格线使用颜色数组,
将第一个设置为白色,其余设置为透明。

请参阅以下工作片段...

$(document).ready(function() {

  // Colors
  const squidInk = '#232F3E'; // Background and hover circle interior
  const mermaid = '#00A4B4'; // Gridlines
  const siren = '#0099D9'; // Line and points
  const darkGrey = '#3A444F'; // Fill below line - NOTE: doesn't seem to be one of main colors
  const white = '#FFF'; // Font white - in one place to change globally (sync w CSS)
  const transparent = 'transparent';

  const mobileBreakpoint = 768;

  const isMobile = window.innerWidth <= mobileBreakpoint;

  // Helper for below tooltip generation
  const getTooltipStyles = (tooltipModel, position) => ({
    opacity: 1,
    position: 'absolute',
    left: position.left + window.pageXOffset + tooltipModel.caretX + 'px',
    top: position.top + window.pageYOffset + tooltipModel.caretY + 'px',
    fontFamily: tooltipModel._bodyFontFamily,
    fontSize: tooltipModel.bodyFontSize + 'px',
    fontStyle: tooltipModel._bodyFontStyle,
    padding: tooltipModel.yPadding + 'px ' + tooltipModel.xPadding + 'px',
    pointerEvents: 'none'
  });

  // Chart points (y-coords; there are 20).
  // Loosely approximates the data in the designs.
  const points = [
     4,  4,  8, 19, 22,
    25, 27, 27, 28, 30,
    32, 34, 40, 44, 46,
    48, 52, 53, 55, 57
  ];

  // The value of the data key in the Chart config.
  // Contains points in the main (only) dataset,
  // and related configuration.
  const data = {
    // Years from 1997 to 2016.
    // Hide all but first and last label on mobile
    labels: points.map((_, ind) =>
      isMobile && ![0, points.length - 1].includes(ind)
        ? ''
        : 1997 + ind
    ),
    datasets: [{
      data: points,
      fill: true,
      backgroundColor: darkGrey,
      borderColor: siren,
      borderWidth: 4,
      pointHitRadius: 20,
      pointRadius: isMobile ? 0 : 2,
      pointHoverRadius: isMobile ? 0 : 10,
      pointHoverBackgroundColor: squidInk,
      pointHoverBorderWidth: 3
    }]
  };

  // Function to replace the tooltip with custom HTML.
  // NOTE: This needs to be a function, not a const, because of how
  // `this` is bound.
  function customTooltip (tooltipModel) {
    if (isMobile) {
      return '';
    }

    // Tooltip Element
    let tooltipEl = document.getElementById('chartjs-tooltip');

    // Create element on first render
    if (!tooltipEl) {
      tooltipEl = document.createElement('div');
      tooltipEl.id = 'chartjs-tooltip';
      tooltipEl.innerHTML = '<div></div>';
      document.body.appendChild(tooltipEl);
    }

    // Hide if no tooltip
    if (tooltipModel.opacity === 0) {
      tooltipEl.style.opacity = 0;
      return;
    }

    // Set caret Position
    tooltipEl.classList.remove('above', 'below', 'no-transform');
    tooltipEl.classList.add(
      tooltipModel.yAlign
        ? tooltipModel.yAlign
        : 'no-transform'
    );

    // Set Text
    if (tooltipModel.body) {
      const titleLines = tooltipModel.title || [];
      const bodyLines = tooltipModel.body.map(bodyItem => bodyItem.lines);

      // Text for hover percentages
      const percentExternal = bodyLines[0];
      const percentSellers = 100 - percentExternal;

      // These spans are styled in the CSS
      const innerHtml = `
        <span class="percent-tooltip external">${percentExternal}%</span>
        <span class="percent-tooltip sellers">${percentSellers}%</span>
      `;

      const root = tooltipEl.querySelector('div');
      root.innerHTML = innerHtml;
    }

    // `this` will be the overall tooltip
    const position = this._chart.canvas.getBoundingClientRect();

    // Apply positional styles to the tooltip (cleaned up and put above for clarity)
    const styles = getTooltipStyles(tooltipModel, position);
    Object.keys(styles).forEach(k => tooltipEl.style[k] = styles[k]);
  };

  // High-level chart options
  const options = {
    legend: {
      display: false
    },
    tooltips: {
      enabled: false,
      custom: customTooltip // Custom tooltip func (above)
    },
    scales: {
      yAxes: [{
        ticks: {
          // Include a percentage sign in the ticks.
          // Hide zero label on mobile.
          callback: value => isMobile ? (value ? `${value}%` : '') : `${value}%`,
          fontColor: white,
          max: 100,
          stepSize: isMobile ? 50 : 25
        },
        scaleLabel: {
          display: !isMobile,
          labelString: '% OF MERCHANDISE SALES',
          fontColor: white
        },
        gridLines: {
          color: mermaid,
          zeroLineColor: white,
          zeroLineWidth: 2,
          drawBorder: false
        }
      }],
      xAxes: [{
        gridLines: {
          color: points.map((_, ind) =>
            ind === 0
              ? white
              : transparent
          ),
          lineWidth: 2
        },
        ticks: {
          fontColor: white
        }
      }]
    }
  };

  // Find the div to insert the chart into
  const ctx = document.getElementById('chart').getContext('2d');

  // And generate the chart
  const chart = new Chart(ctx, {
    type: 'line',
    data,
    options,
  });

});
.container {
  /* squidInk - matches JS */
  background-color: #232F3E;
  position: relative;
  width: 100%;
}

.section-label {
  color: white;
  font-size: 20px;
  position: absolute;
}

.section-label.upper {
  left: 100px;
  top: 60px;
}

.section-label.lower {
  right: 60px;
  bottom: 60px;
}

#chartjs-tooltip div {
  position: absolute;
  left: -10px;
  top: -10px;
  cursor: pointer;
}

#chartjs-tooltip .percent-tooltip {
  font-size: 20px;
  font-weight: bold;
  display: block;
  position: absolute;
  color: white;
}

#chartjs-tooltip span.percent-tooltip.external {
  top: -30px;
}

#chartjs-tooltip span.percent-tooltip.sellers {
  top: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<div class="container">
  <span class="section-label upper">Internal</span>
  <canvas id="chart" width="300" height="150"></canvas>
  <span class="section-label lower">External</span>
</div>