]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Add chart, p0.raw, p1.raw to segment context (#9761)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Fri, 15 Oct 2021 19:56:29 +0000 (22:56 +0300)
committerGitHub <noreply@github.com>
Fri, 15 Oct 2021 19:56:29 +0000 (15:56 -0400)
* Add chart, p0.raw, p1.raw to segment context

* Types

src/controllers/controller.line.js
src/core/core.controller.js
src/core/core.datasetController.js
src/core/core.scale.js
src/elements/element.line.js
src/helpers/helpers.options.js
src/helpers/helpers.segment.js
src/plugins/plugin.tooltip.js
src/scales/scale.radialLinear.js
types/helpers/helpers.options.d.ts
types/tests/helpers/options.ts [new file with mode: 0644]

index 970cc837924913b570334f995f6b3e0bf73b4274..a62d9be895a1e598bce7e1aa18e9595378045df3 100644 (file)
@@ -26,6 +26,7 @@ export default class LineController extends DatasetController {
     }
 
     // Update Line
+    line._chart = this.chart;
     line._datasetIndex = this.index;
     line._decimated = !!_dataset._decimated;
     line.points = points;
@@ -46,13 +47,13 @@ export default class LineController extends DatasetController {
 
   updateElements(points, start, count, mode) {
     const reset = mode === 'reset';
-    const {iScale, vScale, _stacked} = this._cachedMeta;
+    const {iScale, vScale, _stacked, _dataset} = this._cachedMeta;
     const firstOpts = this.resolveDataElementOptions(start, mode);
     const sharedOptions = this.getSharedOptions(firstOpts);
     const includeOptions = this.includeOptions(mode, sharedOptions);
     const iAxis = iScale.axis;
     const vAxis = vScale.axis;
-    const spanGaps = this.options.spanGaps;
+    const {spanGaps, segment} = this.options;
     const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
     const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';
     let prevParsed = start > 0 && this.getParsed(start - 1);
@@ -67,7 +68,10 @@ export default class LineController extends DatasetController {
 
       properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData;
       properties.stop = i > 0 && (parsed[iAxis] - prevParsed[iAxis]) > maxGapLength;
-      properties.parsed = parsed;
+      if (segment) {
+        properties.parsed = parsed;
+        properties.raw = _dataset.data[i];
+      }
 
       if (includeOptions) {
         properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
index 3ba3b2fd748478ae61f7a1b4f523b01f0d7f90ff..8e288578d6ac411933eda35f657319f9ec4f11a3 100644 (file)
@@ -8,7 +8,7 @@ import registry from './core.registry';
 import Config, {determineAxis, getIndexAxis} from './core.config';
 import {retinaScale, _isDomSupported} from '../helpers/helpers.dom';
 import {each, callback as callCallback, uid, valueOrDefault, _elementsEqual, isNullOrUndef, setsEqual, defined, isFunction} from '../helpers/helpers.core';
-import {clearCanvas, clipArea, unclipArea, _isPointInArea} from '../helpers/helpers.canvas';
+import {clearCanvas, clipArea, createContext, unclipArea, _isPointInArea} from '../helpers';
 // @ts-ignore
 import {version} from '../../package.json';
 import {debounce} from '../helpers/helpers.extras';
@@ -735,7 +735,7 @@ class Chart {
   }
 
   getContext() {
-    return this.$context || (this.$context = {chart: this, type: 'chart'});
+    return this.$context || (this.$context = createContext(null, {chart: this, type: 'chart'}));
   }
 
   getVisibleDatasetCount() {
index 63aea1f33ad31a634424e688ed7c1ba8caba1628..1794c7031b97af0682da58d2f6735db85f28c373 100644 (file)
@@ -2,7 +2,7 @@ import Animations from './core.animations';
 import defaults from './core.defaults';
 import {isArray, isFinite, isObject, valueOrDefault, resolveObjectKey, defined} from '../helpers/helpers.core';
 import {listenArrayEvents, unlistenArrayEvents} from '../helpers/helpers.collection';
-import {sign} from '../helpers/helpers.math';
+import {createContext, sign} from '../helpers';
 
 /**
  * @typedef { import("./core.controller").default } Chart
@@ -167,7 +167,7 @@ function getFirstScaleId(chart, axis) {
 }
 
 function createDatasetContext(parent, index) {
-  return Object.assign(Object.create(parent),
+  return createContext(parent,
     {
       active: false,
       dataset: undefined,
@@ -180,7 +180,7 @@ function createDatasetContext(parent, index) {
 }
 
 function createDataContext(parent, index, element) {
-  return Object.assign(Object.create(parent), {
+  return createContext(parent, {
     active: false,
     dataIndex: index,
     parsed: undefined,
index 4549cadb9d93adbfcf38e488bac863152aa6c5a0..97529e591a9ba0ab12cb42acfb8d9e8995de3bf8 100644 (file)
@@ -3,7 +3,7 @@ import {_alignPixel, _measureText, renderText, clipArea, unclipArea} from '../he
 import {callback as call, each, finiteOrDefault, isArray, isFinite, isNullOrUndef, isObject, valueOrDefault} from '../helpers/helpers.core';
 import {toDegrees, toRadians, _int16Range, _limitValue, HALF_PI} from '../helpers/helpers.math';
 import {_alignStartEnd, _toLeftRightCenter} from '../helpers/helpers.extras';
-import {toFont, toPadding, _addGrace} from '../helpers/helpers.options';
+import {createContext, toFont, toPadding, _addGrace} from '../helpers/helpers.options';
 
 import './core.scale.defaults';
 
@@ -109,14 +109,14 @@ function getTitleHeight(options, fallback) {
 }
 
 function createScaleContext(parent, scale) {
-  return Object.assign(Object.create(parent), {
+  return createContext(parent, {
     scale,
     type: 'scale'
   });
 }
 
 function createTickContext(parent, index, tick) {
-  return Object.assign(Object.create(parent), {
+  return createContext(parent, {
     tick,
     index,
     type: 'tick'
index 9ad022dcb1f2ccc32a042ef4224f717958c39c95..64070628cfb00a7f19538ea849a01c308d90e5fc 100644 (file)
@@ -244,6 +244,7 @@ export default class LineElement extends Element {
 
     this.animated = true;
     this.options = undefined;
+    this._chart = undefined;
     this._loop = undefined;
     this._fullLoop = undefined;
     this._path = undefined;
index d42b3503b8e0ebcbc8dc13f1453d30b822d3a547..4c901c85d9ea0f85d469c4a9720afb74ec05a55b 100644 (file)
@@ -184,3 +184,13 @@ export function _addGrace(minmax, grace, beginAtZero) {
     max: keepZero(max, change)
   };
 }
+
+/**
+ * Create a context inheriting parentContext
+ * @param {object|null} parentContext
+ * @param {object} context
+ * @returns {object}
+ */
+export function createContext(parentContext, context) {
+  return Object.assign(Object.create(parentContext), context);
+}
index 3524558e7b9b33707233297f8e9c7aa564b82d30..3bbfebb0dfa4d11f84a4fb89b44a881499c4f454 100644 (file)
@@ -1,4 +1,5 @@
 import {_angleBetween, _angleDiff, _normalizeAngle} from './helpers.math';
+import {createContext} from './helpers.options';
 
 /**
  * @typedef { import("../elements/element.line").default } LineElement
@@ -275,6 +276,7 @@ function splitByStyles(line, segments, points, segmentOptions) {
  * @return {Segment[]}
  */
 function doSplitByStyles(line, segments, points, segmentOptions) {
+  const chartContext = line._chart.getContext();
   const baseStyle = readStyle(line.options);
   const {_datasetIndex: datasetIndex, options: {spanGaps}} = line;
   const count = points.length;
@@ -309,14 +311,14 @@ function doSplitByStyles(line, segments, points, segmentOptions) {
     let style;
     for (i = start + 1; i <= segment.end; i++) {
       const pt = points[i % count];
-      style = readStyle(segmentOptions.setContext({
+      style = readStyle(segmentOptions.setContext(createContext(chartContext, {
         type: 'segment',
         p0: prev,
         p1: pt,
         p0DataIndex: (i - 1) % count,
         p1DataIndex: i % count,
         datasetIndex
-      }));
+      })));
       if (styleChanged(style, prevStyle)) {
         addStyle(start, i - 1, segment.loop, prevStyle);
       }
index cdf4734ec3cefc07eaf247753721f872b4a0e61c..fd068e7aa7b74783b156ab12581a2cb3768e5758 100644 (file)
@@ -5,7 +5,7 @@ import {each, noop, isNullOrUndef, isArray, _elementsEqual} from '../helpers/hel
 import {toFont, toPadding, toTRBLCorners} from '../helpers/helpers.options';
 import {getRtlAdapter, overrideTextDirection, restoreTextDirection} from '../helpers/helpers.rtl';
 import {distanceBetweenPoints, _limitValue} from '../helpers/helpers.math';
-import {drawPoint} from '../helpers';
+import {createContext, drawPoint} from '../helpers';
 
 /**
  * @typedef { import("../platform/platform.base").ChartEvent } ChartEvent
@@ -335,7 +335,7 @@ function getBeforeAfterBodyLines(callback) {
 }
 
 function createTooltipContext(parent, tooltip, tooltipItems) {
-  return Object.assign(Object.create(parent), {
+  return createContext(parent, {
     tooltip,
     tooltipItems,
     type: 'tooltip'
index 8ad7e8b23c2482012becdb20704cc70bdaeb1272..cbe37238e66374208307e3eaf8b9a4a26a5403ea 100644 (file)
@@ -4,7 +4,7 @@ import {HALF_PI, isNumber, TAU, toDegrees, toRadians, _normalizeAngle} from '../
 import LinearScaleBase from './scale.linearbase';
 import Ticks from '../core/core.ticks';
 import {valueOrDefault, isArray, isFinite, callback as callCallback, isNullOrUndef} from '../helpers/helpers.core';
-import {toFont, toPadding} from '../helpers/helpers.options';
+import {createContext, toFont, toPadding} from '../helpers/helpers.options';
 
 function getTickBackdropHeight(opts) {
   const tickOpts = opts.ticks;
@@ -265,7 +265,7 @@ function numberOrZero(param) {
 }
 
 function createPointLabelContext(parent, index, label) {
-  return Object.assign(Object.create(parent), {
+  return createContext(parent, {
     label,
     index,
     type: 'pointLabel'
index 28ad773d3ae7b66b6c44899b4eb3e356d6c538da..a6ff051b5246b9d2087f4c895f71378e93345d6b 100644 (file)
@@ -52,3 +52,10 @@ export function resolve<T, C>(
        index?: number,
        info?: { cacheable?: boolean }
 ): T | undefined;
+
+
+/**
+ * Create a context inheriting parentContext
+ * @since 3.6.0
+ */
+export function createContext<P, T>(parentContext: P, context: T): P extends null ? T : P & T;
diff --git a/types/tests/helpers/options.ts b/types/tests/helpers/options.ts
new file mode 100644 (file)
index 0000000..9fa2222
--- /dev/null
@@ -0,0 +1,10 @@
+import { createContext } from '../../helpers/helpers.options';
+
+const context1 = createContext(null, { type: 'test1', parent: true });
+const context2 = createContext(context1, { type: 'test2' });
+
+const sSest: string = context1.type + context2.type;
+const bTest: boolean = context1.parent && context2.parent;
+
+// @ts-expect-error Property 'notThere' does not exist on type '{ type: string; parent: boolean; } & { type: string; }'
+context2.notThere = '';