From f424f99aabf340705ae4bbebfaaecaa1bc9a9f24 Mon Sep 17 00:00:00 2001 From: kurkle Date: Mon, 23 May 2022 14:52:01 +0300 Subject: [PATCH 1/5] Enable fallback to common defaults --- src/annotation.js | 15 ++++++-------- src/commonDefaults.js | 14 +++++++++++++ src/elements.js | 48 ++++++++++++++++++++++++++++++++++--------- src/types/box.js | 7 ------- src/types/ellipse.js | 7 ------- src/types/label.js | 9 -------- src/types/point.js | 9 -------- src/types/polygon.js | 9 -------- 8 files changed, 58 insertions(+), 60 deletions(-) create mode 100644 src/commonDefaults.js diff --git a/src/annotation.js b/src/annotation.js index 070b3f044..ce726998f 100644 --- a/src/annotation.js +++ b/src/annotation.js @@ -1,11 +1,12 @@ import {Chart} from 'chart.js'; -import {clipArea, unclipArea, isObject, isArray} from 'chart.js/helpers'; +import {clipArea, isArray, isObject, unclipArea} from 'chart.js/helpers'; +import {version} from '../package.json'; +import {commonDefaults} from './commonDefaults'; +import {resolveType, updateElements} from './elements'; import {handleEvent, hooks, updateListeners} from './events'; +import {requireVersion} from './helpers'; import {adjustScaleRange, verifyScaleOptions} from './scale'; -import {updateElements, resolveType} from './elements'; import {annotationTypes} from './types'; -import {requireVersion} from './helpers'; -import {version} from '../package.json'; const chartStates = new Map(); @@ -113,11 +114,7 @@ export default { axis: undefined, intersect: undefined }, - common: { - drawTime: 'afterDatasetsDraw', - label: { - } - } + common: commonDefaults }, descriptors: { diff --git a/src/commonDefaults.js b/src/commonDefaults.js new file mode 100644 index 000000000..aab6f93b8 --- /dev/null +++ b/src/commonDefaults.js @@ -0,0 +1,14 @@ +export const commonDefaults = { + drawTime: 'afterDatasetsDraw', + label: { + }, + xMax: undefined, + xMin: undefined, + xScaleID: undefined, + xValue: undefined, + yMax: undefined, + yMin: undefined, + yScaleID: undefined, + yValue: undefined, + z: 0 +}; diff --git a/src/elements.js b/src/elements.js index 5d296f7ab..0b60d24fd 100644 --- a/src/elements.js +++ b/src/elements.js @@ -1,5 +1,6 @@ import {Animations} from 'chart.js'; -import {isObject, defined} from 'chart.js/helpers'; +import {defined, isObject} from 'chart.js/helpers'; +import {commonDefaults} from './commonDefaults'; import {hooks} from './events'; import {annotationTypes} from './types'; @@ -105,25 +106,52 @@ function getOrCreateElement(elements, index, type, initProperties) { function resolveAnnotationOptions(resolver) { const elementClass = annotationTypes[resolveType(resolver.type)]; - const result = {}; - result.id = resolver.id; - result.type = resolver.type; - result.drawTime = resolver.drawTime; - Object.assign(result, - resolveObj(resolver, elementClass.defaults), - resolveObj(resolver, elementClass.defaultRoutes)); + const result = mergeDeep( + { + id: resolver.id, + type: resolver.type, + drawTime: resolver.drawTime, + }, + resolveObj(resolver, + mergeDeep( + elementClass.defaults, + elementClass.defaultRoutes, + commonDefaults + ) + ), + ); for (const hook of hooks) { result[hook] = resolver[hook]; } return result; } -function resolveObj(resolver, defs) { +function mergeDeep(...objects) { + return objects.reduce((prev, obj) => { + for (const prop of Object.keys(obj)) { + const pVal = prev[prop]; + const oVal = obj[prop]; + + if (Array.isArray(pVal) && Array.isArray(oVal)) { + prev[prop] = pVal.concat(...oVal); + } else if (isObject(pVal) && isObject(oVal)) { + prev[prop] = mergeDeep(pVal, oVal); + } else if (defined(oVal)) { + prev[prop] = oVal; + } + } + + return prev; + }, {}); +} + +function resolveObj(resolver, defs, common = {}) { const result = {}; for (const prop of Object.keys(defs)) { + const commonDefs = common[prop]; const optDefs = defs[prop]; const value = resolver[prop]; - result[prop] = isObject(optDefs) ? resolveObj(value, optDefs) : value; + result[prop] = isObject(optDefs) || isObject(commonDefs) ? resolveObj(value, optDefs, commonDefs) : value; } return result; } diff --git a/src/types/box.js b/src/types/box.js index 32a726e74..32f987911 100644 --- a/src/types/box.js +++ b/src/types/box.js @@ -97,13 +97,6 @@ BoxAnnotation.defaults = { shadowBlur: 0, shadowOffsetX: 0, shadowOffsetY: 0, - xMax: undefined, - xMin: undefined, - xScaleID: undefined, - yMax: undefined, - yMin: undefined, - yScaleID: undefined, - z: 0 }; BoxAnnotation.defaultRoutes = { diff --git a/src/types/ellipse.js b/src/types/ellipse.js index e6a4783fb..78b104c10 100644 --- a/src/types/ellipse.js +++ b/src/types/ellipse.js @@ -59,13 +59,6 @@ EllipseAnnotation.defaults = { shadowBlur: 0, shadowOffsetX: 0, shadowOffsetY: 0, - xMax: undefined, - xMin: undefined, - xScaleID: undefined, - yMax: undefined, - yMin: undefined, - yScaleID: undefined, - z: 0 }; EllipseAnnotation.defaultRoutes = { diff --git a/src/types/label.js b/src/types/label.js index 169f43d2e..487eb80c2 100644 --- a/src/types/label.js +++ b/src/types/label.js @@ -102,16 +102,7 @@ LabelAnnotation.defaults = { textStrokeWidth: 0, width: undefined, xAdjust: 0, - xMax: undefined, - xMin: undefined, - xScaleID: undefined, - xValue: undefined, yAdjust: 0, - yMax: undefined, - yMin: undefined, - yScaleID: undefined, - yValue: undefined, - z: 0 }; LabelAnnotation.defaultRoutes = { diff --git a/src/types/point.js b/src/types/point.js index 97c0dd039..2bedb92bd 100644 --- a/src/types/point.js +++ b/src/types/point.js @@ -61,16 +61,7 @@ PointAnnotation.defaults = { shadowOffsetX: 0, shadowOffsetY: 0, xAdjust: 0, - xMax: undefined, - xMin: undefined, - xScaleID: undefined, - xValue: undefined, yAdjust: 0, - yMax: undefined, - yMin: undefined, - yScaleID: undefined, - yValue: undefined, - z: 0 }; PointAnnotation.defaultRoutes = { diff --git a/src/types/polygon.js b/src/types/polygon.js index bcf08e92f..4fd260b2a 100644 --- a/src/types/polygon.js +++ b/src/types/polygon.js @@ -83,16 +83,7 @@ PolygonAnnotation.defaults = { shadowOffsetY: 0, sides: 3, xAdjust: 0, - xMax: undefined, - xMin: undefined, - xScaleID: undefined, - xValue: undefined, yAdjust: 0, - yMax: undefined, - yMin: undefined, - yScaleID: undefined, - yValue: undefined, - z: 0 }; PolygonAnnotation.defaultRoutes = { From 28eb60ee8399fcf4d6e6764139ef07bb0f496460 Mon Sep 17 00:00:00 2001 From: kurkle Date: Mon, 23 May 2022 15:03:18 +0300 Subject: [PATCH 2/5] Oops --- src/elements.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elements.js b/src/elements.js index 0b60d24fd..81c6862f8 100644 --- a/src/elements.js +++ b/src/elements.js @@ -136,7 +136,7 @@ function mergeDeep(...objects) { prev[prop] = pVal.concat(...oVal); } else if (isObject(pVal) && isObject(oVal)) { prev[prop] = mergeDeep(pVal, oVal); - } else if (defined(oVal)) { + } else if (defined(oVal) || !defined(pVal)) { prev[prop] = oVal; } } From 2d103bf39f0e38caf16a9e81b8c90a08340af22e Mon Sep 17 00:00:00 2001 From: kurkle Date: Mon, 23 May 2022 15:16:25 +0300 Subject: [PATCH 3/5] Remove some lefovers --- src/elements.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/elements.js b/src/elements.js index 81c6862f8..286c90042 100644 --- a/src/elements.js +++ b/src/elements.js @@ -145,13 +145,12 @@ function mergeDeep(...objects) { }, {}); } -function resolveObj(resolver, defs, common = {}) { +function resolveObj(resolver, defs) { const result = {}; for (const prop of Object.keys(defs)) { - const commonDefs = common[prop]; const optDefs = defs[prop]; const value = resolver[prop]; - result[prop] = isObject(optDefs) || isObject(commonDefs) ? resolveObj(value, optDefs, commonDefs) : value; + result[prop] = isObject(optDefs) ? resolveObj(value, optDefs) : value; } return result; } From 21658cacf3f0903885380e43442caa2e89b295f0 Mon Sep 17 00:00:00 2001 From: kurkle Date: Mon, 23 May 2022 15:19:14 +0300 Subject: [PATCH 4/5] No need to merge arrays --- src/elements.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/elements.js b/src/elements.js index 286c90042..e5a9b61b4 100644 --- a/src/elements.js +++ b/src/elements.js @@ -132,9 +132,7 @@ function mergeDeep(...objects) { const pVal = prev[prop]; const oVal = obj[prop]; - if (Array.isArray(pVal) && Array.isArray(oVal)) { - prev[prop] = pVal.concat(...oVal); - } else if (isObject(pVal) && isObject(oVal)) { + if (isObject(pVal) && isObject(oVal)) { prev[prop] = mergeDeep(pVal, oVal); } else if (defined(oVal) || !defined(pVal)) { prev[prop] = oVal; From 4ec64ef4099d3e9d59f376101f972fecdafef379 Mon Sep 17 00:00:00 2001 From: kurkle Date: Mon, 23 May 2022 17:34:16 +0300 Subject: [PATCH 5/5] Some progress --- src/elements.js | 58 +++++++++---------------------------------------- 1 file changed, 10 insertions(+), 48 deletions(-) diff --git a/src/elements.js b/src/elements.js index e5a9b61b4..6ca76229e 100644 --- a/src/elements.js +++ b/src/elements.js @@ -1,7 +1,5 @@ import {Animations} from 'chart.js'; import {defined, isObject} from 'chart.js/helpers'; -import {commonDefaults} from './commonDefaults'; -import {hooks} from './events'; import {annotationTypes} from './types'; const directUpdater = { @@ -62,7 +60,7 @@ export function updateElements(chart, state, options, mode) { Object.assign(element, properties); } - properties.options = resolveAnnotationOptions(resolver); + properties.options = resolveOptions(resolver); animations.update(element, properties); } @@ -87,7 +85,7 @@ function updateSubElements(mainElement, {elements, initProperties}, resolver, an const properties = definition.properties; const subElement = getOrCreateElement(subElements, i, definition.type, initProperties); const subResolver = resolver[definition.optionScope].override(definition); - properties.options = resolveAnnotationOptions(subResolver); + properties.options = resolveOptions(subResolver); animations.update(subElement, properties); } } @@ -104,51 +102,15 @@ function getOrCreateElement(elements, index, type, initProperties) { return element; } -function resolveAnnotationOptions(resolver) { - const elementClass = annotationTypes[resolveType(resolver.type)]; - const result = mergeDeep( - { - id: resolver.id, - type: resolver.type, - drawTime: resolver.drawTime, - }, - resolveObj(resolver, - mergeDeep( - elementClass.defaults, - elementClass.defaultRoutes, - commonDefaults - ) - ), - ); - for (const hook of hooks) { - result[hook] = resolver[hook]; - } - return result; -} - -function mergeDeep(...objects) { - return objects.reduce((prev, obj) => { - for (const prop of Object.keys(obj)) { - const pVal = prev[prop]; - const oVal = obj[prop]; - - if (isObject(pVal) && isObject(oVal)) { - prev[prop] = mergeDeep(pVal, oVal); - } else if (defined(oVal) || !defined(pVal)) { - prev[prop] = oVal; - } - } - - return prev; - }, {}); -} - -function resolveObj(resolver, defs) { +function resolveOptions(resolver, path = []) { const result = {}; - for (const prop of Object.keys(defs)) { - const optDefs = defs[prop]; - const value = resolver[prop]; - result[prop] = isObject(optDefs) ? resolveObj(value, optDefs) : value; + for (const key of Object.getOwnPropertyNames(resolver)) { + if (path.includes(key)) { + // TODO: this is slow, should figure out why the keys start looping instead. + continue; + } + const value = resolver[key]; + result[key] = isObject(value) ? resolveOptions(value, [...path, key]) : value; } return result; }