简体   繁体   中英

ChartJS - Y Axis line not drawing

I'm making a chart using ChartJS. Everything has gone smoothly, with one exception: Although the X-axis line (the line that runs horizontally along the base of the chart) is drawing, the Y-axis line (the one that runs vertically along the left) is not, even though I've applied nearly identical configurations.

I've played around with this extensively, and can't figure out what I'm doing wrong.

I'm getting near trying to do something hacky (basically, absolutely position a line on top of the chart, after trying to use the container to determine its length and location -- a bit of a nightmare), but I wanted to see if anyone here who was more familiar with ChartJS might have a sense of what I'm doing wrong.

Here's the CodePen (JS below the rest of the post).

And here's the styling documentation I was following to attempt to get it working. (See the zeroLineWidth and zeroLineColor values).

Any ideas what I'm doing wrong, or how to fix this?

// 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,
});

not sure why option zeroLineColor works for one axis, and not the other.

but we can use an array of colors for the gridlines,
setting the first as white, and the rest as transparent.

see following working snippet...

 $(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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM