1👍
✅
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>
Source:stackexchange.com