import PluginService from './core.plugins.js';
import registry from './core.registry.js';
import Config, {determineAxis, getIndexAxis} from './core.config.js';
-import {retinaScale, _isDomSupported} from '../helpers/helpers.dom.js';
import {each, callback as callCallback, uid, valueOrDefault, _elementsEqual, isNullOrUndef, setsEqual, defined, isFunction, _isClickEvent} from '../helpers/helpers.core.js';
-import {clearCanvas, clipArea, createContext, unclipArea, _isPointInArea} from '../helpers/index.js';
+import {clearCanvas, clipArea, createContext, unclipArea, _isPointInArea, _isDomSupported, retinaScale, getDatasetClipArea} from '../helpers/index.js';
// @ts-ignore
import {version} from '../../package.json';
import {debounce} from '../helpers/helpers.extras.js';
return e;
}
-function getSizeForArea(scale, chartArea, field) {
- return scale.options.clip ? scale[field] : chartArea[field];
-}
-
-function getDatasetArea(meta, chartArea) {
- const {xScale, yScale} = meta;
- if (xScale && yScale) {
- return {
- left: getSizeForArea(xScale, chartArea, 'left'),
- right: getSizeForArea(xScale, chartArea, 'right'),
- top: getSizeForArea(yScale, chartArea, 'top'),
- bottom: getSizeForArea(yScale, chartArea, 'bottom')
- };
- }
- return chartArea;
-}
-
class Chart {
static defaults = defaults;
*/
_drawDataset(meta) {
const ctx = this.ctx;
- const clip = meta._clip;
- const useClip = !clip.disabled;
- const area = getDatasetArea(meta, this.chartArea);
const args = {
meta,
index: meta.index,
cancelable: true
};
+ // @ts-expect-error
+ const clip = getDatasetClipArea(this, meta);
if (this.notifyPlugins('beforeDatasetDraw', args) === false) {
return;
}
- if (useClip) {
- clipArea(ctx, {
- left: clip.left === false ? 0 : area.left - clip.left,
- right: clip.right === false ? this.width : area.right + clip.right,
- top: clip.top === false ? 0 : area.top - clip.top,
- bottom: clip.bottom === false ? this.height : area.bottom + clip.bottom
- });
+ if (clip) {
+ clipArea(ctx, clip);
}
meta.controller.draw();
- if (useClip) {
+ if (clip) {
unclipArea(ctx);
}
--- /dev/null
+import type {Chart, ChartArea, ChartMeta, Scale, TRBL} from '../types/index.js';
+
+function getSizeForArea(scale: Scale, chartArea: ChartArea, field: keyof ChartArea) {
+ return scale.options.clip ? scale[field] : chartArea[field];
+}
+
+function getDatasetArea(meta: ChartMeta, chartArea: ChartArea): TRBL {
+ const {xScale, yScale} = meta;
+ if (xScale && yScale) {
+ return {
+ left: getSizeForArea(xScale, chartArea, 'left'),
+ right: getSizeForArea(xScale, chartArea, 'right'),
+ top: getSizeForArea(yScale, chartArea, 'top'),
+ bottom: getSizeForArea(yScale, chartArea, 'bottom')
+ };
+ }
+ return chartArea;
+}
+
+export function getDatasetClipArea(chart: Chart, meta: ChartMeta): TRBL | false {
+ const clip = meta._clip;
+ if (clip.disabled) {
+ return false;
+ }
+ const area = getDatasetArea(meta, chart.chartArea);
+
+ return {
+ left: clip.left === false ? 0 : area.left - (clip.left === true ? 0 : clip.left),
+ right: clip.right === false ? chart.width : area.right + (clip.right === true ? 0 : clip.right),
+ top: clip.top === false ? 0 : area.top - (clip.top === true ? 0 : clip.top),
+ bottom: clip.bottom === false ? chart.height : area.bottom + (clip.bottom === true ? 0 : clip.bottom)
+ };
+}
export * from './helpers.math.js';
export * from './helpers.rtl.js';
export * from './helpers.segment.js';
+export * from './helpers.dataset.js';
-import {clipArea, unclipArea} from '../../helpers/index.js';
+import {clipArea, unclipArea, getDatasetClipArea} from '../../helpers/index.js';
import {_findSegmentEnd, _getBounds, _segments} from './filler.segment.js';
import {_getTarget} from './filler.target.js';
export function _drawfill(ctx, source, area) {
const target = _getTarget(source);
- const {line, scale, axis} = source;
+ const {chart, index, line, scale, axis} = source;
const lineOpts = line.options;
const fillOption = lineOpts.fill;
const color = lineOpts.backgroundColor;
const {above = color, below = color} = fillOption || {};
+ const meta = chart.getDatasetMeta(index);
+ const clip = getDatasetClipArea(chart, meta);
if (target && line.points.length) {
clipArea(ctx, area);
- doFill(ctx, {line, target, above, below, area, scale, axis});
+ doFill(ctx, {line, target, above, below, area, scale, axis, clip});
unclipArea(ctx);
}
}
function doFill(ctx, cfg) {
- const {line, target, above, below, area, scale} = cfg;
+ const {line, target, above, below, area, scale, clip} = cfg;
const property = line._loop ? 'angle' : cfg.axis;
ctx.save();
if (property === 'x' && below !== above) {
clipVertical(ctx, target, area.top);
- fill(ctx, {line, target, color: above, scale, property});
+ fill(ctx, {line, target, color: above, scale, property, clip});
ctx.restore();
ctx.save();
clipVertical(ctx, target, area.bottom);
}
- fill(ctx, {line, target, color: below, scale, property});
+ fill(ctx, {line, target, color: below, scale, property, clip});
ctx.restore();
}
}
function fill(ctx, cfg) {
- const {line, target, property, color, scale} = cfg;
+ const {line, target, property, color, scale, clip} = cfg;
const segments = _segments(line, target, property);
for (const {source: src, target: tgt, start, end} of segments) {
ctx.save();
ctx.fillStyle = backgroundColor;
- clipBounds(ctx, scale, notShape && _getBounds(property, start, end));
+ clipBounds(ctx, scale, clip, notShape && _getBounds(property, start, end));
ctx.beginPath();
}
}
-function clipBounds(ctx, scale, bounds) {
- const {top, bottom} = scale.chart.chartArea;
+function clipBounds(ctx, scale, clip, bounds) {
+ const chartArea = scale.chart.chartArea;
const {property, start, end} = bounds || {};
- if (property === 'x') {
+
+ if (property === 'x' || property === 'y') {
+ let left, top, right, bottom;
+
+ if (property === 'x') {
+ left = start;
+ top = chartArea.top;
+ right = end;
+ bottom = chartArea.bottom;
+ } else {
+ left = chartArea.left;
+ top = start;
+ right = chartArea.right;
+ bottom = end;
+ }
+
ctx.beginPath();
- ctx.rect(start, top, end - start, bottom - top);
+
+ if (clip) {
+ left = Math.max(left, clip.left);
+ right = Math.min(right, clip.right);
+ top = Math.max(top, clip.top);
+ bottom = Math.min(bottom, clip.bottom);
+ }
+
+ ctx.rect(left, top, right - left, bottom - top);
ctx.clip();
}
}
prototype: RadarController;
new (chart: Chart, datasetIndex: number): RadarController;
};
+
+interface ChartMetaClip {
+ left: number | boolean;
+ top: number | boolean;
+ right: number | boolean;
+ bottom: number | boolean;
+ disabled: boolean;
+}
+
interface ChartMetaCommon<TElement extends Element = Element, TDatasetElement extends Element = Element> {
type: string;
controller: DatasetController;
_sorted: boolean;
_stacked: boolean | 'single';
_parsed: unknown[];
+ _clip: ChartMetaClip;
}
export type ChartMeta<
--- /dev/null
+const labels = [1, 2, 3, 4, 5, 6, 7];
+const values = [65, 59, 80, 81, 56, 55, 40];
+
+module.exports = {
+ description: 'https://github.com/chartjs/Chart.js/issues/12052',
+ config: {
+ type: 'line',
+ data: {
+ labels,
+ datasets: [
+ {
+ data: values.map(v => v - 10),
+ fill: '1',
+ borderColor: 'rgb(255, 0, 0)',
+ backgroundColor: 'rgba(255, 0, 0, 0.25)',
+ xAxisID: 'x1',
+ },
+ {
+ data: values,
+ fill: false,
+ borderColor: 'rgb(255, 0, 0)',
+ xAxisID: 'x1',
+ },
+ {
+ data: values,
+ fill: false,
+ borderColor: 'rgb(0, 0, 255)',
+ xAxisID: 'x2',
+ },
+ {
+ data: values.map(v => v + 10),
+ fill: '-1',
+ borderColor: 'rgb(0, 0, 255)',
+ backgroundColor: 'rgba(0, 0, 255, 0.25)',
+ xAxisID: 'x2',
+ }
+ ]
+ },
+ options: {
+ clip: false,
+ indexAxis: 'y',
+ animation: false,
+ responsive: false,
+ plugins: {
+ legend: false,
+ title: false,
+ tooltip: false
+ },
+ elements: {
+ point: {
+ radius: 0
+ },
+ line: {
+ cubicInterpolationMode: 'monotone',
+ borderColor: 'transparent',
+ tension: 0
+ }
+ },
+ scales: {
+ x2: {
+ axis: 'x',
+ stack: 'stack',
+ max: 80,
+ display: false,
+ },
+ x1: {
+ min: 50,
+ axis: 'x',
+ stack: 'stack',
+ display: false,
+ },
+ y: {
+ display: false,
+ }
+ }
+ }
+ },
+};
--- /dev/null
+const labels = [1, 2, 3, 4, 5, 6, 7];
+const values = [65, 59, 80, 81, 56, 55, 40];
+
+module.exports = {
+ description: 'https://github.com/chartjs/Chart.js/issues/12052',
+ config: {
+ type: 'line',
+ data: {
+ labels,
+ datasets: [
+ {
+ data: values.map(v => v - 10),
+ fill: '1',
+ borderColor: 'rgb(255, 0, 0)',
+ backgroundColor: 'rgba(255, 0, 0, 0.25)',
+ xAxisID: 'x1',
+ },
+ {
+ data: values,
+ fill: false,
+ borderColor: 'rgb(255, 0, 0)',
+ xAxisID: 'x1',
+ },
+ {
+ data: values,
+ fill: false,
+ borderColor: 'rgb(0, 0, 255)',
+ xAxisID: 'x2',
+ },
+ {
+ data: values.map(v => v + 10),
+ fill: '-1',
+ borderColor: 'rgb(0, 0, 255)',
+ backgroundColor: 'rgba(0, 0, 255, 0.25)',
+ xAxisID: 'x2',
+ }
+ ]
+ },
+ options: {
+ indexAxis: 'y',
+ animation: false,
+ responsive: false,
+ plugins: {
+ legend: false,
+ title: false,
+ tooltip: false
+ },
+ elements: {
+ point: {
+ radius: 0
+ },
+ line: {
+ cubicInterpolationMode: 'monotone',
+ borderColor: 'transparent',
+ tension: 0
+ }
+ },
+ scales: {
+ x2: {
+ axis: 'x',
+ stack: 'stack',
+ max: 80,
+ display: false,
+ },
+ x1: {
+ min: 50,
+ axis: 'x',
+ stack: 'stack',
+ display: false,
+ },
+ y: {
+ display: false,
+ }
+ }
+ }
+ },
+};
--- /dev/null
+const labels = [1, 2, 3, 4, 5, 6, 7];
+const values = [65, 59, 80, 81, 56, 55, 40];
+
+module.exports = {
+ description: 'https://github.com/chartjs/Chart.js/issues/12052',
+ config: {
+ type: 'line',
+ data: {
+ labels,
+ datasets: [
+ {
+ data: values.map(v => v - 10),
+ fill: '1',
+ borderColor: 'rgb(255, 0, 0)',
+ backgroundColor: 'rgba(255, 0, 0, 0.25)',
+ yAxisID: 'y1',
+ },
+ {
+ data: values,
+ fill: false,
+ borderColor: 'rgb(255, 0, 0)',
+ yAxisID: 'y1',
+ },
+ {
+ data: values,
+ fill: false,
+ borderColor: 'rgb(0, 0, 255)',
+ yAxisID: 'y2',
+ },
+ {
+ data: values.map(v => v + 10),
+ fill: '-1',
+ borderColor: 'rgb(0, 0, 255)',
+ backgroundColor: 'rgba(0, 0, 255, 0.25)',
+ yAxisID: 'y2',
+ }
+ ]
+ },
+ options: {
+ clip: false,
+ animation: false,
+ responsive: false,
+ plugins: {
+ legend: false,
+ title: false,
+ tooltip: false
+ },
+ elements: {
+ point: {
+ radius: 0
+ },
+ line: {
+ cubicInterpolationMode: 'monotone',
+ borderColor: 'transparent',
+ tension: 0
+ }
+ },
+ scales: {
+ y2: {
+ axis: 'y',
+ stack: 'stack',
+ max: 80,
+ display: false,
+ },
+ y1: {
+ min: 50,
+ axis: 'y',
+ stack: 'stack',
+ display: false,
+ },
+ x: {
+ display: false,
+ }
+ }
+ }
+ },
+};
--- /dev/null
+const labels = [1, 2, 3, 4, 5, 6, 7];
+const values = [65, 59, 80, 81, 56, 55, 40];
+
+module.exports = {
+ description: 'https://github.com/chartjs/Chart.js/issues/12052',
+ config: {
+ type: 'line',
+ data: {
+ labels,
+ datasets: [
+ {
+ data: values.map(v => v - 10),
+ fill: '1',
+ borderColor: 'rgb(255, 0, 0)',
+ backgroundColor: 'rgba(255, 0, 0, 0.25)',
+ yAxisID: 'y1',
+ },
+ {
+ data: values,
+ fill: false,
+ borderColor: 'rgb(255, 0, 0)',
+ yAxisID: 'y1',
+ },
+ {
+ data: values,
+ fill: false,
+ borderColor: 'rgb(0, 0, 255)',
+ yAxisID: 'y2',
+ },
+ {
+ data: values.map(v => v + 10),
+ fill: '-1',
+ borderColor: 'rgb(0, 0, 255)',
+ backgroundColor: 'rgba(0, 0, 255, 0.25)',
+ yAxisID: 'y2',
+ }
+ ]
+ },
+ options: {
+ animation: false,
+ responsive: false,
+ plugins: {
+ legend: false,
+ title: false,
+ tooltip: false
+ },
+ elements: {
+ point: {
+ radius: 0
+ },
+ line: {
+ cubicInterpolationMode: 'monotone',
+ borderColor: 'transparent',
+ tension: 0
+ }
+ },
+ scales: {
+ y2: {
+ axis: 'y',
+ stack: 'stack',
+ max: 80,
+ display: false,
+ },
+ y1: {
+ min: 50,
+ axis: 'y',
+ stack: 'stack',
+ display: false,
+ },
+ x: {
+ display: false,
+ }
+ }
+ }
+ },
+};