From ecadce290c911122a21fd4060c36d70a69031e61 Mon Sep 17 00:00:00 2001 From: Shafeeq Date: Mon, 18 Dec 2023 14:38:57 +0000 Subject: [PATCH 01/10] Add on object formatting support --- Tutorial/ColorPalette.md | 49 +- Tutorial/ConditionalFormatting.md | 19 +- capabilities.json | 73 +- package-lock.json | 1647 +++++++++++++---------------- package.json | 6 +- pbiviz.json | 4 +- src/barChart.ts | 596 +++++++---- src/barChartSettingsModel.ts | 181 ++++ style/visual.less | 22 +- 9 files changed, 1410 insertions(+), 1187 deletions(-) create mode 100644 src/barChartSettingsModel.ts diff --git a/Tutorial/ColorPalette.md b/Tutorial/ColorPalette.md index bdb8bd3..c1f528e 100644 --- a/Tutorial/ColorPalette.md +++ b/Tutorial/ColorPalette.md @@ -26,16 +26,47 @@ interface BarChartDataPoint { `colorPalette` is a service that manages the colors used on your visual. An instance of it is available on `IVisualHost`. ## Assigning Color to Data Points -We defined `visualTransform` as a construct to convert `dataView` to a view model Bar Chart can use. -Since we iterate through the data points in `visualTransform` it is also the ideal place to assign colors. +We defined `createSelectorDataPoints` as a construct to convert options `dataView` Bar Chart data points that will be used in visual view. +Since we iterate through the data points in `createSelectorDataPoints` it is also the ideal place to assign colors. ```typescript -let colorPalette: IColorPalette = host.colorPalette; // host: IVisualHost -for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) { - barChartDataPoints.push({ - category: category.values[i], - value: dataValue.values[i], - color: colorPalette.getColor(category.values[i]).value, - }); +function createSelectorDataPoints(options: VisualUpdateOptions, host: IVisualHost): BarChartDataPoint[] { + let barChartDataPoints: BarChartDataPoint[] = [] + const dataViews = options.dataViews; + if (!dataViews + || !dataViews[0] + || !dataViews[0].categorical + || !dataViews[0].categorical.categories + || !dataViews[0].categorical.categories[0].source + || !dataViews[0].categorical.values + ) { + return barChartDataPoints; + } + + const categorical = dataViews[0].categorical; + const category = categorical.categories[0]; + const dataValue = categorical.values[0]; + + const colorPalette: ISandboxExtendedColorPalette = host.colorPalette; + const strokeColor: string = getColumnStrokeColor(colorPalette); + const strokeWidth: number = getColumnStrokeWidth(colorPalette.isHighContrast); + + for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) { + const color: string = getColumnColorByIndex(category, i, colorPalette); + + const selectionId: ISelectionId = host.createSelectionIdBuilder() + .withCategory(category, i) + .createSelectionId(); + + barChartDataPoints.push({ + color, + strokeColor, + strokeWidth, + selectionId, + value: dataValue.values[i], + category: `${category.values[i]}`, + }); + } + return barChartDataPoints; } ``` diff --git a/Tutorial/ConditionalFormatting.md b/Tutorial/ConditionalFormatting.md index 2e87772..dde89b0 100644 --- a/Tutorial/ConditionalFormatting.md +++ b/Tutorial/ConditionalFormatting.md @@ -1,7 +1,6 @@ # Adding conditional formatting to your Visual -[Conditional formatting](https://docs.microsoft.com/en-us/power-bi/visuals/service-tips-and-tricks-for-color-formatting#conditional-formatting-for-visualizations) of custom properties is supported by updating `VisualObjectInstance` object's properties as enumerated under `enumerateObjectInstances` method. - -See [commit](https://github.com/microsoft/powerbi-visuals-api/commit/8fe88399c5ba82feeec4541ce5bf8e02a3ecd15a) for what was added at this step. +[Conditional formatting](https://docs.microsoft.com/en-us/power-bi/visuals/service-tips-and-tricks-for-color-formatting#conditional-formatting-for-visualizations) of custom formatting properties is supported by setting formatting property `instanceKind` in `getFormattingModel` method. +For more info on conditional formatting click [here](https://learn.microsoft.com/en-us/power-bi/developer/visuals/conditional-format?tabs=getFormattingModel) Conditional formatting can only be applied to the following property types: * Color @@ -10,25 +9,23 @@ Conditional formatting can only be applied to the following property types: * Web URL ## Add a conditional color formatting entry in the format pane -To add the conditional color formatting button in the format pane for the desired object, under the `enumerateObjectInstances` method, make the following change: +To add the conditional color formatting button in the format pane for the desired object, under the `getFormattingModel` method, make the following change: -Via `propertyInstanceKind` property of enumerated `VisualObjectInstance`, list all the properties that you'd like to have the conditional formatting entry applied to in the format pane. +Define `instanceKind` property of required formatting property `descriptor` with the appropriate value. Use `VisualEnumerationInstanceKinds` enum to declare the type of the desired format (constant, rule or both). ```typescript // List your conditional formatting properties -propertyInstanceKind: { - fill: VisualEnumerationInstanceKinds.ConstantOrRule -} +instanceKind: powerbi.VisualEnumerationInstanceKinds.ConstantOrRule ``` ![](images/ConditionalFormattingEntry.png) ## Define how conditional formatting behaves Using `createDataViewWildcardSelector` declared under `powerbi-visuals-utils-dataviewutils`, specify whether conditional formatting will be applied to instances, totals, or both. For more information, see [DataViewWildcard](https://docs.microsoft.com/en-us/power-bi/developer/visuals/utils-dataview#dataviewwildcard). -In `enumerateObjectInstances`, make the following changes to the objects you want to apply conditional formatting to: +In `BarChartFormattingSettingsModel`, make the following changes to the formatting properties you want to apply conditional formatting to: -* Replace the `VisualObjectInstance`'s `selector` value with a `dataViewWildcard.createDataViewWildcardSelector()` call. Specify the desired option from `DataViewWildcardMatchingOption` enum to define whether conditional formatting is applied to instances, totals, or both. +* Replace the formatting property `descriptor`'s `selector` value with a `dataViewWildcard.createDataViewWildcardSelector()` call. Specify the desired option from `DataViewWildcardMatchingOption` enum to define whether conditional formatting is applied to instances, totals, or both. * Add the `altConstantValueSelector` property having the value previously defined for the `selector` property. @@ -39,6 +36,6 @@ selector: dataViewWildcard.createDataViewWildcardSelector(dataViewWildcard.DataV // Add this property with the value previously defined for the selector property altConstantValueSelector: barDataPoint.selectionId.getSelector() ``` -See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/commit/956923b641bb1eacb613bf55a91f77725bc42431) for how conditional formatting was applied to sample bar chart. +See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart) for how conditional formatting was applied to sample bar chart. ![](images/CondFormatSupport.png) \ No newline at end of file diff --git a/capabilities.json b/capabilities.json index 1653d75..c00d9d7 100644 --- a/capabilities.json +++ b/capabilities.json @@ -79,6 +79,67 @@ } } }, + "directEditTest": { + "properties": { + "show": { + "displayName": "Show", + "type": { + "bool": true + } + }, + "textProperty": { + "displayName": "Text", + "type": { + "text": true + } + }, + "fontFamily": { + "type": { + "formatting": { + "fontFamily": true + } + } + }, + "fontSize": { + "type": { + "formatting": { + "fontSize": true + } + } + }, + "bold": { + "type": { + "formatting": { + "fontSize": true + } + } + }, + "italic": { + "type": { + "formatting": { + "fontSize": true + } + } + }, + "underline": { + "type": { + "formatting": { + "fontSize": true + } + } + }, + "fill": { + "displayName": "Color", + "type": { + "fill": { + "solid": { + "color": true + } + } + } + } + } + }, "colorSelector": { "displayName": "Data Colors", "properties": { @@ -149,12 +210,18 @@ "default": true, "canvas": true }, - "roles": ["Tooltips"], + "roles": [ + "Tooltips" + ], "supportEnhancedTooltips": true }, "supportsLandingPage": false, + "supportsOnObjectFormatting": true, + "enablePointerEventsFormatMode": true, "drilldown": { - "roles": ["category"] + "roles": [ + "category" + ] }, "privileges": [] -} +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c73f40d..5ffc026 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,10 @@ "": { "name": "visual", "version": "4.0.0", + "dependencies": { + "on-object-utils": "file:../../Utils/on-object-utils/on-object-utils-1.0.0.tgz", + "powerbi-visuals-utils-onobjectformatting": "file:../../powerbi-visuals-utils-onobjectformatting/powerbi-visuals-utils-onobjectformatting-1.0.0.tgz" + }, "devDependencies": { "@types/d3-axis": "^3.0.4", "@types/d3-scale": "^4.0.5", @@ -19,8 +23,9 @@ "eslint": "^8.50.0", "eslint-plugin-powerbi-visuals": "^0.8.1", "powerbi-visuals-api": "~5.4.0", - "powerbi-visuals-tools": "^5.1.1", + "powerbi-visuals-tools": "^5.3.0", "powerbi-visuals-utils-dataviewutils": "^6.0.1", + "powerbi-visuals-utils-formattingmodel": "6.0.0", "powerbi-visuals-utils-formattingutils": "^6.0.1", "powerbi-visuals-utils-interactivityutils": "^6.0.2", "powerbi-visuals-utils-tooltiputils": "^6.0.1", @@ -296,10 +301,9 @@ } }, "node_modules/@types/d3-selection": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.7.tgz", - "integrity": "sha512-qoj2O7KjfqCobmtFOth8FMvjwMVPUAAmn6xiUbLl1ld7vQCPgffvyV5BBcEFfqWdilAUm+3zciU/3P3vZrUMlg==", - "dev": true + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.10.tgz", + "integrity": "sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==" }, "node_modules/@types/d3-time": { "version": "1.0.10", @@ -498,15 +502,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.3.tgz", - "integrity": "sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.1.tgz", + "integrity": "sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.7.3", - "@typescript-eslint/types": "6.7.3", - "@typescript-eslint/typescript-estree": "6.7.3", - "@typescript-eslint/visitor-keys": "6.7.3", + "@typescript-eslint/scope-manager": "6.13.1", + "@typescript-eslint/types": "6.13.1", + "@typescript-eslint/typescript-estree": "6.13.1", + "@typescript-eslint/visitor-keys": "6.13.1", "debug": "^4.3.4" }, "engines": { @@ -525,6 +529,80 @@ } } }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz", + "integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.1", + "@typescript-eslint/visitor-keys": "6.13.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz", + "integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz", + "integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.1", + "@typescript-eslint/visitor-keys": "6.13.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz", + "integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.1", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/scope-manager": { "version": "6.7.3", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.3.tgz", @@ -865,9 +943,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", + "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", "dev": true, "engines": { "node": ">=0.4.0" @@ -1026,21 +1104,22 @@ "dev": true }, "node_modules/assert": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", - "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", "dev": true, "dependencies": { - "es6-object-assign": "^1.1.0", - "is-nan": "^1.2.1", - "object-is": "^1.0.1", - "util": "^0.12.0" + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" } }, "node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", "dev": true }, "node_modules/at-least-node": { @@ -1053,9 +1132,9 @@ } }, "node_modules/available-typed-arrays": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz", - "integrity": "sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", "dev": true, "engines": { "node": ">= 0.4" @@ -1462,13 +1541,14 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1925,7 +2005,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "dev": true, "engines": { "node": ">=12" } @@ -1963,6 +2042,12 @@ "node": ">=12" } }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1998,6 +2083,20 @@ "node": ">= 10" } }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -2008,15 +2107,20 @@ } }, "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "dependencies": { - "object-keys": "^1.0.12" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/depd": { @@ -2104,12 +2208,12 @@ } }, "node_modules/domain-browser": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.22.0.tgz", - "integrity": "sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-5.4.0.tgz", + "integrity": "sha512-p20fsErHHxkrpfqi6BcwUmBWpKCO9oUDAegNqtnzpiS72Zu4uEXqTFlStlOr5dOf53reASN7ab47+P8OLVIVOQ==", "dev": true, "engines": { - "node": ">=10" + "node": ">=4" }, "funding": { "url": "https://bevry.me/fund" @@ -2189,66 +2293,12 @@ "errno": "cli.js" } }, - "node_modules/es-abstract": { - "version": "1.18.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", - "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/es-module-lexer": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", "dev": true }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es6-object-assign": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", - "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", - "dev": true - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2949,11 +2999,14 @@ } } }, - "node_modules/foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } }, "node_modules/forwarded": { "version": "0.2.0", @@ -3014,20 +3067,24 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3118,6 +3175,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -3151,40 +3220,43 @@ "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "dev": true }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, "engines": { - "node": ">= 0.4.0" + "node": ">=8" } }, - "node_modules/has-bigints": { + "node_modules/has-property-descriptors": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", "dev": true, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, "engines": { "node": ">= 0.4" @@ -3252,6 +3324,18 @@ "minimalistic-assert": "^1.0.1" } }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -3315,6 +3399,12 @@ } ] }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "node_modules/http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", @@ -3511,20 +3601,6 @@ "node": ">=0.10.0" } }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", @@ -3559,18 +3635,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -3583,42 +3647,11 @@ "node": ">=8" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, "engines": { "node": ">= 0.4" }, @@ -3693,18 +3726,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -3714,21 +3735,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -3750,20 +3756,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, "node_modules/is-stream": { @@ -3778,47 +3777,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.7.tgz", - "integrity": "sha512-VxlpTBGknhQ3o7YiVjIhdLU6+oD8dPz/79vvvH4F+S/c8608UCVa9fgDpa1kZgFoUST2DCgacc70UszKgzKuvA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.4", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", - "has-tostringtag": "^1.0.0" + "which-typed-array": "^1.1.11" }, "engines": { "node": ">= 0.4" @@ -4084,12 +4049,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -4108,6 +4067,12 @@ "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", "dev": true }, + "node_modules/lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4124,7 +4089,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -4514,14 +4478,14 @@ } }, "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, "engines": { @@ -4546,6 +4510,26 @@ "node": ">= 0.8" } }, + "node_modules/on-object-utils": { + "version": "1.0.0", + "resolved": "file:../../Utils/on-object-utils/on-object-utils-1.0.0.tgz", + "integrity": "sha512-rBcLdKDSXVdhLwOeAcdLRT6fVyAsvB6TgafZjurJalr/U05gcc2rD4uzGVX1uEToCvuZEQijC8q5BSKTSC7HeA==", + "license": "ISC", + "dependencies": { + "@types/d3-selection": "^3.0.10", + "d3-selection": "^3.0.0", + "powerbi-visuals-api": "~5.1.0", + "typescript": "^5.3.2" + } + }, + "node_modules/on-object-utils/node_modules/powerbi-visuals-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.1.0.tgz", + "integrity": "sha512-ol+h1gF1VRK3n6/wwXR2YMkQsczHU3aiqmqtPl0/KEHPbCBQon/0vcdOVDXFp5QtYj/Ua+LXegD47x8K9FWCzg==", + "dependencies": { + "semver": "^7.3.5" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4925,24 +4909,24 @@ } }, "node_modules/powerbi-visuals-tools": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/powerbi-visuals-tools/-/powerbi-visuals-tools-5.1.1.tgz", - "integrity": "sha512-kQTWXYI416H5Oh6PPi62Wu7LogGYVnpRjVBJU+dFcXBzzx5MWOecmdY/0Z9Jt2hK6LY0xZuiOxue8mxoOSQQPg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-tools/-/powerbi-visuals-tools-5.3.0.tgz", + "integrity": "sha512-d6Y7MuqDqpMyl4r7aAwC85NW2UDYzCUE9hbuUCItrfUdAEHpPGg6eqhPYjZREbbkEmeXNPjGrYra+91XMq6csQ==", "dev": true, "dependencies": { - "@typescript-eslint/parser": "^5.62.0", - "assert": "^2.0.0", - "async": "^3.2.4", + "@typescript-eslint/parser": "^6.12.0", + "assert": "^2.1.0", + "async": "^3.2.5", "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", "chalk": "^5.3.0", - "commander": "^11.0.0", + "commander": "^11.1.0", "compare-versions": "^6.1.0", "console-browserify": "^1.2.0", "constants-browserify": "^1.0.0", "crypto-browserify": "^3.12.0", "css-loader": "^6.8.1", - "domain-browser": "^4.22.0", + "domain-browser": "^5.4.0", "events": "^3.3.0", "extra-watch-webpack-plugin": "^1.0.3", "fs-extra": "^11.1.1", @@ -4955,12 +4939,13 @@ "lodash.clonedeep": "4.5.0", "lodash.defaults": "4.2.0", "lodash.isequal": "4.5.0", + "lodash.ismatch": "^4.4.0", "mini-css-extract-plugin": "^2.7.6", "os-browserify": "^0.3.0", "path-browserify": "^1.0.1", - "powerbi-visuals-webpack-plugin": "4.0.1", + "powerbi-visuals-webpack-plugin": "4.1.0", "process": "^0.11.10", - "punycode": "^2.3.0", + "punycode": "^2.3.1", "querystring-es3": "^0.2.1", "readable-stream": "^4.4.2", "stream-browserify": "^3.0.0", @@ -4968,14 +4953,14 @@ "string_decoder": "^1.3.0", "terser-webpack-plugin": "^5.3.9", "timers-browserify": "^2.0.12", - "ts-loader": "^9.4.4", + "ts-loader": "^9.5.1", "tty-browserify": "^0.0.1", "typescript": "^4.9.5", - "url": "^0.11.1", + "url": "^0.11.3", "util": "^0.12.5", "vm-browserify": "^1.1.2", - "webpack": "^5.88.2", - "webpack-bundle-analyzer": "4.9.0", + "webpack": "^5.89.0", + "webpack-bundle-analyzer": "4.10.1", "webpack-dev-server": "^4.15.1" }, "bin": { @@ -4988,111 +4973,10 @@ "fsevents": "*" } }, - "node_modules/powerbi-visuals-tools/node_modules/@typescript-eslint/parser": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/powerbi-visuals-tools/node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/powerbi-visuals-tools/node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/powerbi-visuals-tools/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/powerbi-visuals-tools/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/powerbi-visuals-tools/node_modules/commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true, "engines": { "node": ">=16" @@ -5136,6 +5020,24 @@ "fsevents": "*" } }, + "node_modules/powerbi-visuals-utils-formattingmodel": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-utils-formattingmodel/-/powerbi-visuals-utils-formattingmodel-6.0.0.tgz", + "integrity": "sha512-2G2qNfcTlJ+aR7CkZDrG75SzH6WO3So/xJFOGtY4bfiVQC4J1ao0juxmIZEyJkCPRV0Sbxg3N0kMxqjOKjdBMA==", + "dev": true, + "dependencies": { + "powerbi-visuals-api": "~5.1.0" + } + }, + "node_modules/powerbi-visuals-utils-formattingmodel/node_modules/powerbi-visuals-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.1.0.tgz", + "integrity": "sha512-ol+h1gF1VRK3n6/wwXR2YMkQsczHU3aiqmqtPl0/KEHPbCBQon/0vcdOVDXFp5QtYj/Ua+LXegD47x8K9FWCzg==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + } + }, "node_modules/powerbi-visuals-utils-formattingutils": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/powerbi-visuals-utils-formattingutils/-/powerbi-visuals-utils-formattingutils-6.0.1.tgz", @@ -5171,6 +5073,25 @@ "powerbi-visuals-utils-typeutils": "^6.0.1" } }, + "node_modules/powerbi-visuals-utils-onobjectformatting": { + "version": "1.0.0", + "resolved": "file:../../powerbi-visuals-utils-onobjectformatting/powerbi-visuals-utils-onobjectformatting-1.0.0.tgz", + "integrity": "sha512-6QeFsdCHs8nETNgItTJGjTiHrlh9t18QzyQaazjjZOpBV6JQReTuKj6jZOertsiotB5I7teiJUssBYhqO5pjVw==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "^3.0.10", + "d3-selection": "^3.0.0", + "powerbi-visuals-api": "~5.1.0" + } + }, + "node_modules/powerbi-visuals-utils-onobjectformatting/node_modules/powerbi-visuals-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.1.0.tgz", + "integrity": "sha512-ol+h1gF1VRK3n6/wwXR2YMkQsczHU3aiqmqtPl0/KEHPbCBQon/0vcdOVDXFp5QtYj/Ua+LXegD47x8K9FWCzg==", + "dependencies": { + "semver": "^7.3.5" + } + }, "node_modules/powerbi-visuals-utils-svgutils": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/powerbi-visuals-utils-svgutils/-/powerbi-visuals-utils-svgutils-6.0.1.tgz", @@ -5201,9 +5122,9 @@ } }, "node_modules/powerbi-visuals-webpack-plugin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/powerbi-visuals-webpack-plugin/-/powerbi-visuals-webpack-plugin-4.0.1.tgz", - "integrity": "sha512-ologdk1TEX2qdvKy9EloIdUf8bxLayvWwoKvyvDbFudMUNOwoiobxaJUXxP11j3DaygrP9PeO0hQoNbVwAuymA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-webpack-plugin/-/powerbi-visuals-webpack-plugin-4.1.0.tgz", + "integrity": "sha512-ttXVVsQYcs6VuoMNZ4SRaK9vdRaIZsU1S16sDSgcnnf5dlaXXiB/j411HACdYLMrU0YUR/vI4QTC7xq52hbMgw==", "dev": true, "dependencies": { "ajv": "6.12.3", @@ -5354,9 +5275,9 @@ "dev": true }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -5718,7 +5639,6 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -5798,6 +5718,21 @@ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", "dev": true }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -5868,14 +5803,14 @@ "dev": true }, "node_modules/sirv": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", - "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", + "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==", "dev": true, "dependencies": { "@polka/url": "^1.0.0-next.20", "mrmime": "^1.0.0", - "totalist": "^1.0.0" + "totalist": "^3.0.0" }, "engines": { "node": ">= 10" @@ -6028,32 +5963,6 @@ } ] }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -6215,9 +6124,9 @@ } }, "node_modules/totalist": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", - "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", "dev": true, "engines": { "node": ">=6" @@ -6236,15 +6145,16 @@ } }, "node_modules/ts-loader": { - "version": "9.4.4", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.4.tgz", - "integrity": "sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", "dev": true, "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^5.0.0", "micromatch": "^4.0.0", - "semver": "^7.3.4" + "semver": "^7.3.4", + "source-map": "^0.7.4" }, "engines": { "node": ">=12.0.0" @@ -6270,31 +6180,19 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/tslib": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", - "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + "node": ">= 8" } }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "node_modules/tslib": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", + "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", "dev": true }, "node_modules/tty-browserify": { @@ -6341,10 +6239,9 @@ } }, "node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", - "dev": true, + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6353,21 +6250,6 @@ "node": ">=14.17" } }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -6507,9 +6389,9 @@ } }, "node_modules/webpack": { - "version": "5.88.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", - "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -6554,20 +6436,23 @@ } }, "node_modules/webpack-bundle-analyzer": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.0.tgz", - "integrity": "sha512-+bXGmO1LyiNx0i9enBu3H8mv42sj/BJWhZNFwjz92tVnBa9J3JMGo2an2IXlEleoDOPn/Hofl5hr/xCpObUDtw==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz", + "integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==", "dev": true, "dependencies": { "@discoveryjs/json-ext": "0.5.7", "acorn": "^8.0.4", "acorn-walk": "^8.0.0", - "chalk": "^4.1.0", "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", "gzip-size": "^6.0.0", - "lodash": "^4.17.20", + "html-escaper": "^2.0.2", + "is-plain-object": "^5.0.0", "opener": "^1.5.2", - "sirv": "^1.0.7", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", "ws": "^7.3.1" }, "bin": { @@ -6577,22 +6462,6 @@ "node": ">= 10.13.0" } }, - "node_modules/webpack-bundle-analyzer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/webpack-bundle-analyzer/node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -6782,34 +6651,17 @@ "node": ">= 8" } }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/which-typed-array": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.6.tgz", - "integrity": "sha512-DdY984dGD5sQ7Tf+x1CkXzdg85b9uEel6nr4UkFg1LoE9OXv3uRuZhe5CoWdawhGACeFpEZXH8fFLQnDhbpm/Q==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.4", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.6" + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -6857,8 +6709,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yocto-queue": { "version": "0.1.0", @@ -7091,10 +6942,9 @@ } }, "@types/d3-selection": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.7.tgz", - "integrity": "sha512-qoj2O7KjfqCobmtFOth8FMvjwMVPUAAmn6xiUbLl1ld7vQCPgffvyV5BBcEFfqWdilAUm+3zciU/3P3vZrUMlg==", - "dev": true + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.10.tgz", + "integrity": "sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg==" }, "@types/d3-time": { "version": "1.0.10", @@ -7277,16 +7127,59 @@ } }, "@typescript-eslint/parser": { - "version": "6.7.3", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.3.tgz", - "integrity": "sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.1.tgz", + "integrity": "sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "6.7.3", - "@typescript-eslint/types": "6.7.3", - "@typescript-eslint/typescript-estree": "6.7.3", - "@typescript-eslint/visitor-keys": "6.7.3", + "@typescript-eslint/scope-manager": "6.13.1", + "@typescript-eslint/types": "6.13.1", + "@typescript-eslint/typescript-estree": "6.13.1", + "@typescript-eslint/visitor-keys": "6.13.1", "debug": "^4.3.4" + }, + "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz", + "integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.13.1", + "@typescript-eslint/visitor-keys": "6.13.1" + } + }, + "@typescript-eslint/types": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz", + "integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz", + "integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.13.1", + "@typescript-eslint/visitor-keys": "6.13.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz", + "integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.13.1", + "eslint-visitor-keys": "^3.4.1" + } + } } }, "@typescript-eslint/scope-manager": { @@ -7555,9 +7448,9 @@ "requires": {} }, "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", + "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", "dev": true }, "ajv": { @@ -7678,21 +7571,22 @@ } }, "assert": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", - "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", "dev": true, "requires": { - "es6-object-assign": "^1.1.0", - "is-nan": "^1.2.1", - "object-is": "^1.0.1", - "util": "^0.12.0" + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" } }, "async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", "dev": true }, "at-least-node": { @@ -7702,9 +7596,9 @@ "dev": true }, "available-typed-arrays": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz", - "integrity": "sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", "dev": true }, "balanced-match": { @@ -8006,13 +7900,14 @@ "dev": true }, "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" } }, "callsites": { @@ -8356,8 +8251,7 @@ "d3-selection": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "dev": true + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" }, "d3-time": { "version": "3.1.0", @@ -8383,6 +8277,12 @@ "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", "dev": true }, + "debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -8407,6 +8307,17 @@ "execa": "^5.0.0" } }, + "define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, "define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -8414,12 +8325,14 @@ "dev": true }, "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "requires": { - "object-keys": "^1.0.12" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" } }, "depd": { @@ -8497,9 +8410,9 @@ } }, "domain-browser": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.22.0.tgz", - "integrity": "sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-5.4.0.tgz", + "integrity": "sha512-p20fsErHHxkrpfqi6BcwUmBWpKCO9oUDAegNqtnzpiS72Zu4uEXqTFlStlOr5dOf53reASN7ab47+P8OLVIVOQ==", "dev": true }, "duplexer": { @@ -8569,54 +8482,12 @@ "prr": "~1.0.1" } }, - "es-abstract": { - "version": "1.18.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", - "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, "es-module-lexer": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", "dev": true }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-object-assign": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", - "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", - "dev": true - }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -9156,11 +9027,14 @@ "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", "dev": true }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } }, "forwarded": { "version": "0.2.0", @@ -9205,20 +9079,21 @@ "optional": true }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true }, "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" } }, "get-stream": { @@ -9279,6 +9154,15 @@ "slash": "^3.0.0" } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -9306,31 +9190,31 @@ "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "dev": true }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", "dev": true, "requires": { - "function-bind": "^1.1.1" + "get-intrinsic": "^1.2.2" } }, - "has-bigints": { + "has-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", "dev": true }, "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true }, "has-tostringtag": { @@ -9371,6 +9255,15 @@ "minimalistic-assert": "^1.0.1" } }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -9426,6 +9319,12 @@ "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", "dev": true }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", @@ -9564,17 +9463,6 @@ } } }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, "internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", @@ -9597,15 +9485,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -9615,31 +9494,12 @@ "binary-extensions": "^2.0.0" } }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, "is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -9680,27 +9540,12 @@ "define-properties": "^1.1.3" } }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true - }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, "is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -9713,15 +9558,11 @@ "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true }, "is-stream": { "version": "2.0.1", @@ -9729,35 +9570,13 @@ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, "is-typed-array": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.7.tgz", - "integrity": "sha512-VxlpTBGknhQ3o7YiVjIhdLU6+oD8dPz/79vvvH4F+S/c8608UCVa9fgDpa1kZgFoUST2DCgacc70UszKgzKuvA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", "dev": true, "requires": { - "available-typed-arrays": "^1.0.4", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", - "has-tostringtag": "^1.0.0" + "which-typed-array": "^1.1.11" } }, "is-what": { @@ -9974,12 +9793,6 @@ "p-locate": "^5.0.0" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -9998,6 +9811,12 @@ "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", "dev": true }, + "lodash.ismatch": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", + "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -10014,7 +9833,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -10304,14 +10122,14 @@ "dev": true }, "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" } }, @@ -10327,6 +10145,26 @@ "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true }, + "on-object-utils": { + "version": "file:..\\..\\Utils\\on-object-utils\\on-object-utils-1.0.0.tgz", + "integrity": "sha512-rBcLdKDSXVdhLwOeAcdLRT6fVyAsvB6TgafZjurJalr/U05gcc2rD4uzGVX1uEToCvuZEQijC8q5BSKTSC7HeA==", + "requires": { + "@types/d3-selection": "^3.0.10", + "d3-selection": "^3.0.0", + "powerbi-visuals-api": "~5.1.0", + "typescript": "^5.3.2" + }, + "dependencies": { + "powerbi-visuals-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.1.0.tgz", + "integrity": "sha512-ol+h1gF1VRK3n6/wwXR2YMkQsczHU3aiqmqtPl0/KEHPbCBQon/0vcdOVDXFp5QtYj/Ua+LXegD47x8K9FWCzg==", + "requires": { + "semver": "^7.3.5" + } + } + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -10597,24 +10435,24 @@ } }, "powerbi-visuals-tools": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/powerbi-visuals-tools/-/powerbi-visuals-tools-5.1.1.tgz", - "integrity": "sha512-kQTWXYI416H5Oh6PPi62Wu7LogGYVnpRjVBJU+dFcXBzzx5MWOecmdY/0Z9Jt2hK6LY0xZuiOxue8mxoOSQQPg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-tools/-/powerbi-visuals-tools-5.3.0.tgz", + "integrity": "sha512-d6Y7MuqDqpMyl4r7aAwC85NW2UDYzCUE9hbuUCItrfUdAEHpPGg6eqhPYjZREbbkEmeXNPjGrYra+91XMq6csQ==", "dev": true, "requires": { - "@typescript-eslint/parser": "^5.62.0", - "assert": "^2.0.0", - "async": "^3.2.4", + "@typescript-eslint/parser": "^6.12.0", + "assert": "^2.1.0", + "async": "^3.2.5", "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", "chalk": "^5.3.0", - "commander": "^11.0.0", + "commander": "^11.1.0", "compare-versions": "^6.1.0", "console-browserify": "^1.2.0", "constants-browserify": "^1.0.0", "crypto-browserify": "^3.12.0", "css-loader": "^6.8.1", - "domain-browser": "^4.22.0", + "domain-browser": "^5.4.0", "events": "^3.3.0", "extra-watch-webpack-plugin": "^1.0.3", "fs-extra": "^11.1.1", @@ -10628,12 +10466,13 @@ "lodash.clonedeep": "4.5.0", "lodash.defaults": "4.2.0", "lodash.isequal": "4.5.0", + "lodash.ismatch": "^4.4.0", "mini-css-extract-plugin": "^2.7.6", "os-browserify": "^0.3.0", "path-browserify": "^1.0.1", - "powerbi-visuals-webpack-plugin": "4.0.1", + "powerbi-visuals-webpack-plugin": "4.1.0", "process": "^0.11.10", - "punycode": "^2.3.0", + "punycode": "^2.3.1", "querystring-es3": "^0.2.1", "readable-stream": "^4.4.2", "stream-browserify": "^3.0.0", @@ -10641,74 +10480,21 @@ "string_decoder": "^1.3.0", "terser-webpack-plugin": "^5.3.9", "timers-browserify": "^2.0.12", - "ts-loader": "^9.4.4", + "ts-loader": "^9.5.1", "tty-browserify": "^0.0.1", "typescript": "^4.9.5", - "url": "^0.11.1", + "url": "^0.11.3", "util": "^0.12.5", "vm-browserify": "^1.1.2", - "webpack": "^5.88.2", - "webpack-bundle-analyzer": "4.9.0", + "webpack": "^5.89.0", + "webpack-bundle-analyzer": "4.10.1", "webpack-dev-server": "^4.15.1" }, "dependencies": { - "@typescript-eslint/parser": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" - } - }, - "@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - } - }, "commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true }, "readable-stream": { @@ -10741,6 +10527,26 @@ "fsevents": "*" } }, + "powerbi-visuals-utils-formattingmodel": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-utils-formattingmodel/-/powerbi-visuals-utils-formattingmodel-6.0.0.tgz", + "integrity": "sha512-2G2qNfcTlJ+aR7CkZDrG75SzH6WO3So/xJFOGtY4bfiVQC4J1ao0juxmIZEyJkCPRV0Sbxg3N0kMxqjOKjdBMA==", + "dev": true, + "requires": { + "powerbi-visuals-api": "~5.1.0" + }, + "dependencies": { + "powerbi-visuals-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.1.0.tgz", + "integrity": "sha512-ol+h1gF1VRK3n6/wwXR2YMkQsczHU3aiqmqtPl0/KEHPbCBQon/0vcdOVDXFp5QtYj/Ua+LXegD47x8K9FWCzg==", + "dev": true, + "requires": { + "semver": "^7.3.5" + } + } + } + }, "powerbi-visuals-utils-formattingutils": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/powerbi-visuals-utils-formattingutils/-/powerbi-visuals-utils-formattingutils-6.0.1.tgz", @@ -10776,6 +10582,25 @@ "powerbi-visuals-utils-typeutils": "^6.0.1" } }, + "powerbi-visuals-utils-onobjectformatting": { + "version": "file:..\\..\\powerbi-visuals-utils-onobjectformatting\\powerbi-visuals-utils-onobjectformatting-1.0.0.tgz", + "integrity": "sha512-6QeFsdCHs8nETNgItTJGjTiHrlh9t18QzyQaazjjZOpBV6JQReTuKj6jZOertsiotB5I7teiJUssBYhqO5pjVw==", + "requires": { + "@types/d3-selection": "^3.0.10", + "d3-selection": "^3.0.0", + "powerbi-visuals-api": "~5.1.0" + }, + "dependencies": { + "powerbi-visuals-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.1.0.tgz", + "integrity": "sha512-ol+h1gF1VRK3n6/wwXR2YMkQsczHU3aiqmqtPl0/KEHPbCBQon/0vcdOVDXFp5QtYj/Ua+LXegD47x8K9FWCzg==", + "requires": { + "semver": "^7.3.5" + } + } + } + }, "powerbi-visuals-utils-svgutils": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/powerbi-visuals-utils-svgutils/-/powerbi-visuals-utils-svgutils-6.0.1.tgz", @@ -10806,9 +10631,9 @@ } }, "powerbi-visuals-webpack-plugin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/powerbi-visuals-webpack-plugin/-/powerbi-visuals-webpack-plugin-4.0.1.tgz", - "integrity": "sha512-ologdk1TEX2qdvKy9EloIdUf8bxLayvWwoKvyvDbFudMUNOwoiobxaJUXxP11j3DaygrP9PeO0hQoNbVwAuymA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-webpack-plugin/-/powerbi-visuals-webpack-plugin-4.1.0.tgz", + "integrity": "sha512-ttXVVsQYcs6VuoMNZ4SRaK9vdRaIZsU1S16sDSgcnnf5dlaXXiB/j411HACdYLMrU0YUR/vI4QTC7xq52hbMgw==", "dev": true, "requires": { "ajv": "6.12.3", @@ -10934,9 +10759,9 @@ } }, "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true }, "qs": { @@ -11199,7 +11024,6 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, "requires": { "lru-cache": "^6.0.0" } @@ -11269,6 +11093,18 @@ } } }, + "set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "requires": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -11324,14 +11160,14 @@ "dev": true }, "sirv": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz", - "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", + "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==", "dev": true, "requires": { "@polka/url": "^1.0.0-next.20", "mrmime": "^1.0.0", - "totalist": "^1.0.0" + "totalist": "^3.0.0" } }, "slash": { @@ -11453,26 +11289,6 @@ } } }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -11578,9 +11394,9 @@ } }, "totalist": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", - "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", "dev": true }, "ts-api-utils": { @@ -11591,15 +11407,16 @@ "requires": {} }, "ts-loader": { - "version": "9.4.4", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.4.tgz", - "integrity": "sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", "dev": true, "requires": { "chalk": "^4.1.0", "enhanced-resolve": "^5.0.0", "micromatch": "^4.0.0", - "semver": "^7.3.4" + "semver": "^7.3.4", + "source-map": "^0.7.4" }, "dependencies": { "chalk": { @@ -11611,6 +11428,12 @@ "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true } } }, @@ -11620,23 +11443,6 @@ "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", "dev": true }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, "tty-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", @@ -11669,22 +11475,9 @@ } }, "typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", - "dev": true - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==" }, "universalify": { "version": "2.0.0", @@ -11792,9 +11585,9 @@ } }, "webpack": { - "version": "5.88.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", - "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", @@ -11837,33 +11630,26 @@ } }, "webpack-bundle-analyzer": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.9.0.tgz", - "integrity": "sha512-+bXGmO1LyiNx0i9enBu3H8mv42sj/BJWhZNFwjz92tVnBa9J3JMGo2an2IXlEleoDOPn/Hofl5hr/xCpObUDtw==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz", + "integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==", "dev": true, "requires": { "@discoveryjs/json-ext": "0.5.7", "acorn": "^8.0.4", "acorn-walk": "^8.0.0", - "chalk": "^4.1.0", "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", "gzip-size": "^6.0.0", - "lodash": "^4.17.20", + "html-escaper": "^2.0.2", + "is-plain-object": "^5.0.0", "opener": "^1.5.2", - "sirv": "^1.0.7", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", "ws": "^7.3.1" }, "dependencies": { - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, "commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -11978,31 +11764,17 @@ "isexe": "^2.0.0" } }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, "which-typed-array": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.6.tgz", - "integrity": "sha512-DdY984dGD5sQ7Tf+x1CkXzdg85b9uEel6nr4UkFg1LoE9OXv3uRuZhe5CoWdawhGACeFpEZXH8fFLQnDhbpm/Q==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", "dev": true, "requires": { - "available-typed-arrays": "^1.0.4", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.6" + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" } }, "wrappy": { @@ -12027,8 +11799,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yocto-queue": { "version": "0.1.0", diff --git a/package.json b/package.json index 7e7936c..3e9138e 100644 --- a/package.json +++ b/package.json @@ -21,11 +21,15 @@ "eslint": "^8.50.0", "eslint-plugin-powerbi-visuals": "^0.8.1", "powerbi-visuals-api": "~5.4.0", - "powerbi-visuals-tools": "^5.1.1", + "powerbi-visuals-tools": "^5.3.0", "powerbi-visuals-utils-dataviewutils": "^6.0.1", + "powerbi-visuals-utils-formattingmodel": "6.0.0", "powerbi-visuals-utils-formattingutils": "^6.0.1", "powerbi-visuals-utils-interactivityutils": "^6.0.2", "powerbi-visuals-utils-tooltiputils": "^6.0.1", "typescript": "^5.1.6" + }, + "dependencies": { + "powerbi-visuals-utils-onobjectformatting": "file:../../powerbi-visuals-utils-onobjectformatting/powerbi-visuals-utils-onobjectformatting-1.0.0.tgz" } } diff --git a/pbiviz.json b/pbiviz.json index 313591c..f5b6fd4 100644 --- a/pbiviz.json +++ b/pbiviz.json @@ -4,12 +4,12 @@ "displayName": "barChart", "guid": "PBI_CV_9894B302_1DFF_4A96_ABFE_BF8588197166", "visualClassName": "BarChart", - "version": "4.0.0", + "version": "4.0.0.0", "description": "Sample bar chart", "supportUrl": "pbicvsupport@microsoft.com", "gitHubUrl": "" }, - "apiVersion": "5.4.0", + "apiVersion": "5.8.0", "author": { "name": "Author name", "email": "author@mail.com" diff --git a/src/barChart.ts b/src/barChart.ts index f932f49..44a4e1d 100644 --- a/src/barChart.ts +++ b/src/barChart.ts @@ -1,26 +1,37 @@ -import "./../style/visual.less"; import { + BaseType, select as d3Select, - Selection as d3Selection, - BaseType + Selection as d3Selection } from "d3-selection"; import { + scaleBand, scaleLinear, - ScaleLinear, - scaleBand + ScaleLinear } from "d3-scale"; import { axisBottom } from "d3-axis"; import powerbiVisualsApi from "powerbi-visuals-api"; +import { createTooltipServiceWrapper, ITooltipServiceWrapper } from "powerbi-visuals-utils-tooltiputils"; +import { FormattingSettingsService } from "powerbi-visuals-utils-formattingmodel"; +import { textMeasurementService, valueFormatter } from "powerbi-visuals-utils-formattingutils"; +import { dataViewWildcard } from "powerbi-visuals-utils-dataviewutils"; +import { HtmlSubSelectableClass, HtmlSubSelectionHelper, SubSelectableDirectEdit as SubSelectableDirectEditAttr, SubSelectableDisplayNameAttribute, SubSelectableObjectNameAttribute, SubSelectableTypeAttribute } from '../node_modules/powerbi-visuals-utils-onobjectformatting/src'; + +import { BarChartSettingsModel } from "./barChartSettingsModel"; +import { getLocalizedString } from "./localization/localizationHelper" +import { getValue, getCategoricalObjectValue } from "./objectEnumerationUtility"; + +import "./../style/visual.less"; + import powerbi = powerbiVisualsApi; type Selection = d3Selection; // powerbi.visuals +import CustomVisualSubSelection = powerbi.visuals.CustomVisualSubSelection; import DataViewCategoryColumn = powerbi.DataViewCategoryColumn; import DataViewObjects = powerbi.DataViewObjects; -import EnumerateVisualObjectInstancesOptions = powerbi.EnumerateVisualObjectInstancesOptions; import Fill = powerbi.Fill; import ISandboxExtendedColorPalette = powerbi.extensibility.ISandboxExtendedColorPalette; import ISelectionId = powerbi.visuals.ISelectionId; @@ -28,97 +39,83 @@ import ISelectionManager = powerbi.extensibility.ISelectionManager; import IVisual = powerbi.extensibility.IVisual; import IVisualHost = powerbi.extensibility.visual.IVisualHost; import PrimitiveValue = powerbi.PrimitiveValue; -import VisualObjectInstance = powerbi.VisualObjectInstance; -import VisualObjectInstanceEnumeration = powerbi.VisualObjectInstanceEnumeration; +import SubSelectableDirectEdit = powerbi.visuals.SubSelectableDirectEdit; +import SubSelectableDirectEditStyle = powerbi.visuals.SubSelectableDirectEditStyle; +import SubSelectionShortcutsKey = powerbi.visuals.SubSelectionShortcutsKey; +import SubSelectionStyles = powerbi.visuals.SubSelectionStyles; +import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions; +import VisualShortcutType = powerbi.visuals.VisualShortcutType; +import VisualSubSelectionShortcuts = powerbi.visuals.VisualSubSelectionShortcuts; import VisualTooltipDataItem = powerbi.extensibility.VisualTooltipDataItem; import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions; -import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions; -import VisualEnumerationInstanceKinds = powerbi.VisualEnumerationInstanceKinds; - -import { createTooltipServiceWrapper, ITooltipServiceWrapper } from "powerbi-visuals-utils-tooltiputils"; -import { textMeasurementService, valueFormatter } from "powerbi-visuals-utils-formattingutils"; - -import { getValue, getCategoricalObjectValue } from "./objectEnumerationUtility"; -import { getLocalizedString } from "./localization/localizationHelper" -import { dataViewWildcard } from "powerbi-visuals-utils-dataviewutils"; +import SliceFormattingModelReference = powerbi.visuals.SliceFormattingModelReference +import SubSelectionStylesType = powerbi.visuals.SubSelectionStylesType; -/** - * Interface for BarCharts viewmodel. - * - * @interface - * @property {BarChartDataPoint[]} dataPoints - Set of data points the visual will render. - * @property {number} dataMax - Maximum data value in the set of data points. - */ -interface BarChartViewModel { - dataPoints: BarChartDataPoint[]; - dataMax: number; - settings: BarChartSettings; -} /** * Interface for BarChart data points. * * @interface - * @property {number} value - Data value for point. + * @property {PrimitiveValue} value - Data value for point. * @property {string} category - Corresponding category of data value. * @property {string} color - Color corresponding to data point. + * @property {string} strokeColor - Stroke color for data point column. + * @property {number} strokeWidth - Stroke width for data point column. * @property {ISelectionId} selectionId - Id assigned to data point for cross filtering * and visual interaction. */ -interface BarChartDataPoint { +export interface BarChartDataPoint { value: PrimitiveValue; category: string; color: string; strokeColor: string; strokeWidth: number; selectionId: ISelectionId; + index: number; format?: string; } -/** - * Interface for BarChart settings. - * - * @interface - * @property {{show:boolean}} enableAxis - Object property that allows axis to be enabled. - * @property {{generalView.opacity:number}} Bars Opacity - Controls opacity of plotted bars, values range between 10 (almost transparent) to 100 (fully opaque, default) - * @property {{generalView.showHelpLink:boolean}} Show Help Button - When TRUE, the plot displays a button which launch a link to documentation. - */ -interface BarChartSettings { - enableAxis: { - show: boolean; - fill: string; - }; - - generalView: { - opacity: number; - showHelpLink: boolean; - helpLinkColor: string; - }; +interface SliceReferences { + cardUid?: string; + groupUid?: string; + fillSliceUid?: string; + fontSliceUid?: string; + fontColorSliceUid?: string; +} - averageLine: { - show: boolean; - displayName: string; - fill: string; - showDataLabel: boolean; - }; +const enum BarChartObjectNames { + ArcElement = 'arcElement', + ColorSelector = 'colorSelector', + EnableAxis = 'enableAxis', + DirectEdit = 'directEditTest' } -const defaultSettings: BarChartSettings = { - enableAxis: { - show: false, - fill: "#000000", - }, - generalView: { - opacity: 100, - showHelpLink: false, - helpLinkColor: "#80B0E0", +const DirectEdit: SubSelectableDirectEdit = { + reference: { + cardUid: 'Visual-directEditTest-card', + groupUid: 'directEditTest-group', + sliceUid: 'directEditTest-textProperty', }, - averageLine: { - show: false, - displayName: "Average Line", - fill: "#888888", - showDataLabel: false - } + style: SubSelectableDirectEditStyle.Outline, +}; + +const colorSelectorReferences: SliceReferences = { + cardUid: 'Visual-colorSelector-card', + groupUid: 'colorSelector-group', + fillSliceUid: 'colorSelector-fill' +}; + +const enableAxisReferences: SliceReferences = { + cardUid: 'Visual-enableAxis-card', + groupUid: 'enableAxis-group', + fillSliceUid: 'enableAxis-fill' +}; + +const directEditReferences: SliceReferences = { + cardUid: 'Visual-directEditTest-card', + groupUid: 'directEditTest-group', + fontSliceUid: 'directEditTest-font', + fontColorSliceUid: 'directEditTest-fontColor' }; /** @@ -130,13 +127,9 @@ const defaultSettings: BarChartSettings = { * the visual had queried. * @param {IVisualHost} host - Contains references to the host which contains services */ -function visualTransform(options: VisualUpdateOptions, host: IVisualHost): BarChartViewModel { +function createSelectorDataPoints(options: VisualUpdateOptions, host: IVisualHost): BarChartDataPoint[] { + const barChartDataPoints: BarChartDataPoint[] = [] const dataViews = options.dataViews; - const viewModel: BarChartViewModel = { - dataPoints: [], - dataMax: 0, - settings: {} - }; if (!dataViews || !dataViews[0] @@ -145,39 +138,20 @@ function visualTransform(options: VisualUpdateOptions, host: IVisualHost): BarCh || !dataViews[0].categorical.categories[0].source || !dataViews[0].categorical.values ) { - return viewModel; + return barChartDataPoints; } const categorical = dataViews[0].categorical; const category = categorical.categories[0]; const dataValue = categorical.values[0]; - const barChartDataPoints: BarChartDataPoint[] = []; - let dataMax: number = 0; + //let dataMax: number = 0; const colorPalette: ISandboxExtendedColorPalette = host.colorPalette; - const objects = dataViews[0].metadata.objects; + //const objects = dataViews[0].metadata.objects; const strokeColor: string = getColumnStrokeColor(colorPalette); - const barChartSettings: BarChartSettings = { - enableAxis: { - show: getValue(objects, 'enableAxis', 'show', defaultSettings.enableAxis.show), - fill: getAxisTextFillColor(objects, colorPalette, defaultSettings.enableAxis.fill), - }, - generalView: { - opacity: getValue(objects, 'generalView', 'opacity', defaultSettings.generalView.opacity), - showHelpLink: getValue(objects, 'generalView', 'showHelpLink', defaultSettings.generalView.showHelpLink), - helpLinkColor: strokeColor, - }, - averageLine: { - show: getValue(objects, 'averageLine', 'show', defaultSettings.averageLine.show), - displayName: getValue(objects, 'averageLine', 'displayName', defaultSettings.averageLine.displayName), - fill: getValue(objects, 'averageLine', 'fill', defaultSettings.averageLine.fill), - showDataLabel: getValue(objects, 'averageLine', 'showDataLabel', defaultSettings.averageLine.showDataLabel), - }, - }; - const strokeWidth: number = getColumnStrokeWidth(colorPalette.isHighContrast); for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) { @@ -194,17 +168,12 @@ function visualTransform(options: VisualUpdateOptions, host: IVisualHost): BarCh selectionId, value: dataValue.values[i], category: `${category.values[i]}`, + index: i, format: dataValue.objects ? dataValue.objects[i].general.formatString : null, }); } - dataMax = dataValue.maxLocal; - - return { - dataPoints: barChartDataPoints, - dataMax: dataMax, - settings: barChartSettings, - }; + return barChartDataPoints; } function getColumnColorByIndex( @@ -265,24 +234,31 @@ function getAxisTextFillColor( } export class BarChart implements IVisual { - private svg: Selection; - private host: IVisualHost; - private selectionManager: ISelectionManager; + private averageLine: Selection; private barContainer: Selection; - private xAxis: Selection; private barDataPoints: BarChartDataPoint[]; - private barChartSettings: BarChartSettings; - private tooltipServiceWrapper: ITooltipServiceWrapper; - private locale: string; - private helpLinkElement: Selection; private element: HTMLElement; + private formattingSettingsService: FormattingSettingsService; + private formattingSettings: BarChartSettingsModel; + private helpLinkElement: Selection; + private host: IVisualHost; private isLandingPageOn: boolean; - private LandingPageRemoved: boolean; private LandingPage: Selection; - private averageLine: Selection; + private LandingPageRemoved: boolean; + private locale: string; + private selectionManager: ISelectionManager; + private svg: Selection; + private tooltipServiceWrapper: ITooltipServiceWrapper; + private xAxis: Selection; private barSelection: Selection; + private subSelectionHelper: HtmlSubSelectionHelper; + private formatMode: boolean = false; + private directEditElement: Selection; + private visualDirectEditSubSelection = JSON.stringify(DirectEdit); + public visualOnObjectFormatting?: powerbi.extensibility.visual.VisualOnObjectFormatting; + static Config = { xScalePadding: 0.1, solidOpacity: 1, @@ -316,6 +292,16 @@ export class BarChart implements IVisual { this.tooltipServiceWrapper = createTooltipServiceWrapper(this.host.tooltipService, options.element); + //Creating the formatting settings service. + const localizationManager = this.host.createLocalizationManager(); + this.formattingSettingsService = new FormattingSettingsService(localizationManager); + + this.subSelectionHelper = HtmlSubSelectionHelper.createHtmlSubselectionHelper({ + hostElement: options.element, + subSelectionService: options.host.subSelectionService, + selectionIdCallback: (e) => this.selectionIdCallback(e), + }); + this.svg = d3Select(options.element) .append('svg') .classed('barChart', true); @@ -335,6 +321,17 @@ export class BarChart implements IVisual { this.helpLinkElement = d3Select(helpLinkElement); + //create direct edit box + const directEditDiv = this.creatDirectEditElement(); + options.element.appendChild(directEditDiv); + this.directEditElement = d3Select(directEditDiv); + + this.visualOnObjectFormatting = { + getSubSelectionStyles: (subSelections) => this.getSubSelectionStyles(subSelections), + getSubSelectionShortcuts: (subSelections, filter) => this.getSubSelectionShortcuts(subSelections, filter), + getSubSelectables: (filter) => this.getSubSelectables(filter) + }; + this.handleContextMenu(); } @@ -347,11 +344,12 @@ export class BarChart implements IVisual { * the visual had queried. */ public update(options: VisualUpdateOptions) { - const viewModel: BarChartViewModel = visualTransform(options, this.host); - const settings = this.barChartSettings = viewModel.settings; - this.barDataPoints = viewModel.dataPoints; // Turn on landing page in capabilities and remove comment to turn on landing page! // this.HandleLandingPage(options); + this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(BarChartSettingsModel, options.dataViews?.[0]); + this.barDataPoints = createSelectorDataPoints(options, this.host); + this.formattingSettings.populateColorSelector(this.barDataPoints); + this.formatMode = options.formatMode; const width = options.viewport.width; let height = options.viewport.height; @@ -359,26 +357,40 @@ export class BarChart implements IVisual { .attr("width", width) .attr("height", height); - if (settings.enableAxis.show) { + if (this.formattingSettings.enableAxis.show.value) { const margins = BarChart.Config.margins; height -= margins.bottom; } this.helpLinkElement - .classed("hidden", !settings.generalView.showHelpLink) - .style("border-color", settings.generalView.helpLinkColor) - .style("color", settings.generalView.helpLinkColor); + .classed("hidden", !this.formattingSettings.generalView.showHelpLink.value) + .style("border-color", this.formattingSettings.generalView.helpLinkColor) + .style("color", this.formattingSettings.generalView.helpLinkColor); + + this.directEditElement + .classed('direct-edit', true) + .classed('hidden', !this.formattingSettings.directEditSettings.show.value) + .attr(SubSelectableObjectNameAttribute, 'directEditTest') + .attr(SubSelectableDisplayNameAttribute, 'Direct Edit') + .attr(SubSelectableDirectEditAttr, this.visualDirectEditSubSelection) + .classed(HtmlSubSelectableClass, options.formatMode && this.formattingSettings.directEditSettings.show.value) + .style('font-family', this.formattingSettings.directEditSettings.font.fontFamily.value) + .style('color', this.formattingSettings.directEditSettings.fontColor.value.value) + .style('font-style', this.formattingSettings.directEditSettings.font.italic.value ? 'italic' : 'normal') + .style('text-decoration', this.formattingSettings.directEditSettings.font.underline.value ? 'underline' : 'none') + .style('font-weight', this.formattingSettings.directEditSettings.font.bold.value ? 'bold' : 'normal') + .text(this.formattingSettings.directEditSettings.textProperty.value); this.xAxis .style("font-size", Math.min(height, width) * BarChart.Config.xAxisFontMultiplier) - .style("fill", settings.enableAxis.fill); + .style("fill", this.formattingSettings.enableAxis.fill.value.value); const yScale = scaleLinear() - .domain([0, viewModel.dataMax]) + .domain([0, options.dataViews[0].categorical.values[0].maxLocal]) .range([height, 0]); const xScale = scaleBand() - .domain(viewModel.dataPoints.map(d => d.category)) + .domain(this.barDataPoints.map(d => d.category)) .rangeRound([0, width]) .padding(0.2); @@ -389,10 +401,15 @@ export class BarChart implements IVisual { .attr("color", getAxisTextFillColor( colorObjects, this.host.colorPalette, - defaultSettings.enableAxis.fill + this.formattingSettings.enableAxis.fill.value.value )); - const textNodes = this.xAxis.selectAll("text") + const textNodes = this.xAxis.selectAll("text"); + textNodes + .attr(SubSelectableObjectNameAttribute, 'enableAxis') + .attr(SubSelectableDisplayNameAttribute, 'x-Axis') + .attr(SubSelectableTypeAttribute, powerbi.visuals.SubSelectionStylesType.Shape) + .classed(HtmlSubSelectableClass, options.formatMode && this.formattingSettings.enableAxis.show.value); BarChart.wordBreak(textNodes, xScale.bandwidth(), height); this.handleAverageLineUpdate(height, width, yScale); @@ -407,12 +424,16 @@ export class BarChart implements IVisual { barSelectionMerged.classed('bar', true); - const opacity: number = viewModel.settings.generalView.opacity / 100; + const opacity: number = this.formattingSettings.generalView.opacity.value / 100; barSelectionMerged .attr("width", xScale.bandwidth()) .attr("height", d => height - yScale(d.value)) .attr("y", d => yScale(d.value)) .attr("x", d => xScale(d.category)) + .attr(SubSelectableObjectNameAttribute, 'colorSelector') + .attr(SubSelectableDisplayNameAttribute, d => `colorSelector-${d.index}`) + .attr(SubSelectableTypeAttribute, powerbi.visuals.SubSelectionStylesType.Shape) + .classed(HtmlSubSelectableClass, options.formatMode) .style("fill-opacity", opacity) .style("stroke-opacity", opacity) .style("fill", (dataPoint: BarChartDataPoint) => dataPoint.color) @@ -420,28 +441,32 @@ export class BarChart implements IVisual { .style("stroke-width", (dataPoint: BarChartDataPoint) => `${dataPoint.strokeWidth}px`); this.tooltipServiceWrapper.addTooltip(barSelectionMerged, - (datapoint: BarChartDataPoint) => this.getTooltipData(datapoint), - (datapoint: BarChartDataPoint) => datapoint.selectionId + (dataPoint: BarChartDataPoint) => this.getTooltipData(dataPoint), + (dataPoint: BarChartDataPoint) => dataPoint.selectionId ); this.syncSelectionState( barSelectionMerged, this.selectionManager.getSelectionIds() ); + if (this.formatMode) { + barSelectionMerged.on('click', null); + this.svg.on('click', null); + this.svg.on('contextmenu', null); + } else { + this.handleBarClick(barSelectionMerged); + this.handleClick(barSelectionMerged); + this.handleContextMenu(); + } - barSelectionMerged.on('click', (event: Event, datum: BarChartDataPoint) => { - // Allow selection only if the visual is rendered in a view that supports interactivity (e.g. Report) - if (this.host.hostCapabilities.allowInteractions) { - const isCtrlPressed: boolean = (event).ctrlKey; + this.subSelectionHelper.setFormatMode(options.formatMode); + const shouldUpdateSubSelection = options.type & powerbi.VisualUpdateType.Data + || options.type & powerbi.VisualUpdateType.Resize + || options.type & powerbi.VisualUpdateType.FormattingSubSelectionChange; + if (this.formatMode && shouldUpdateSubSelection) { + this.subSelectionHelper.updateOutlinesFromSubSelections(options.subSelections, true); + } - this.selectionManager - .select(datum.selectionId, isCtrlPressed) - .then((ids: ISelectionId[]) => { - this.syncSelectionState(barSelectionMerged, ids); - }); - (event).stopPropagation(); - } - }); this.barSelection .exit() .remove(); @@ -461,6 +486,22 @@ export class BarChart implements IVisual { }); } + private handleBarClick(barSelectionMerged: Selection) { + barSelectionMerged.on('click', (event: Event, datum: BarChartDataPoint) => { + // Allow selection only if the visual is rendered in a view that supports interactivity (e.g. Report) + if (this.host.hostCapabilities.allowInteractions) { + const isCtrlPressed: boolean = (event).ctrlKey; + + this.selectionManager + .select(datum.selectionId, isCtrlPressed) + .then((ids: ISelectionId[]) => { + this.syncSelectionState(barSelectionMerged, ids); + }); + (event).stopPropagation(); + } + }); + } + private handleClick(barSelection: Selection) { // Clear selection when clicking outside a bar this.svg.on('click', () => { @@ -496,7 +537,7 @@ export class BarChart implements IVisual { } if (!selectionIds.length) { - const opacity: number = this.barChartSettings.generalView.opacity / 100; + const opacity: number = this.formattingSettings.generalView.opacity.value / 100; selection .style("fill-opacity", opacity) .style("stroke-opacity", opacity); @@ -529,85 +570,196 @@ export class BarChart implements IVisual { } /** - * Enumerates through the objects defined in the capabilities and adds the properties to the format pane - * - * @function - * @param {EnumerateVisualObjectInstancesOptions} options - Map of defined objects + * Returns properties pane formatting model content hierarchies, properties and latest formatting values, Then populate properties pane. + * This method is called once every time we open properties pane or when the user edit any format property. */ - public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstanceEnumeration { - const objectName = options.objectName; - const objectEnumeration: VisualObjectInstance[] = []; - - if (!this.barChartSettings || - !this.barChartSettings.enableAxis || - !this.barDataPoints) { - return objectEnumeration; + public getFormattingModel(): powerbiVisualsApi.visuals.FormattingModel { + return this.formattingSettingsService.buildFormattingModel(this.formattingSettings); + } + + private getSubSelectionStyles(subSelections: CustomVisualSubSelection[]): powerbi.visuals.SubSelectionStyles | undefined { + const visualObject = subSelections[0]?.customVisualObjects[0]; + if (visualObject) { + switch (visualObject.objectName) { + case BarChartObjectNames.ColorSelector: + return this.getColorSelectorStyles(subSelections); + case BarChartObjectNames.EnableAxis: + return this.getEnableAxisStyles(); + case BarChartObjectNames.DirectEdit: + return this.getDirectEditStyles(); + } } + } + private getSubSelectionShortcuts(subSelections: CustomVisualSubSelection[], filter: SubSelectionShortcutsKey | undefined): VisualSubSelectionShortcuts | undefined { + const visualObject = subSelections[0]?.customVisualObjects[0]; + if (visualObject) { + switch (visualObject.objectName) { + case BarChartObjectNames.ColorSelector: + return this.getColorSelectorShortcuts(subSelections); + case BarChartObjectNames.EnableAxis: + return this.getEnableAxisShortcuts(); + case BarChartObjectNames.DirectEdit: + return this.getDirectEditShortcuts(); + } + } + } + private getSubSelectables?(filter?: powerbi.visuals.SubSelectionStylesType): CustomVisualSubSelection[] | undefined { + return this.subSelectionHelper.getAllSubSelectables(filter); + } - switch (objectName) { - case 'enableAxis': - objectEnumeration.push({ - objectName: objectName, - properties: { - show: this.barChartSettings.enableAxis.show, - fill: this.barChartSettings.enableAxis.fill, - }, - selector: null - }); - break; - case 'colorSelector': - for (const barDataPoint of this.barDataPoints) { - objectEnumeration.push({ - objectName: objectName, - displayName: barDataPoint.category, - properties: { - fill: { - solid: { - color: barDataPoint.color - } - } - }, - propertyInstanceKind: { - fill: VisualEnumerationInstanceKinds.ConstantOrRule - }, - altConstantValueSelector: barDataPoint.selectionId.getSelector(), - selector: dataViewWildcard.createDataViewWildcardSelector(dataViewWildcard.DataViewWildcardMatchingOption.InstancesAndTotals) - }); - } - break; - case 'generalView': - objectEnumeration.push({ - objectName: objectName, - properties: { - opacity: this.barChartSettings.generalView.opacity, - showHelpLink: this.barChartSettings.generalView.showHelpLink - }, - validValues: { - opacity: { - numberRange: { - min: 10, - max: 100 - } - } - }, - selector: null - }); - break; - case 'averageLine': - objectEnumeration.push({ - objectName: objectName, - properties: { - show: this.barChartSettings.averageLine.show, - displayName: this.barChartSettings.averageLine.displayName, - fill: this.barChartSettings.averageLine.fill, - showDataLabel: this.barChartSettings.averageLine.showDataLabel - }, - selector: null - }); - break; + private getColorSelectorShortcuts(subSelections: CustomVisualSubSelection[]): VisualSubSelectionShortcuts { + const selector = subSelections[0].customVisualObjects[0].selectionId?.getSelector(); + return [ + { + type: VisualShortcutType.Reset, + relatedResetSourceUids: [{ + sourceUid: colorSelectorReferences.fillSliceUid, + selector + }] + }, + { + type: VisualShortcutType.Navigate, + destinationUids: [{ cardUid: colorSelectorReferences.cardUid }], + label: 'colorlabel' + } + ]; + } + + private getColorSelectorStyles(subSelections: CustomVisualSubSelection[]): SubSelectionStyles { + const cardUid = colorSelectorReferences.cardUid; + const groupUid = colorSelectorReferences.groupUid; + const sliceUid = colorSelectorReferences.fillSliceUid; + const selector = subSelections[0].customVisualObjects[0].selectionId?.getSelector(); + return { + type: SubSelectionStylesType.Shape, + fill: { + label: 'Visual_Fill', + reference: { + cardUid, + groupUid, + sliceUid, + selector, + }, + }, + color: { + label: 'Visual_Color', + reference: { + cardUid, + groupUid, + sliceUid, + selector, + }, + }, + }; + } + + private getEnableAxisStyles(): SubSelectionStyles { + return { + type: SubSelectionStylesType.Shape, + fill: { + reference: { + cardUid: enableAxisReferences.cardUid, + groupUid: enableAxisReferences.groupUid, + sliceUid: enableAxisReferences.fillSliceUid + }, + label: 'Enable Axis' + } + } + } + + private getEnableAxisShortcuts(): VisualSubSelectionShortcuts { + return [ + { + type: VisualShortcutType.Reset, + relatedResetSourceUids: [{ + sourceUid: enableAxisReferences.fillSliceUid, + + }] + }, + { + type: VisualShortcutType.Toggle, + sourceUid: enableAxisReferences.cardUid, + disabledLabel: 'Delete', + keyboardShortcuts: [{ + key: 'Delete', + nextValue: false, + }] + }, + { + type: VisualShortcutType.Navigate, + destinationUids: [{ cardUid: enableAxisReferences.cardUid }], + label: 'EnableAxis' + } + ]; + } + + private getDirectEditShortcuts(): VisualSubSelectionShortcuts { + return [ + { + type: VisualShortcutType.Reset, + relatedResetSourceUids: [{ + sourceUid: directEditReferences.fontSliceUid, + }] + }, + { + type: VisualShortcutType.Toggle, + sourceUid: directEditReferences.cardUid, + disabledLabel: 'Delete', + keyboardShortcuts: [{ + key: 'Delete', + nextValue: false, + }] + }, + { + type: VisualShortcutType.Navigate, + destinationUids: [{ cardUid: directEditReferences.cardUid }], + label: 'Direct edit' + } + ]; + } + + private getDirectEditStyles(): SubSelectionStyles { + const fontReference: powerbi.visuals.SliceFormattingModelReference = { + cardUid: directEditReferences.cardUid, + groupUid: directEditReferences.groupUid, + sliceUid: directEditReferences.fontSliceUid, + }; + + const fontColorReference: powerbi.visuals.SliceFormattingModelReference = { + cardUid: directEditReferences.cardUid, + groupUid: directEditReferences.groupUid, + sliceUid: directEditReferences.fontColorSliceUid, + }; + + return { + type: powerbi.visuals.SubSelectionStylesType.Text, + font: { + reference: fontReference, + label: 'font' + }, + fontColor: { + reference: fontColorReference, + label: 'fontColor' + } + }; + } + + public selectionIdCallback(e: Element): ISelectionId { + const elementType: string = d3Select(e).attr(SubSelectableObjectNameAttribute); + + switch (elementType) { + case BarChartObjectNames.ColorSelector: + const datum = d3Select(e).datum(); + return datum.selectionId; + default: + return undefined; } + } - return objectEnumeration; + private creatDirectEditElement(): Element { + const element = document.createElement('div'); + element.setAttribute('class', 'direct-edit'); + return element; } /** @@ -709,13 +861,13 @@ export class BarChart implements IVisual { private handleAverageLineUpdate(height: number, width: number, yScale: ScaleLinear) { const average = this.calculateAverage(); const fontSize = Math.min(height, width) * BarChart.Config.xAxisFontMultiplier; - const chosenColor = this.getColorValue(this.barChartSettings.averageLine.fill); - // If there's no room to place lable above line, place it below + const chosenColor = this.getColorValue(this.formattingSettings.averageLine.fill.value.value); + // If there's no room to place label above line, place it below const labelYOffset = fontSize * ((yScale(average) > fontSize * 1.5) ? -0.5 : 1.5); this.averageLine .style("font-size", fontSize) - .style("display", (this.barChartSettings.averageLine.show) ? "initial" : "none") + .style("display", (this.formattingSettings.averageLine.show.value) ? "initial" : "none") .attr("transform", "translate(0, " + Math.round(yScale(average)) + ")"); this.averageLine.select("#averageLine") @@ -728,7 +880,7 @@ export class BarChart implements IVisual { this.averageLine.select("#averageLineLabel") .text("Average: " + average.toFixed(2)) .attr("transform", "translate(0, " + labelYOffset + ")") - .style("fill", this.barChartSettings.averageLine.showDataLabel ? chosenColor : "none"); + .style("fill", this.formattingSettings.averageLine.showDataLabel.value ? chosenColor : "none"); } private calculateAverage(): number { diff --git a/src/barChartSettingsModel.ts b/src/barChartSettingsModel.ts new file mode 100644 index 0000000..43098d0 --- /dev/null +++ b/src/barChartSettingsModel.ts @@ -0,0 +1,181 @@ +import powerbiVisualsApi from "powerbi-visuals-api"; +import { formattingSettings } from "powerbi-visuals-utils-formattingmodel"; +import { BarChartDataPoint } from "./barChart"; + +import Card = formattingSettings.SimpleCard; +import Model = formattingSettings.Model; + +class EnableAxisCardSettings extends Card { + show = new formattingSettings.ToggleSwitch({ + name: "show", + displayName: undefined, + value: false, + }); + + fill = new formattingSettings.ColorPicker({ + name: "fill", + displayName: "Color", + value: { value: "#000000" } + }); + topLevelSlice = this.show; + name: string = "enableAxis"; + displayName: string = "Enable Axis"; + slices = [this.show, this.fill]; +} + + +class ColorSelectorCardSettings extends Card { + name: string = "colorSelector"; + displayName: string = "Data Colors"; + slices = []; +} + +class GeneralViewCardSettings extends Card { + opacity = new formattingSettings.NumUpDown({ + name: "opacity", + displayName: "Bars Opacity", + value: 100, + options: { + minValue: { + type: powerbiVisualsApi.visuals.ValidatorType.Min, + value: 0, + }, + maxValue: { + type: powerbiVisualsApi.visuals.ValidatorType.Max, + value: 100, + } + } + }); + + showHelpLink = new formattingSettings.ToggleSwitch({ + name: "showHelpLink", + displayName: "Show Help Button", + value: false + }); + + name: string = "generalView"; + displayName: string = "General View"; + helpLinkColor: string = "#80B0E0" + slices = [this.opacity, this.showHelpLink]; +} + +class AverageLineCardSettings extends Card { + show = new formattingSettings.ToggleSwitch({ + name: "show", + displayName: undefined, + value: false, + }); + + fill = new formattingSettings.ColorPicker({ + name: "fill", + displayName: "Color", + value: { value: "#888888" }, + }); + + showDataLabel = new formattingSettings.ToggleSwitch({ + name: "showDataLabel", + displayName: "Data Label", + value: false + }); + + topLevelSlice = this.show; + name: string = "averageLine"; + displayName: string = "Average Line"; + analyticsPane: boolean = true; + slices = [this.show, this.fill, this.showDataLabel]; +} + +class DirectEditSettings extends Card { + displayName = 'Direct Edit'; + name = 'directEditTest'; + private minFontSize: number = 8; + private defaultFontSize: number = 11; + show = new formattingSettings.ToggleSwitch({ + name: "show", + displayName: undefined, + value: true, + }); + + topLevelSlice = this.show + textProperty = new formattingSettings.TextInput({ + displayName: "Text Property", + name: "textProperty", + value: "What is your quest?", + placeholder: "" + }); + + font = new formattingSettings.FontControl({ + name: "font", + displayName: 'Font', + //displayNameKey: "Visual_Font", + fontFamily: new formattingSettings.FontPicker({ + name: "fontFamily", + displayName: "Visual_Font_Family", + value: "Segoe UI, wf_segoe-ui_normal, helvetica, arial, sans-serif" + }), + fontSize: new formattingSettings.NumUpDown({ + name: "fontSize", + displayName: "Visual_Font_Size", + value: this.defaultFontSize, + options: { + minValue: { + type: powerbi.visuals.ValidatorType.Min, + value: this.minFontSize, + } + } + }), + bold: new formattingSettings.ToggleSwitch({ + name: 'bold', + displayName: "Visual_Font_Size", + value: true + }), + italic: new formattingSettings.ToggleSwitch({ + name: 'italic', + displayName: "Visual_Font_Size", + value: true + }), + underline: new formattingSettings.ToggleSwitch({ + name: 'underline', + displayName: "Visual_Font_Size", + value: true + }) + }); + + fontColor = new formattingSettings.ColorPicker({ + name: "fill", + displayName: "Color", + value: { value: "#000000" } + }); + slices = [this.show, this.textProperty, this.font, this.fontColor]; +} + +/** +* BarChart formatting settings model class +*/ +export class BarChartSettingsModel extends Model { + enableAxis = new EnableAxisCardSettings(); + colorSelector = new ColorSelectorCardSettings(); + generalView = new GeneralViewCardSettings(); + averageLine = new AverageLineCardSettings(); + directEditSettings = new DirectEditSettings(); + cards = [this.enableAxis, this.colorSelector, this.generalView, this.averageLine, this.directEditSettings]; + + /** + * populate colorSelector object categories formatting properties + * @param dataPoints + */ + populateColorSelector(dataPoints: BarChartDataPoint[]) { + let slices: formattingSettings.ColorPicker[] = this.colorSelector.slices; + if (dataPoints) { + dataPoints.forEach(dataPoint => { + slices.push(new formattingSettings.ColorPicker({ + name: "fill", + displayName: dataPoint.category, + value: { value: dataPoint.color }, + selector: dataPoint.selectionId.getSelector(), + })); + }); + } + } +} +//"4.7.1", \ No newline at end of file diff --git a/style/visual.less b/style/visual.less index fe05eb9..1cd34eb 100644 --- a/style/visual.less +++ b/style/visual.less @@ -1,10 +1,11 @@ p { font-size: 20px; font-weight: bold; + em { background: yellow; padding: 5px; - + } } @@ -45,4 +46,23 @@ p { top: 50px; font-size: 12pt; right: 15px; +} + +.direct-edit { + position: absolute; + bottom: 60%; + right: 12px; + display: inline-block; + width: 40%; + height: 20%; + border: 2px solid #80B0E0; + border-radius: 20px; + color: #80B0E0; + text-align: center; + font-size: 16px; + padding: 5px; +} + +.hidden { + display: none; } \ No newline at end of file From ca949b694dbfcfca0acf72970ce71a584d8b9da0 Mon Sep 17 00:00:00 2001 From: shafeeqz <58530222+shafeeqz@users.noreply.github.com> Date: Fri, 26 Jan 2024 13:20:36 +0200 Subject: [PATCH 02/10] Update Bar chart to use formattingId --- src/barChart.ts | 242 +++++++++++++++++++++++++++++++----------------- 1 file changed, 157 insertions(+), 85 deletions(-) diff --git a/src/barChart.ts b/src/barChart.ts index 44a4e1d..19f30b3 100644 --- a/src/barChart.ts +++ b/src/barChart.ts @@ -15,7 +15,6 @@ import powerbiVisualsApi from "powerbi-visuals-api"; import { createTooltipServiceWrapper, ITooltipServiceWrapper } from "powerbi-visuals-utils-tooltiputils"; import { FormattingSettingsService } from "powerbi-visuals-utils-formattingmodel"; import { textMeasurementService, valueFormatter } from "powerbi-visuals-utils-formattingutils"; -import { dataViewWildcard } from "powerbi-visuals-utils-dataviewutils"; import { HtmlSubSelectableClass, HtmlSubSelectionHelper, SubSelectableDirectEdit as SubSelectableDirectEditAttr, SubSelectableDisplayNameAttribute, SubSelectableObjectNameAttribute, SubSelectableTypeAttribute } from '../node_modules/powerbi-visuals-utils-onobjectformatting/src'; import { BarChartSettingsModel } from "./barChartSettingsModel"; @@ -48,8 +47,8 @@ import VisualShortcutType = powerbi.visuals.VisualShortcutType; import VisualSubSelectionShortcuts = powerbi.visuals.VisualSubSelectionShortcuts; import VisualTooltipDataItem = powerbi.extensibility.VisualTooltipDataItem; import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions; -import SliceFormattingModelReference = powerbi.visuals.SliceFormattingModelReference import SubSelectionStylesType = powerbi.visuals.SubSelectionStylesType; +import FormattingId = powerbi.visuals.FormattingId; /** @@ -75,47 +74,98 @@ export interface BarChartDataPoint { format?: string; } -interface SliceReferences { +interface References { cardUid?: string; groupUid?: string; - fillSliceUid?: string; - fontSliceUid?: string; - fontColorSliceUid?: string; + fill?: FormattingId; + font?: FormattingId; + fontColor?: FormattingId; + show?: FormattingId; + fontFamily?: FormattingId; + bold?: FormattingId; + italic?: FormattingId; + underline?: FormattingId; + fontSize?: FormattingId; + position?: FormattingId; + textProperty?: FormattingId; } const enum BarChartObjectNames { ArcElement = 'arcElement', ColorSelector = 'colorSelector', EnableAxis = 'enableAxis', - DirectEdit = 'directEditTest' + DirectEdit = 'directEdit' } const DirectEdit: SubSelectableDirectEdit = { reference: { - cardUid: 'Visual-directEditTest-card', - groupUid: 'directEditTest-group', - sliceUid: 'directEditTest-textProperty', + objectName: 'directEdit', + propertyName: 'textProperty' }, style: SubSelectableDirectEditStyle.Outline, }; -const colorSelectorReferences: SliceReferences = { +const colorSelectorReferences: References = { cardUid: 'Visual-colorSelector-card', groupUid: 'colorSelector-group', - fillSliceUid: 'colorSelector-fill' + fill: { + objectName: `${BarChartObjectNames.ColorSelector}`, + propertyName: 'fill' + } }; -const enableAxisReferences: SliceReferences = { +const enableAxisReferences: References = { cardUid: 'Visual-enableAxis-card', groupUid: 'enableAxis-group', - fillSliceUid: 'enableAxis-fill' + fill: { + objectName: `${BarChartObjectNames.EnableAxis}`, + propertyName: 'fill' + }, + show: { + objectName: `${BarChartObjectNames.EnableAxis}`, + propertyName: 'show' + } }; -const directEditReferences: SliceReferences = { - cardUid: 'Visual-directEditTest-card', - groupUid: 'directEditTest-group', - fontSliceUid: 'directEditTest-font', - fontColorSliceUid: 'directEditTest-fontColor' +const directEditReferences: References = { + cardUid: 'Visual-directEdit-card', + groupUid: 'directEdit-group', + fontFamily: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'fontFamily' + }, + bold: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'bold' + }, + italic: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'italic' + }, + underline: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'underline' + }, + fontSize: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'fontSize' + }, + fontColor: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'fontColor' + }, + show: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'show' + }, + position: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'position' + }, + textProperty: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'textProperty' + } }; /** @@ -250,7 +300,6 @@ export class BarChart implements IVisual { private svg: Selection; private tooltipServiceWrapper: ITooltipServiceWrapper; private xAxis: Selection; - private barSelection: Selection; private subSelectionHelper: HtmlSubSelectionHelper; @@ -370,15 +419,18 @@ export class BarChart implements IVisual { this.directEditElement .classed('direct-edit', true) .classed('hidden', !this.formattingSettings.directEditSettings.show.value) - .attr(SubSelectableObjectNameAttribute, 'directEditTest') + .classed(HtmlSubSelectableClass, options.formatMode && this.formattingSettings.directEditSettings.show.value) + .attr(SubSelectableObjectNameAttribute, 'directEdit') .attr(SubSelectableDisplayNameAttribute, 'Direct Edit') .attr(SubSelectableDirectEditAttr, this.visualDirectEditSubSelection) - .classed(HtmlSubSelectableClass, options.formatMode && this.formattingSettings.directEditSettings.show.value) .style('font-family', this.formattingSettings.directEditSettings.font.fontFamily.value) .style('color', this.formattingSettings.directEditSettings.fontColor.value.value) .style('font-style', this.formattingSettings.directEditSettings.font.italic.value ? 'italic' : 'normal') .style('text-decoration', this.formattingSettings.directEditSettings.font.underline.value ? 'underline' : 'none') .style('font-weight', this.formattingSettings.directEditSettings.font.bold.value ? 'bold' : 'normal') + .style('right', this.formattingSettings.directEditSettings.position.value.value === 'Right' ? '12px' : '60px') + .style('background-color', this.formattingSettings.directEditSettings.background.value.value) + .style('font-size', `${this.formattingSettings.directEditSettings.font.fontSize.value}px`) .text(this.formattingSettings.directEditSettings.textProperty.value); this.xAxis @@ -426,14 +478,14 @@ export class BarChart implements IVisual { const opacity: number = this.formattingSettings.generalView.opacity.value / 100; barSelectionMerged + .attr(SubSelectableObjectNameAttribute, 'colorSelector') + .attr(SubSelectableDisplayNameAttribute, (dataPoint: BarChartDataPoint) => this.formattingSettings.colorSelector.slices[dataPoint.index].displayName) + .attr(SubSelectableTypeAttribute, powerbi.visuals.SubSelectionStylesType.Shape) + .classed(HtmlSubSelectableClass, options.formatMode) .attr("width", xScale.bandwidth()) .attr("height", d => height - yScale(d.value)) .attr("y", d => yScale(d.value)) .attr("x", d => xScale(d.category)) - .attr(SubSelectableObjectNameAttribute, 'colorSelector') - .attr(SubSelectableDisplayNameAttribute, d => `colorSelector-${d.index}`) - .attr(SubSelectableTypeAttribute, powerbi.visuals.SubSelectionStylesType.Shape) - .classed(HtmlSubSelectableClass, options.formatMode) .style("fill-opacity", opacity) .style("stroke-opacity", opacity) .style("fill", (dataPoint: BarChartDataPoint) => dataPoint.color) @@ -449,7 +501,7 @@ export class BarChart implements IVisual { barSelectionMerged, this.selectionManager.getSelectionIds() ); - if (this.formatMode) { + if (this.formatMode) {// disabling barSelectionMerged.on('click', null); this.svg.on('click', null); this.svg.on('contextmenu', null); @@ -612,42 +664,28 @@ export class BarChart implements IVisual { return [ { type: VisualShortcutType.Reset, - relatedResetSourceUids: [{ - sourceUid: colorSelectorReferences.fillSliceUid, + relatedResetFormattingIds: [{ + ...colorSelectorReferences.fill, selector - }] + }], }, { type: VisualShortcutType.Navigate, - destinationUids: [{ cardUid: colorSelectorReferences.cardUid }], - label: 'colorlabel' + destinationInfo: { cardUid: colorSelectorReferences.cardUid }, + label: 'Color' } ]; } private getColorSelectorStyles(subSelections: CustomVisualSubSelection[]): SubSelectionStyles { - const cardUid = colorSelectorReferences.cardUid; - const groupUid = colorSelectorReferences.groupUid; - const sliceUid = colorSelectorReferences.fillSliceUid; const selector = subSelections[0].customVisualObjects[0].selectionId?.getSelector(); return { type: SubSelectionStylesType.Shape, fill: { - label: 'Visual_Fill', + label: 'Fill', reference: { - cardUid, - groupUid, - sliceUid, - selector, - }, - }, - color: { - label: 'Visual_Color', - reference: { - cardUid, - groupUid, - sliceUid, - selector, + ...colorSelectorReferences.fill, + selector }, }, }; @@ -658,9 +696,7 @@ export class BarChart implements IVisual { type: SubSelectionStylesType.Shape, fill: { reference: { - cardUid: enableAxisReferences.cardUid, - groupUid: enableAxisReferences.groupUid, - sliceUid: enableAxisReferences.fillSliceUid + ...enableAxisReferences.fill }, label: 'Enable Axis' } @@ -671,23 +707,25 @@ export class BarChart implements IVisual { return [ { type: VisualShortcutType.Reset, - relatedResetSourceUids: [{ - sourceUid: enableAxisReferences.fillSliceUid, - + relatedResetFormattingIds: [{ + ...enableAxisReferences.fill, + }], + excludedResetFormattingIds: [{ + ...enableAxisReferences.show, }] }, { type: VisualShortcutType.Toggle, - sourceUid: enableAxisReferences.cardUid, + relatedToggledFormattingIds: [{ + ...enableAxisReferences.show + }], + ...enableAxisReferences.show, disabledLabel: 'Delete', - keyboardShortcuts: [{ - key: 'Delete', - nextValue: false, - }] + enabledLabel: 'Delete' }, { type: VisualShortcutType.Navigate, - destinationUids: [{ cardUid: enableAxisReferences.cardUid }], + destinationInfo: { cardUid: enableAxisReferences.cardUid }, label: 'EnableAxis' } ]; @@ -697,49 +735,83 @@ export class BarChart implements IVisual { return [ { type: VisualShortcutType.Reset, - relatedResetSourceUids: [{ - sourceUid: directEditReferences.fontSliceUid, - }] + relatedResetFormattingIds: [ + directEditReferences.bold, + directEditReferences.fontFamily, + directEditReferences.fontSize, + directEditReferences.italic, + directEditReferences.underline, + directEditReferences.fontColor, + directEditReferences.textProperty + ] }, { type: VisualShortcutType.Toggle, - sourceUid: directEditReferences.cardUid, + relatedToggledFormattingIds: [{ + ...directEditReferences.show, + }], + ...directEditReferences.show, disabledLabel: 'Delete', - keyboardShortcuts: [{ - key: 'Delete', - nextValue: false, - }] + + }, + { + type: VisualShortcutType.Picker, + ...directEditReferences.position, + label: 'Position' }, { type: VisualShortcutType.Navigate, - destinationUids: [{ cardUid: directEditReferences.cardUid }], + destinationInfo: { cardUid: directEditReferences.cardUid }, label: 'Direct edit' } ]; } private getDirectEditStyles(): SubSelectionStyles { - const fontReference: powerbi.visuals.SliceFormattingModelReference = { - cardUid: directEditReferences.cardUid, - groupUid: directEditReferences.groupUid, - sliceUid: directEditReferences.fontSliceUid, - }; - - const fontColorReference: powerbi.visuals.SliceFormattingModelReference = { - cardUid: directEditReferences.cardUid, - groupUid: directEditReferences.groupUid, - sliceUid: directEditReferences.fontColorSliceUid, - }; - return { type: powerbi.visuals.SubSelectionStylesType.Text, - font: { - reference: fontReference, + fontFamily: { + reference: { + ...directEditReferences.fontFamily + }, + label: 'font' + }, + bold: { + reference: { + ...directEditReferences.bold + }, + label: 'font' + }, + italic: { + reference: { + ...directEditReferences.italic + }, + label: 'font' + }, + underline: { + reference: { + ...directEditReferences.underline + }, + label: 'font' + }, + fontSize: { + reference: { + ...directEditReferences.fontSize + }, label: 'font' }, fontColor: { - reference: fontColorReference, + reference: { + ...directEditReferences.fontColor + }, label: 'fontColor' + }, + background: { + reference: { + objectName: 'directEdit', + propertyName: 'background' + }, + label: 'background' } }; } From dda3b7ba9fb0067b67c0642fb34adb200d44ba9f Mon Sep 17 00:00:00 2001 From: shafeeqz <58530222+shafeeqz@users.noreply.github.com> Date: Fri, 26 Jan 2024 13:25:22 +0200 Subject: [PATCH 03/10] Update barChartSettingsModel.ts --- src/barChartSettingsModel.ts | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/barChartSettingsModel.ts b/src/barChartSettingsModel.ts index 43098d0..ee39fb0 100644 --- a/src/barChartSettingsModel.ts +++ b/src/barChartSettingsModel.ts @@ -87,7 +87,7 @@ class AverageLineCardSettings extends Card { class DirectEditSettings extends Card { displayName = 'Direct Edit'; - name = 'directEditTest'; + name = 'directEdit'; private minFontSize: number = 8; private defaultFontSize: number = 11; show = new formattingSettings.ToggleSwitch({ @@ -96,7 +96,7 @@ class DirectEditSettings extends Card { value: true, }); - topLevelSlice = this.show + topLevelSlice = this.show; textProperty = new formattingSettings.TextInput({ displayName: "Text Property", name: "textProperty", @@ -104,18 +104,23 @@ class DirectEditSettings extends Card { placeholder: "" }); + position = new formattingSettings.ItemDropdown({ + name: 'position', + items: [{ displayName: 'Left', value: 'Left' }, { displayName: 'Right', value: 'Right' }], + value: { displayName: 'Right', value: 'Right' } + }); + font = new formattingSettings.FontControl({ name: "font", displayName: 'Font', - //displayNameKey: "Visual_Font", fontFamily: new formattingSettings.FontPicker({ name: "fontFamily", - displayName: "Visual_Font_Family", + displayName: "Font Family", value: "Segoe UI, wf_segoe-ui_normal, helvetica, arial, sans-serif" }), fontSize: new formattingSettings.NumUpDown({ name: "fontSize", - displayName: "Visual_Font_Size", + displayName: "Font Size", value: this.defaultFontSize, options: { minValue: { @@ -126,27 +131,32 @@ class DirectEditSettings extends Card { }), bold: new formattingSettings.ToggleSwitch({ name: 'bold', - displayName: "Visual_Font_Size", + displayName: "bold", value: true }), italic: new formattingSettings.ToggleSwitch({ name: 'italic', - displayName: "Visual_Font_Size", + displayName: "italic", value: true }), underline: new formattingSettings.ToggleSwitch({ name: 'underline', - displayName: "Visual_Font_Size", + displayName: "underline", value: true }) }); fontColor = new formattingSettings.ColorPicker({ - name: "fill", + name: "fontColor", displayName: "Color", value: { value: "#000000" } }); - slices = [this.show, this.textProperty, this.font, this.fontColor]; + background = new formattingSettings.ColorPicker({ + name: "background", + displayName: "Color", + value: { value: "#FFFFFF" } + }); + slices = [this.show, this.textProperty, this.font, this.fontColor, this.background, this.position]; } /** @@ -178,4 +188,3 @@ export class BarChartSettingsModel extends Model { } } } -//"4.7.1", \ No newline at end of file From 633ae1d0b1a83ba5f4ad8adb074591423c3cbbbd Mon Sep 17 00:00:00 2001 From: shafeeqz <58530222+shafeeqz@users.noreply.github.com> Date: Fri, 26 Jan 2024 13:26:55 +0200 Subject: [PATCH 04/10] Update capabilities.json --- capabilities.json | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/capabilities.json b/capabilities.json index c00d9d7..8599c19 100644 --- a/capabilities.json +++ b/capabilities.json @@ -79,7 +79,7 @@ } } }, - "directEditTest": { + "directEdit": { "properties": { "show": { "displayName": "Show", @@ -109,27 +109,31 @@ }, "bold": { "type": { - "formatting": { - "fontSize": true - } + "bool": true } }, "italic": { "type": { - "formatting": { - "fontSize": true - } + "bool": true } }, "underline": { "type": { - "formatting": { - "fontSize": true + "bool": true + } + }, + "fontColor": { + "displayName": "Font Color", + "type": { + "fill": { + "solid": { + "color": true + } } } }, - "fill": { - "displayName": "Color", + "background": { + "displayName": "Background", "type": { "fill": { "solid": { @@ -137,6 +141,14 @@ } } } + }, + "position": { + "displayName": "Position", + "type": { + "enumeration": [ + { "displayName": "Left", "value": "Left" }, { "displayName": "Right", "value": "Right" } + ] + } } } }, @@ -205,6 +217,8 @@ } } }, + "supportsOnObjectFormatting": true, + "enablePointerEventsFormatMode": true, "tooltips": { "supportedTypes": { "default": true, @@ -216,12 +230,10 @@ "supportEnhancedTooltips": true }, "supportsLandingPage": false, - "supportsOnObjectFormatting": true, - "enablePointerEventsFormatMode": true, "drilldown": { "roles": [ "category" ] }, "privileges": [] -} \ No newline at end of file +} From 5f01bfc7c75c926b35b7d7e9616a2d14b1294412 Mon Sep 17 00:00:00 2001 From: shafeeqz <58530222+shafeeqz@users.noreply.github.com> Date: Fri, 26 Jan 2024 13:28:10 +0200 Subject: [PATCH 05/10] Update package.json --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3e9138e..4e23165 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "d3-selection": "^3.0.0", "eslint": "^8.50.0", "eslint-plugin-powerbi-visuals": "^0.8.1", - "powerbi-visuals-api": "~5.4.0", + "powerbi-visuals-api": "~5.7.0", "powerbi-visuals-tools": "^5.3.0", "powerbi-visuals-utils-dataviewutils": "^6.0.1", "powerbi-visuals-utils-formattingmodel": "6.0.0", @@ -30,6 +30,6 @@ "typescript": "^5.1.6" }, "dependencies": { - "powerbi-visuals-utils-onobjectformatting": "file:../../powerbi-visuals-utils-onobjectformatting/powerbi-visuals-utils-onobjectformatting-1.0.0.tgz" + "powerbi-visuals-utils-onobjectformatting": "file:../../powerbi-visuals-utils-onobjectformatting/powerbi-visuals-utils-onobjectformatting-6.0.0.tgz" } } From 69b0f44bce2c35dbda01b50bb367fe30ac98b648 Mon Sep 17 00:00:00 2001 From: Shafeeq Date: Sun, 25 Feb 2024 10:43:00 +0200 Subject: [PATCH 06/10] use onobjectutils package --- package-lock.json | 101 ++++++++++------------------------------------ package.json | 4 +- src/barChart.ts | 5 ++- 3 files changed, 27 insertions(+), 83 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5ffc026..7cb48ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,7 @@ "name": "visual", "version": "4.0.0", "dependencies": { - "on-object-utils": "file:../../Utils/on-object-utils/on-object-utils-1.0.0.tgz", - "powerbi-visuals-utils-onobjectformatting": "file:../../powerbi-visuals-utils-onobjectformatting/powerbi-visuals-utils-onobjectformatting-1.0.0.tgz" + "powerbi-visuals-utils-onobjectutils": "^6.0.1" }, "devDependencies": { "@types/d3-axis": "^3.0.4", @@ -22,7 +21,7 @@ "d3-selection": "^3.0.0", "eslint": "^8.50.0", "eslint-plugin-powerbi-visuals": "^0.8.1", - "powerbi-visuals-api": "~5.4.0", + "powerbi-visuals-api": "~5.8.0", "powerbi-visuals-tools": "^5.3.0", "powerbi-visuals-utils-dataviewutils": "^6.0.1", "powerbi-visuals-utils-formattingmodel": "6.0.0", @@ -4510,26 +4509,6 @@ "node": ">= 0.8" } }, - "node_modules/on-object-utils": { - "version": "1.0.0", - "resolved": "file:../../Utils/on-object-utils/on-object-utils-1.0.0.tgz", - "integrity": "sha512-rBcLdKDSXVdhLwOeAcdLRT6fVyAsvB6TgafZjurJalr/U05gcc2rD4uzGVX1uEToCvuZEQijC8q5BSKTSC7HeA==", - "license": "ISC", - "dependencies": { - "@types/d3-selection": "^3.0.10", - "d3-selection": "^3.0.0", - "powerbi-visuals-api": "~5.1.0", - "typescript": "^5.3.2" - } - }, - "node_modules/on-object-utils/node_modules/powerbi-visuals-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.1.0.tgz", - "integrity": "sha512-ol+h1gF1VRK3n6/wwXR2YMkQsczHU3aiqmqtPl0/KEHPbCBQon/0vcdOVDXFp5QtYj/Ua+LXegD47x8K9FWCzg==", - "dependencies": { - "semver": "^7.3.5" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4900,10 +4879,9 @@ "dev": true }, "node_modules/powerbi-visuals-api": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.4.0.tgz", - "integrity": "sha512-3T7OCBTd6yQtKFt1T+YgQpWGScHByEhOxncWZlNyPVBJBjL+46/CsJL7T6VXOpD0paAYFFS3DWuZOE/q5smPMg==", - "dev": true, + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.8.0.tgz", + "integrity": "sha512-0rcldFiNPn0HSQ3XGdFzRqFofh/UHn0zcGMtcUWXqJIIL3ekhpdRmTdw/OsT9biEHVnBiim3HIhgHHoGr/se/Q==", "dependencies": { "semver": "^7.3.5" } @@ -5073,23 +5051,14 @@ "powerbi-visuals-utils-typeutils": "^6.0.1" } }, - "node_modules/powerbi-visuals-utils-onobjectformatting": { - "version": "1.0.0", - "resolved": "file:../../powerbi-visuals-utils-onobjectformatting/powerbi-visuals-utils-onobjectformatting-1.0.0.tgz", - "integrity": "sha512-6QeFsdCHs8nETNgItTJGjTiHrlh9t18QzyQaazjjZOpBV6JQReTuKj6jZOertsiotB5I7teiJUssBYhqO5pjVw==", - "license": "MIT", + "node_modules/powerbi-visuals-utils-onobjectutils": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/powerbi-visuals-utils-onobjectutils/-/powerbi-visuals-utils-onobjectutils-6.0.1.tgz", + "integrity": "sha512-D7mlH4/6GkhvcDVxmjfqJ9m5yiuRAyTKepJVoMXXoVTo08XabilRgLSPfyWyVyfMGGONObPqiPhmWVhivo3eJg==", "dependencies": { "@types/d3-selection": "^3.0.10", "d3-selection": "^3.0.0", - "powerbi-visuals-api": "~5.1.0" - } - }, - "node_modules/powerbi-visuals-utils-onobjectformatting/node_modules/powerbi-visuals-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.1.0.tgz", - "integrity": "sha512-ol+h1gF1VRK3n6/wwXR2YMkQsczHU3aiqmqtPl0/KEHPbCBQon/0vcdOVDXFp5QtYj/Ua+LXegD47x8K9FWCzg==", - "dependencies": { - "semver": "^7.3.5" + "powerbi-visuals-api": "~5.8.0" } }, "node_modules/powerbi-visuals-utils-svgutils": { @@ -6242,6 +6211,7 @@ "version": "5.3.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10145,26 +10115,6 @@ "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true }, - "on-object-utils": { - "version": "file:..\\..\\Utils\\on-object-utils\\on-object-utils-1.0.0.tgz", - "integrity": "sha512-rBcLdKDSXVdhLwOeAcdLRT6fVyAsvB6TgafZjurJalr/U05gcc2rD4uzGVX1uEToCvuZEQijC8q5BSKTSC7HeA==", - "requires": { - "@types/d3-selection": "^3.0.10", - "d3-selection": "^3.0.0", - "powerbi-visuals-api": "~5.1.0", - "typescript": "^5.3.2" - }, - "dependencies": { - "powerbi-visuals-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.1.0.tgz", - "integrity": "sha512-ol+h1gF1VRK3n6/wwXR2YMkQsczHU3aiqmqtPl0/KEHPbCBQon/0vcdOVDXFp5QtYj/Ua+LXegD47x8K9FWCzg==", - "requires": { - "semver": "^7.3.5" - } - } - } - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -10426,10 +10376,9 @@ "dev": true }, "powerbi-visuals-api": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.4.0.tgz", - "integrity": "sha512-3T7OCBTd6yQtKFt1T+YgQpWGScHByEhOxncWZlNyPVBJBjL+46/CsJL7T6VXOpD0paAYFFS3DWuZOE/q5smPMg==", - "dev": true, + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.8.0.tgz", + "integrity": "sha512-0rcldFiNPn0HSQ3XGdFzRqFofh/UHn0zcGMtcUWXqJIIL3ekhpdRmTdw/OsT9biEHVnBiim3HIhgHHoGr/se/Q==", "requires": { "semver": "^7.3.5" } @@ -10582,23 +10531,14 @@ "powerbi-visuals-utils-typeutils": "^6.0.1" } }, - "powerbi-visuals-utils-onobjectformatting": { - "version": "file:..\\..\\powerbi-visuals-utils-onobjectformatting\\powerbi-visuals-utils-onobjectformatting-1.0.0.tgz", - "integrity": "sha512-6QeFsdCHs8nETNgItTJGjTiHrlh9t18QzyQaazjjZOpBV6JQReTuKj6jZOertsiotB5I7teiJUssBYhqO5pjVw==", + "powerbi-visuals-utils-onobjectutils": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/powerbi-visuals-utils-onobjectutils/-/powerbi-visuals-utils-onobjectutils-6.0.1.tgz", + "integrity": "sha512-D7mlH4/6GkhvcDVxmjfqJ9m5yiuRAyTKepJVoMXXoVTo08XabilRgLSPfyWyVyfMGGONObPqiPhmWVhivo3eJg==", "requires": { "@types/d3-selection": "^3.0.10", "d3-selection": "^3.0.0", - "powerbi-visuals-api": "~5.1.0" - }, - "dependencies": { - "powerbi-visuals-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/powerbi-visuals-api/-/powerbi-visuals-api-5.1.0.tgz", - "integrity": "sha512-ol+h1gF1VRK3n6/wwXR2YMkQsczHU3aiqmqtPl0/KEHPbCBQon/0vcdOVDXFp5QtYj/Ua+LXegD47x8K9FWCzg==", - "requires": { - "semver": "^7.3.5" - } - } + "powerbi-visuals-api": "~5.8.0" } }, "powerbi-visuals-utils-svgutils": { @@ -11477,7 +11417,8 @@ "typescript": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==" + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true }, "universalify": { "version": "2.0.0", diff --git a/package.json b/package.json index 4e23165..20700eb 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "d3-selection": "^3.0.0", "eslint": "^8.50.0", "eslint-plugin-powerbi-visuals": "^0.8.1", - "powerbi-visuals-api": "~5.7.0", + "powerbi-visuals-api": "~5.8.0", "powerbi-visuals-tools": "^5.3.0", "powerbi-visuals-utils-dataviewutils": "^6.0.1", "powerbi-visuals-utils-formattingmodel": "6.0.0", @@ -30,6 +30,6 @@ "typescript": "^5.1.6" }, "dependencies": { - "powerbi-visuals-utils-onobjectformatting": "file:../../powerbi-visuals-utils-onobjectformatting/powerbi-visuals-utils-onobjectformatting-6.0.0.tgz" + "powerbi-visuals-utils-onobjectutils": "^6.0.1" } } diff --git a/src/barChart.ts b/src/barChart.ts index 19f30b3..1c7fda2 100644 --- a/src/barChart.ts +++ b/src/barChart.ts @@ -15,7 +15,10 @@ import powerbiVisualsApi from "powerbi-visuals-api"; import { createTooltipServiceWrapper, ITooltipServiceWrapper } from "powerbi-visuals-utils-tooltiputils"; import { FormattingSettingsService } from "powerbi-visuals-utils-formattingmodel"; import { textMeasurementService, valueFormatter } from "powerbi-visuals-utils-formattingutils"; -import { HtmlSubSelectableClass, HtmlSubSelectionHelper, SubSelectableDirectEdit as SubSelectableDirectEditAttr, SubSelectableDisplayNameAttribute, SubSelectableObjectNameAttribute, SubSelectableTypeAttribute } from '../node_modules/powerbi-visuals-utils-onobjectformatting/src'; +import { + HtmlSubSelectableClass, HtmlSubSelectionHelper, SubSelectableDirectEdit as SubSelectableDirectEditAttr, + SubSelectableDisplayNameAttribute, SubSelectableObjectNameAttribute, SubSelectableTypeAttribute +} from 'powerbi-visuals-utils-onobjectutils'; import { BarChartSettingsModel } from "./barChartSettingsModel"; import { getLocalizedString } from "./localization/localizationHelper" From 8c9542e352a1cb3b8cb1963a4744405b82aea425 Mon Sep 17 00:00:00 2001 From: Shafeeq Date: Mon, 11 Mar 2024 10:51:55 +0200 Subject: [PATCH 07/10] comments --- src/barChart.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/barChart.ts b/src/barChart.ts index 1c7fda2..28b6a6b 100644 --- a/src/barChart.ts +++ b/src/barChart.ts @@ -515,9 +515,9 @@ export class BarChart implements IVisual { } this.subSelectionHelper.setFormatMode(options.formatMode); - const shouldUpdateSubSelection = options.type & powerbi.VisualUpdateType.Data - || options.type & powerbi.VisualUpdateType.Resize - || options.type & powerbi.VisualUpdateType.FormattingSubSelectionChange; + const shouldUpdateSubSelection = options.type & (powerbi.VisualUpdateType.Data + | powerbi.VisualUpdateType.Resize + | powerbi.VisualUpdateType.FormattingSubSelectionChange); if (this.formatMode && shouldUpdateSubSelection) { this.subSelectionHelper.updateOutlinesFromSubSelections(options.subSelections, true); } @@ -552,7 +552,7 @@ export class BarChart implements IVisual { .then((ids: ISelectionId[]) => { this.syncSelectionState(barSelectionMerged, ids); }); - (event).stopPropagation(); + event.stopPropagation(); } }); } From 90ca3c03ddc88bfdcdf27ab8c73652783dd5a423 Mon Sep 17 00:00:00 2001 From: Shafeeq Date: Mon, 18 Mar 2024 12:12:27 +0200 Subject: [PATCH 08/10] lint fixes and comments --- capabilities.json | 25 ++++--------- package.json | 2 +- pbiviz.json | 2 +- src/barChart.ts | 72 ++++++++++++++++++++---------------- src/barChartSettingsModel.ts | 14 ++++--- 5 files changed, 58 insertions(+), 57 deletions(-) diff --git a/capabilities.json b/capabilities.json index 8599c19..9ec0298 100644 --- a/capabilities.json +++ b/capabilities.json @@ -59,16 +59,13 @@ } }, "enableAxis": { - "displayName": "Enable Axis", "properties": { "show": { - "displayName": "Enable Axis", "type": { "bool": true } }, "fill": { - "displayName": "Color", "type": { "fill": { "solid": { @@ -82,13 +79,11 @@ "directEdit": { "properties": { "show": { - "displayName": "Show", "type": { "bool": true } }, "textProperty": { - "displayName": "Text", "type": { "text": true } @@ -123,7 +118,6 @@ } }, "fontColor": { - "displayName": "Font Color", "type": { "fill": { "solid": { @@ -133,7 +127,6 @@ } }, "background": { - "displayName": "Background", "type": { "fill": { "solid": { @@ -143,20 +136,22 @@ } }, "position": { - "displayName": "Position", "type": { "enumeration": [ - { "displayName": "Left", "value": "Left" }, { "displayName": "Right", "value": "Right" } + { + "value": "Left" + }, + { + "value": "Right" + } ] } } } }, "colorSelector": { - "displayName": "Data Colors", "properties": { "fill": { - "displayName": "Color", "type": { "fill": { "solid": { @@ -168,16 +163,13 @@ } }, "generalView": { - "displayName": "General View", "properties": { "opacity": { - "displayName": "Bars Opacity", "type": { "integer": true } }, "showHelpLink": { - "displayName": "Show Help Button", "type": { "bool": true } @@ -185,7 +177,6 @@ } }, "averageLine": { - "displayName": "Average Line", "objectCategory": 2, "properties": { "show": { @@ -199,7 +190,6 @@ } }, "fill": { - "displayName": "Color", "type": { "fill": { "solid": { @@ -209,7 +199,6 @@ } }, "showDataLabel": { - "displayName": "Data label", "type": { "bool": true } @@ -236,4 +225,4 @@ ] }, "privileges": [] -} +} \ No newline at end of file diff --git a/package.json b/package.json index 20700eb..e68d8b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "visual", - "version": "4.0.0", + "version": "4.1.0.0", "scripts": { "pbiviz": "pbiviz", "start": "pbiviz start", diff --git a/pbiviz.json b/pbiviz.json index f5b6fd4..06ac37d 100644 --- a/pbiviz.json +++ b/pbiviz.json @@ -4,7 +4,7 @@ "displayName": "barChart", "guid": "PBI_CV_9894B302_1DFF_4A96_ABFE_BF8588197166", "visualClassName": "BarChart", - "version": "4.0.0.0", + "version": "4.1.0.0", "description": "Sample bar chart", "supportUrl": "pbicvsupport@microsoft.com", "gitHubUrl": "" diff --git a/src/barChart.ts b/src/barChart.ts index 28b6a6b..f51f0b2 100644 --- a/src/barChart.ts +++ b/src/barChart.ts @@ -43,7 +43,6 @@ import IVisualHost = powerbi.extensibility.visual.IVisualHost; import PrimitiveValue = powerbi.PrimitiveValue; import SubSelectableDirectEdit = powerbi.visuals.SubSelectableDirectEdit; import SubSelectableDirectEditStyle = powerbi.visuals.SubSelectableDirectEditStyle; -import SubSelectionShortcutsKey = powerbi.visuals.SubSelectionShortcutsKey; import SubSelectionStyles = powerbi.visuals.SubSelectionStyles; import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions; import VisualShortcutType = powerbi.visuals.VisualShortcutType; @@ -380,7 +379,7 @@ export class BarChart implements IVisual { this.visualOnObjectFormatting = { getSubSelectionStyles: (subSelections) => this.getSubSelectionStyles(subSelections), - getSubSelectionShortcuts: (subSelections, filter) => this.getSubSelectionShortcuts(subSelections, filter), + getSubSelectionShortcuts: (subSelections) => this.getSubSelectionShortcuts(subSelections), getSubSelectables: (filter) => this.getSubSelectables(filter) }; @@ -419,23 +418,7 @@ export class BarChart implements IVisual { .style("border-color", this.formattingSettings.generalView.helpLinkColor) .style("color", this.formattingSettings.generalView.helpLinkColor); - this.directEditElement - .classed('direct-edit', true) - .classed('hidden', !this.formattingSettings.directEditSettings.show.value) - .classed(HtmlSubSelectableClass, options.formatMode && this.formattingSettings.directEditSettings.show.value) - .attr(SubSelectableObjectNameAttribute, 'directEdit') - .attr(SubSelectableDisplayNameAttribute, 'Direct Edit') - .attr(SubSelectableDirectEditAttr, this.visualDirectEditSubSelection) - .style('font-family', this.formattingSettings.directEditSettings.font.fontFamily.value) - .style('color', this.formattingSettings.directEditSettings.fontColor.value.value) - .style('font-style', this.formattingSettings.directEditSettings.font.italic.value ? 'italic' : 'normal') - .style('text-decoration', this.formattingSettings.directEditSettings.font.underline.value ? 'underline' : 'none') - .style('font-weight', this.formattingSettings.directEditSettings.font.bold.value ? 'bold' : 'normal') - .style('right', this.formattingSettings.directEditSettings.position.value.value === 'Right' ? '12px' : '60px') - .style('background-color', this.formattingSettings.directEditSettings.background.value.value) - .style('font-size', `${this.formattingSettings.directEditSettings.font.fontSize.value}px`) - .text(this.formattingSettings.directEditSettings.textProperty.value); - + this.updateDirectEditElementFormat(); this.xAxis .style("font-size", Math.min(height, width) * BarChart.Config.xAxisFontMultiplier) .style("fill", this.formattingSettings.enableAxis.fill.value.value); @@ -504,14 +487,10 @@ export class BarChart implements IVisual { barSelectionMerged, this.selectionManager.getSelectionIds() ); - if (this.formatMode) {// disabling - barSelectionMerged.on('click', null); - this.svg.on('click', null); - this.svg.on('contextmenu', null); + if (this.formatMode) { + this.removeEventHandlers(barSelectionMerged); } else { - this.handleBarClick(barSelectionMerged); - this.handleClick(barSelectionMerged); - this.handleContextMenu(); + this.addEventHandlers(barSelectionMerged); } this.subSelectionHelper.setFormatMode(options.formatMode); @@ -528,6 +507,36 @@ export class BarChart implements IVisual { this.handleClick(barSelectionMerged); } + private removeEventHandlers(barSelectionMerged: d3Selection) { + barSelectionMerged.on('click', null); + this.svg.on('click', null); + this.svg.on('contextmenu', null); + } + + private addEventHandlers(barSelectionMerged: d3Selection) { + this.handleBarClick(barSelectionMerged); + this.handleClick(barSelectionMerged); + this.handleContextMenu(); + } + + private updateDirectEditElementFormat() { + this.directEditElement + .classed('direct-edit', true) + .classed('hidden', !this.formattingSettings.directEditSettings.show.value) + .classed(HtmlSubSelectableClass, this.formatMode && this.formattingSettings.directEditSettings.show.value) + .attr(SubSelectableObjectNameAttribute, 'directEdit') + .attr(SubSelectableDisplayNameAttribute, 'Direct Edit') + .attr(SubSelectableDirectEditAttr, this.visualDirectEditSubSelection) + .style('font-family', this.formattingSettings.directEditSettings.font.fontFamily.value) + .style('color', this.formattingSettings.directEditSettings.fontColor.value.value) + .style('font-style', this.formattingSettings.directEditSettings.font.italic.value ? 'italic' : 'normal') + .style('text-decoration', this.formattingSettings.directEditSettings.font.underline.value ? 'underline' : 'none') + .style('font-weight', this.formattingSettings.directEditSettings.font.bold.value ? 'bold' : 'normal') + .style('right', this.formattingSettings.directEditSettings.position.value.value === 'Right' ? '12px' : '60px') + .style('background-color', this.formattingSettings.directEditSettings.background.value.value) + .style('font-size', `${this.formattingSettings.directEditSettings.font.fontSize.value}px`) + .text(this.formattingSettings.directEditSettings.textProperty.value); + } private static wordBreak( textNodes: Selection, allowedWidth: number, @@ -645,7 +654,7 @@ export class BarChart implements IVisual { } } } - private getSubSelectionShortcuts(subSelections: CustomVisualSubSelection[], filter: SubSelectionShortcutsKey | undefined): VisualSubSelectionShortcuts | undefined { + private getSubSelectionShortcuts(subSelections: CustomVisualSubSelection[]): VisualSubSelectionShortcuts | undefined { const visualObject = subSelections[0]?.customVisualObjects[0]; if (visualObject) { switch (visualObject.objectName) { @@ -821,14 +830,15 @@ export class BarChart implements IVisual { public selectionIdCallback(e: Element): ISelectionId { const elementType: string = d3Select(e).attr(SubSelectableObjectNameAttribute); + let selectionId: ISelectionId = undefined; switch (elementType) { case BarChartObjectNames.ColorSelector: - const datum = d3Select(e).datum(); - return datum.selectionId; - default: - return undefined; + selectionId = d3Select(e).datum().selectionId; + break; } + + return selectionId; } private creatDirectEditElement(): Element { diff --git a/src/barChartSettingsModel.ts b/src/barChartSettingsModel.ts index ee39fb0..4984840 100644 --- a/src/barChartSettingsModel.ts +++ b/src/barChartSettingsModel.ts @@ -20,7 +20,7 @@ class EnableAxisCardSettings extends Card { topLevelSlice = this.show; name: string = "enableAxis"; displayName: string = "Enable Axis"; - slices = [this.show, this.fill]; + slices = [this.fill]; } @@ -90,6 +90,7 @@ class DirectEditSettings extends Card { name = 'directEdit'; private minFontSize: number = 8; private defaultFontSize: number = 11; + private positionOptions: powerbiVisualsApi.IEnumMember[] = [{ displayName: 'Right', value: 'Right' }, { displayName: 'Left', value: 'Left' }] show = new formattingSettings.ToggleSwitch({ name: "show", displayName: undefined, @@ -106,8 +107,9 @@ class DirectEditSettings extends Card { position = new formattingSettings.ItemDropdown({ name: 'position', - items: [{ displayName: 'Left', value: 'Left' }, { displayName: 'Right', value: 'Right' }], - value: { displayName: 'Right', value: 'Right' } + displayName: 'Position', + items: this.positionOptions, + value: this.positionOptions[0] }); font = new formattingSettings.FontControl({ @@ -153,10 +155,10 @@ class DirectEditSettings extends Card { }); background = new formattingSettings.ColorPicker({ name: "background", - displayName: "Color", + displayName: "Background Color", value: { value: "#FFFFFF" } }); - slices = [this.show, this.textProperty, this.font, this.fontColor, this.background, this.position]; + slices = [this.textProperty, this.font, this.fontColor, this.background, this.position]; } /** @@ -175,7 +177,7 @@ export class BarChartSettingsModel extends Model { * @param dataPoints */ populateColorSelector(dataPoints: BarChartDataPoint[]) { - let slices: formattingSettings.ColorPicker[] = this.colorSelector.slices; + const slices: formattingSettings.ColorPicker[] = this.colorSelector.slices; if (dataPoints) { dataPoints.forEach(dataPoint => { slices.push(new formattingSettings.ColorPicker({ From fec60e7c3fbfc27830b32c4df3dff1e244ef7ce1 Mon Sep 17 00:00:00 2001 From: Shafeeq Date: Mon, 18 Mar 2024 16:51:47 +0200 Subject: [PATCH 09/10] iupdate tutorials --- Tutorial/ColorPalette.md | 5 +- Tutorial/DataBinding.md | 13 +- Tutorial/DataBoundObjects.md | 102 ++++----- Tutorial/ExtensibilityUtils.md | 4 +- Tutorial/ExternalLibraries.md | 2 +- Tutorial/HighContrastSupport.md | 14 +- Tutorial/LaunchURL.md | 20 +- Tutorial/Locale.md | 9 +- Tutorial/OnObject.md | 363 ++++++++++++++++++++++++++++++++ Tutorial/ReportPageTooltips.md | 7 +- Tutorial/Selection.md | 91 +++++--- Tutorial/StaticObjects.md | 254 +++++++++++++++------- Tutorial/Typings.md | 3 +- src/barChart.ts | 6 +- 14 files changed, 692 insertions(+), 201 deletions(-) create mode 100644 Tutorial/OnObject.md diff --git a/Tutorial/ColorPalette.md b/Tutorial/ColorPalette.md index c1f528e..16c1589 100644 --- a/Tutorial/ColorPalette.md +++ b/Tutorial/ColorPalette.md @@ -26,10 +26,11 @@ interface BarChartDataPoint { `colorPalette` is a service that manages the colors used on your visual. An instance of it is available on `IVisualHost`. ## Assigning Color to Data Points -We defined `createSelectorDataPoints` as a construct to convert options `dataView` Bar Chart data points that will be used in visual view. +We defined `createSelectorDataPoints` as a construct to convert options `dataView` to Bar Chart data points that will be used in visual view. Since we iterate through the data points in `createSelectorDataPoints` it is also the ideal place to assign colors. ```typescript + function createSelectorDataPoints(options: VisualUpdateOptions, host: IVisualHost): BarChartDataPoint[] { let barChartDataPoints: BarChartDataPoint[] = [] const dataViews = options.dataViews; @@ -69,4 +70,4 @@ function createSelectorDataPoints(options: VisualUpdateOptions, host: IVisualHos } return barChartDataPoints; } -``` +``` \ No newline at end of file diff --git a/Tutorial/DataBinding.md b/Tutorial/DataBinding.md index 79fad8f..569fc64 100644 --- a/Tutorial/DataBinding.md +++ b/Tutorial/DataBinding.md @@ -57,16 +57,16 @@ Use the internal `name` defined in your dataRoles to reference each field. For more information, see the section about [Data View Mapping](https://github.com/Microsoft/PowerBI-visuals/blob/master/Capabilities/DataViewMappings.md). -## Defining and Using `visualTransform` +## Defining and Using `createSelectorDataPoints` DataView is the structure that PowerBI provides to your visual and it contains the queried data to be visualized. However, DataView provides your data in different forms such as categorical and table forms. In this instance we're building a categorical visual and we will only need the use the categorical property on the DataView. -Defining visualTransform will allow you to convert DataView into a view model your visual will use. +Defining `createSelectorDataPoints` will allow you to convert options dataView into bar chart data points your visual will use. IVisualHost is required because when defining individual data points, you will want to assign colors and selection to them. ```typescript /** - * Function that converts queried data into a view model that will be used by the visual + * Function that converts queried data into bar chart data points that will be used by the visual * * @function * @param {VisualUpdateOptions} options - Contains references to the size of the container @@ -74,9 +74,8 @@ IVisualHost is required because when defining individual data points, you will w * the visual had queried. * @param {IVisualHost} host - Contains references to the host which contains services */ -function visualTransform(options: VisualUpdateOptions, host: IVisualHost): BarChartViewModel { - /*Convert dataView to your viewModel*/ +function createSelectorDataPoints(options: VisualUpdateOptions, host: IVisualHost): BarChartDataPoint[] { + /*Convert dataView to bar chart data points*/ } -``` -See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/commit/3c6e8186436b63bf0cf97d2cdd5dde8aa8d08709) for what was added to visualTransform +``` \ No newline at end of file diff --git a/Tutorial/DataBoundObjects.md b/Tutorial/DataBoundObjects.md index 421cb7e..9ecc0fd 100644 --- a/Tutorial/DataBoundObjects.md +++ b/Tutorial/DataBoundObjects.md @@ -9,16 +9,13 @@ See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/commit/ ## Define Object in Capabilities Similar to static objects, we will define another object in the capabilities `colorSelector` is the internal name that will be referenced in the `dataView`. -`displayName` is the name that will be shown on the property pane. `fill` is a `StructuralObjectValue` and is not associated with a primitive type. ```typescript "colorSelector": { - "displayName": "Data Colors", "properties": { "fill": { - "displayName": "Color", "type": { "fill": { "solid": { @@ -69,74 +66,65 @@ export function getCategoricalObjectValue(category: DataViewCategoryColumn, i See [objectEnumerationUtility.ts](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/blob/master/src/objectEnumerationUtility.ts) for source code. ## Defining Default Color and Retrieving Categorical Object from DataView -Each color is now associated with each category inside `dataView`. We will set each data point to its cooresponding color. +Each color is now associated with each category inside options dataView. We will set each data point to its corresponding color. ```typescript + const strokeWidth: number = getColumnStrokeWidth(colorPalette.isHighContrast); + for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) { - let defaultColor: Fill = { - solid: { - color: colorPalette.getColor(category.values[i]).value - } - } + const color: string = getColumnColorByIndex(category, i, colorPalette); + + const selectionId: ISelectionId = host.createSelectionIdBuilder() + .withCategory(category, i) + .createSelectionId(); barChartDataPoints.push({ - category: category.values[i], + color, + strokeColor, + strokeWidth, + selectionId, value: dataValue.values[i], - color: getCategoricalObjectValue(category, i, 'colorSelector', 'fill', defaultColor).solid.color, - selectionId: host.createSelectionIdBuilder() - .withCategory(category, i) - .createSelectionId() + category: `${category.values[i]}`, }); } ``` -## Populate Property Pane with `enumerateObjectInstances` -`enumerateObjectInstances` is used to populate the property pane with objects. +## Populate Property Pane with `getFormattingModel` +`getFormattingModel` is used to populate the property pane with objects. +For more information [here](https://learn.microsoft.com/en-us/power-bi/developer/visuals/format-pane) + For this instance, we would like a color picker per category we have. Each category be rendered on the property pane. +We will do this by adding a populate method `populateColorSelector` to create corresponding bar chart data points color selector in format pane after building the data points in `update` method. This `populateColorSelector` method iterate through each data point with the associated color. -We will do this by adding an additional case to the switch statement for `colorSelector` and iterate through each data point with the associated color. +Selection is required to associate the color with a data point. +In visual class: +```typescript + public update(options: VisualUpdateOptions) { + this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(BarChartSettingsModel, options.dataViews); + this.barDataPoints = createSelectorDataPoints(options, this.host); + this.formattingSettings.populateColorSelector(this.barDataPoints); -Selection is required to associate the color with a datapoint. + // ... + } +``` +In formatting settings model: ```typescript -/** - * Enumerates through the objects defined in the capabilities and adds the properties to the format pane - * - * @function - * @param {EnumerateVisualObjectInstancesOptions} options - Map of defined objects + /** + * populate colorSelector object categories formatting properties + * @param dataPoints */ -public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstanceEnumeration { - let objectName = options.objectName; - let objectEnumeration: VisualObjectInstance[] = []; - - switch(objectName) { - case 'enableAxis': - objectEnumeration.push({ - objectName: objectName, - properties: { - show: this.barChartSettings.enableAxis.show, - }, - selector: null +populateColorSelector(dataPoints: BarChartDataPoint[]) { + const slices: formattingSettings.ColorPicker[] = this.colorSelector.slices; + if (dataPoints) { + dataPoints.forEach(dataPoint => { + slices.push(new formattingSettings.ColorPicker({ + name: "fill", + displayName: dataPoint.category, + value: { value: dataPoint.color }, + selector: dataPoint.selectionId.getSelector(), + })); }); - break; - case 'colorSelector': - for(let barDataPoint of this.barDataPoints) { - objectEnumeration.push({ - objectName: objectName, - displayName: barDataPoint.category, - properties: { - fill: { - solid: { - color: barDataPoint.color - } - } - }, - selector: barDataPoint.selectionId.getSelector() - }); - } - break; - }; - - return objectEnumeration; -} -``` + } + } +``` \ No newline at end of file diff --git a/Tutorial/ExtensibilityUtils.md b/Tutorial/ExtensibilityUtils.md index 7d095f2..a246b9e 100644 --- a/Tutorial/ExtensibilityUtils.md +++ b/Tutorial/ExtensibilityUtils.md @@ -9,6 +9,8 @@ PowerBI provides several tools that help to cover the main needs to build your o 5. [InteractivityUtils](https://www.npmjs.com/package/powerbi-visuals-utils-interactivityutils) is a set of functions and classes for implementation of cross-selection and cross-filtering for PowerBI custom visuals. 6. [FormattingUtils](https://www.npmjs.com/package/powerbi-visuals-utils-formattingutils) are interfaces for creating PowerBI custom visuals. 7. [SVGUtils](https://www.npmjs.com/package/powerbi-visuals-utils-svgutils) is a tool for SVG manipulations for PowerBI custom visuals. +8. [FormattingModelUtils](https://github.com/microsoft/powerbi-visuals-utils-formattingmodel) is a set of classes, interfaces and method help building format pane easily. +9. [OnObjectUtils](https://github.com/microsoft/powerbi-visuals-utils-onobjectutils) provides an easy way for your Power BI custom visual to emit subselections to Power BI, get and render outlines. ### How to install To install the package you should run the following command in the directory with your current custom visual: @@ -47,4 +49,4 @@ After that user can use all available module methods .call(xAxis); ``` -To get more information about SVGItils package, please check the following [documentation](https://github.com/Microsoft/powerbi-visuals-utils-svgutils/) +To get more information about SVGItils package, please check the following [documentation](https://github.com/Microsoft/powerbi-visuals-utils-svgutils/) \ No newline at end of file diff --git a/Tutorial/ExternalLibraries.md b/Tutorial/ExternalLibraries.md index ab548fa..4e39912 100644 --- a/Tutorial/ExternalLibraries.md +++ b/Tutorial/ExternalLibraries.md @@ -40,4 +40,4 @@ Add the library to your `tsconfig.json` file. } ``` -Refer to [this](Typings.md) if you'd like to add typings for your JS file to get intellisense and compile time safety on them. +Refer to [this](Typings.md) if you'd like to add typings for your JS file to get intellisense and compile time safety on them. \ No newline at end of file diff --git a/Tutorial/HighContrastSupport.md b/Tutorial/HighContrastSupport.md index a1ad392..e9a73e7 100644 --- a/Tutorial/HighContrastSupport.md +++ b/Tutorial/HighContrastSupport.md @@ -65,7 +65,7 @@ In Sample Bar Chart, for example, all bars are drawn with 2 pixels thick foregro ![Sample Bar Chart using *Dark #2* color theme](images/HC_sampleBarChart_dark2.png) ![Sample Bar Chart using *White* color theme](images/HC_sampleBarChart_white.png) -Here is one place in the `visualTransform` function that was changed to support high-contrast, it is called as part of rendering during `update`: +Here is one place in the `createSelectorDataPoints` function that was changed to support high-contrast, it is called as part of rendering during `update`: **before** ```typescript @@ -89,6 +89,11 @@ Here is one place in the `visualTransform` function that was changed to support **after** ```typescript + + const colorPalette: ISandboxExtendedColorPalette = host.colorPalette; + const strokeColor: string = getColumnStrokeColor(colorPalette); + const strokeWidth: number = getColumnStrokeWidth(colorPalette.isHighContrast); + for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) { const color: string = getColumnColorByIndex(category, i, colorPalette); @@ -125,9 +130,4 @@ Here is one place in the `visualTransform` function that was changed to support return getCategoricalObjectValue(category, index, 'colorSelector', 'fill', defaultColor).solid.color; } -``` - - - - - +``` \ No newline at end of file diff --git a/Tutorial/LaunchURL.md b/Tutorial/LaunchURL.md index b004453..0d61fa7 100644 --- a/Tutorial/LaunchURL.md +++ b/Tutorial/LaunchURL.md @@ -1,12 +1,10 @@ # Opening a URL in a new tab/window Launch URL allows opening a new browser tab (or window), by delegating the actual work to Power BI. -See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/commit/2ecc5cf74b9bc6fbf5c03f84c3ab24841b489d4e) for what was added at this step. - Note: custom visuals are hosted in Power BI inside sandboxed iframes, this prevents opening a new browser tab (or window) in "the usual way", e.g. using `window.open('http://some.link.net','_blank')`. ## Usage -Use the `host.launchUrl()` API call, passing your destenation URL as a string argument: +Use the `host.launchUrl()` API call, passing your destination URL as a string argument: ```typescript this.host.launchUrl('http://some.link.net'); @@ -18,7 +16,7 @@ this.host.launchUrl('http://some.link.net'); ## Best practices 1. For most cases, it is best to only open a link as a response to a user's explicit action. Make it easy for the user to understand that clicking the link or button will result in opening a new tab. Triggering a `launchUrl()` call without a user's action, or as a side effect of a different action can be confusing or frustrating for the user. -2. If the link is not crucial for the proper functioning of the visual, it is recommanded to provide the report's author a way to disable and hide the link. This is especially relevant for special Power BI use-cases, such as embedding a report in a 3rd party application or publishing it to the web. +2. If the link is not crucial for the proper functioning of the visual, it is recommended to provide the report's author a way to disable and hide the link. This is especially relevant for special Power BI use-cases, such as embedding a report in a 3rd party application or publishing it to the web. 3. Avoid Triggering a `launchUrl()` call from inside a loop, the visual's `update` function, or any other frequently recurring code. ## Step by step example @@ -51,11 +49,9 @@ A `showHelpLink` boolean static object was added to `capabilities.json` objects "objects": { //... "generalView": { - "displayName": "General View", "properties": //... "showHelpLink": { - "displayName": "Show Help Button", "type": { "bool": true } @@ -69,10 +65,10 @@ A `showHelpLink` boolean static object was added to `capabilities.json` objects And, in the visual's `update` function, the following lines were added: ```typescript - if (settings.generalView.showHelpLink) { - this.helpLinkElement.classList.remove("hidden"); - } else { - this.helpLinkElement.classList.add("hidden"); - } +this.helpLinkElement + .classed("hidden", !this.formattingSettings.generalView.showHelpLink.value) + .style("border-color", this.formattingSettings.generalView.helpLinkColor) + .style("color", this.formattingSettings.generalView.helpLinkColor); ``` -The `hidden` class is defined in visual.less to control the display of the element. + +The `hidden` class is defined in visual.less to control the display of the element. \ No newline at end of file diff --git a/Tutorial/Locale.md b/Tutorial/Locale.md index d60d826..8795447 100644 --- a/Tutorial/Locale.md +++ b/Tutorial/Locale.md @@ -14,7 +14,7 @@ In the sample we display the current locale in the tooltip. Each of these bar charts was created under different locale (English, Basque and Hindi). -The BarChart contructor now has a `locale` member which is instantiated in the constructor with the host `locale` instance. +The BarChart constructor now has a `locale` member which is instantiated in the constructor with the host `locale` instance. ```typescript private locale: string; @@ -22,7 +22,7 @@ The BarChart contructor now has a `locale` member which is instantiated in the c this.locale = options.host.locale; ``` -A `LocalizaionResources` interface was added, which helps in localizing strings. It defines the required string for each locale, and also the 'defaultValue', which will be displayed if the visual wansn't adapted to this locale.
+A `LocalizationResources` interface was added, which helps in localizing strings. It defines the required string for each locale, and also the 'defaultValue', which will be displayed if the visual wasn't adapted to this locale.
`myResources` is an instance of this interface, which holds the localized strings: ```typescript @@ -45,7 +45,7 @@ module powerbi.extensibility.visual { Getting a localized string is easy using `getLocalizedString`. ```typescript /** - * Returns the localized string in the locale transfared using the key that was given to serch the resources + * Returns the localized string in the locale transferred using the key that was given to search the resources * * @param {string} locale - the locale in which PowerBI is currently running * @param {object} key - specify a key for the string you want localized in your visual @@ -68,3 +68,6 @@ private getTooltipData(value: any): VisualTooltipDataItem[] { }]; } ``` + +## Format Pane Localization +For more info on localization [here](https://learn.microsoft.com/power-bi/developer/visuals/localization) \ No newline at end of file diff --git a/Tutorial/OnObject.md b/Tutorial/OnObject.md new file mode 100644 index 0000000..3c40419 --- /dev/null +++ b/Tutorial/OnObject.md @@ -0,0 +1,363 @@ +# Adding OnObject formatting to your Visual +The `IVisual` interface expose `VisualOnObjectFormatting` which we will implement in this tutorial using the `HtmlSubSelectionHelper` and `subSelectionService` exposed on `IVisualHost`. + +```typescript +interface VisualOnObjectFormatting { + getSubSelectionStyles(subSelections: powerbi.visuals.CustomVisualSubSelection[]): powerbi.visuals. SubSelectionStyles | undefined; + getSubSelectionShortcuts(subSelections: powerbi.visuals.CustomVisualSubSelection[], filter: powerbi.visuals.SubSelectionShortcutsKey | undefined): powerbi.visuals.VisualSubSelectionShortcuts | undefined; + getSubSelectables?(filter?: powerbi.visuals.SubSelectionStylesType): powerbi.visuals.CustomVisualSubSelection[] | undefined; + } +``` + +import the `HtmlSubSelectionHelper` and its attributes: +```typescript +import { + HtmlSubSelectableClass, HtmlSubSelectionHelper, SubSelectableDirectEdit as SubSelectableDirectEditAttr, + SubSelectableDisplayNameAttribute, SubSelectableObjectNameAttribute, SubSelectableTypeAttribute +} from 'powerbi-visuals-utils-onobjectutils'; +``` + +To make it easy to use the visual object names let's create an enum containing the visual objects: +```typescript +const enum BarChartObjectNames { + ArcElement = 'arcElement', + ColorSelector = 'colorSelector', + EnableAxis = 'enableAxis', + DirectEdit = 'directEdit' +} +``` + +create a reference interface for the visual objects properties FormattingIds, this will help when implementing the `VisualOnObjectFormatting` methods +```typescript +interface References { + cardUid?: string; + groupUid?: string; + fill?: FormattingId; + font?: FormattingId; + fontColor?: FormattingId; + show?: FormattingId; + fontFamily?: FormattingId; + bold?: FormattingId; + italic?: FormattingId; + underline?: FormattingId; + fontSize?: FormattingId; + position?: FormattingId; + textProperty?: FormattingId; +} +``` + +Create a reference for each visual object you need. + +```typescript +const colorSelectorReferences: References = { + cardUid: 'Visual-colorSelector-card', + groupUid: 'colorSelector-group', + fill: { + objectName: BarChartObjectNames.ColorSelector, + propertyName: 'fill' + } +}; + +const enableAxisReferences: References = { + cardUid: 'Visual-enableAxis-card', + groupUid: 'enableAxis-group', + fill: { + objectName: BarChartObjectNames.EnableAxis, + propertyName: 'fill' + }, + show: { + objectName: BarChartObjectNames.EnableAxis, + propertyName: 'show' + } +}; + +const directEditReferences: References = { + cardUid: 'Visual-directEdit-card', + groupUid: 'directEdit-group', + fontFamily: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'fontFamily' + }, + bold: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'bold' + }, + italic: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'italic' + }, + underline: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'underline' + }, + fontSize: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'fontSize' + }, + fontColor: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'fontColor' + }, + show: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'show' + }, + position: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'position' + }, + textProperty: { + objectName: BarChartObjectNames.DirectEdit, + propertyName: 'textProperty' + } +}; +``` + +implement the `VisualOnObjectFormatting` methods +```typescript + private getSubSelectionStyles(subSelections: CustomVisualSubSelection[]): powerbi.visuals.SubSelectionStyles | undefined { + const visualObject = subSelections[0]?.customVisualObjects[0]; + if (visualObject) { + switch (visualObject.objectName) { + case BarChartObjectNames.ColorSelector: + return this.getColorSelectorStyles(subSelections); + case BarChartObjectNames.EnableAxis: + return this.getEnableAxisStyles(); + case BarChartObjectNames.DirectEdit: + return this.getDirectEditStyles(); + } + } + } + private getSubSelectionShortcuts(subSelections: CustomVisualSubSelection[]): VisualSubSelectionShortcuts | undefined { + const visualObject = subSelections[0]?.customVisualObjects[0]; + if (visualObject) { + switch (visualObject.objectName) { + case BarChartObjectNames.ColorSelector: + return this.getColorSelectorShortcuts(subSelections); + case BarChartObjectNames.EnableAxis: + return this.getEnableAxisShortcuts(); + case BarChartObjectNames.DirectEdit: + return this.getDirectEditShortcuts(); + } + } + } + private getSubSelectables?(filter?: powerbi.visuals.SubSelectionStylesType): CustomVisualSubSelection[] | undefined { + return this.subSelectionHelper.getAllSubSelectables(filter); + } + + private getColorSelectorShortcuts(subSelections: CustomVisualSubSelection[]): VisualSubSelectionShortcuts { + const selector = subSelections[0].customVisualObjects[0].selectionId?.getSelector(); + return [ + { + type: VisualShortcutType.Reset, + relatedResetFormattingIds: [{ + ...colorSelectorReferences.fill, + selector + }], + }, + { + type: VisualShortcutType.Navigate, + destinationInfo: { cardUid: colorSelectorReferences.cardUid }, + label: 'Color' + } + ]; + } + + private getColorSelectorStyles(subSelections: CustomVisualSubSelection[]): SubSelectionStyles { + const selector = subSelections[0].customVisualObjects[0].selectionId?.getSelector(); + return { + type: SubSelectionStylesType.Shape, + fill: { + label: 'Fill', + reference: { + ...colorSelectorReferences.fill, + selector + }, + }, + }; + } + + private getEnableAxisStyles(): SubSelectionStyles { + return { + type: SubSelectionStylesType.Shape, + fill: { + reference: { + ...enableAxisReferences.fill + }, + label: 'Enable Axis' + } + } + } + + private getEnableAxisShortcuts(): VisualSubSelectionShortcuts { + return [ + { + type: VisualShortcutType.Reset, + relatedResetFormattingIds: [{ + ...enableAxisReferences.fill, + }], + excludedResetFormattingIds: [{ + ...enableAxisReferences.show, + }] + }, + { + type: VisualShortcutType.Toggle, + relatedToggledFormattingIds: [{ + ...enableAxisReferences.show + }], + ...enableAxisReferences.show, + disabledLabel: 'Delete', + enabledLabel: 'Delete' + }, + { + type: VisualShortcutType.Navigate, + destinationInfo: { cardUid: enableAxisReferences.cardUid }, + label: 'EnableAxis' + } + ]; + } + + private getDirectEditShortcuts(): VisualSubSelectionShortcuts { + return [ + { + type: VisualShortcutType.Reset, + relatedResetFormattingIds: [ + directEditReferences.bold, + directEditReferences.fontFamily, + directEditReferences.fontSize, + directEditReferences.italic, + directEditReferences.underline, + directEditReferences.fontColor, + directEditReferences.textProperty + ] + }, + { + type: VisualShortcutType.Toggle, + relatedToggledFormattingIds: [{ + ...directEditReferences.show, + }], + ...directEditReferences.show, + disabledLabel: 'Delete', + + }, + { + type: VisualShortcutType.Picker, + ...directEditReferences.position, + label: 'Position' + }, + { + type: VisualShortcutType.Navigate, + destinationInfo: { cardUid: directEditReferences.cardUid }, + label: 'Direct edit' + } + ]; + } + + private getDirectEditStyles(): SubSelectionStyles { + return { + type: powerbi.visuals.SubSelectionStylesType.Text, + fontFamily: { + reference: { + ...directEditReferences.fontFamily + }, + label: 'font' + }, + bold: { + reference: { + ...directEditReferences.bold + }, + label: 'font' + }, + italic: { + reference: { + ...directEditReferences.italic + }, + label: 'font' + }, + underline: { + reference: { + ...directEditReferences.underline + }, + label: 'font' + }, + fontSize: { + reference: { + ...directEditReferences.fontSize + }, + label: 'font' + }, + fontColor: { + reference: { + ...directEditReferences.fontColor + }, + label: 'fontColor' + }, + background: { + reference: { + objectName: 'directEdit', + propertyName: 'background' + }, + label: 'background' + } + }; + } +``` + +in the constuctor create the `HtmlSubSelectionHelper` and provide the get methods in the `visualOnObjectFormatting` +```typescript + this.subSelectionHelper = HtmlSubSelectionHelper.createHtmlSubselectionHelper({ + hostElement: options.element, + subSelectionService: options.host.subSelectionService, + selectionIdCallback: (e) => this.selectionIdCallback(e), + }); + + this.visualOnObjectFormatting = { + getSubSelectionStyles: (subSelections) => this.getSubSelectionStyles(subSelections), + getSubSelectionShortcuts: (subSelections) => this.getSubSelectionShortcuts(subSelections), + getSubSelectables: (filter) => this.getSubSelectables(filter) + }; +``` + +In the visual update: +Add `HtmlSubSelectionHelper` attributes to the relevant element and set their format in the visual update, for example for the `colorSelector` +```typescript + barSelectionMerged + .attr(SubSelectableObjectNameAttribute, 'colorSelector') + .attr(SubSelectableDisplayNameAttribute, (dataPoint: BarChartDataPoint) => this.formattingSettings.colorSelector.slices[dataPoint.index].displayName) + .attr(SubSelectableTypeAttribute, powerbi.visuals.SubSelectionStylesType.Shape) + .classed(HtmlSubSelectableClass, options.formatMode) + .attr("width", xScale.bandwidth()) + .attr("height", d => height - yScale(d.value)) + .attr("y", d => yScale(d.value)) + .attr("x", d => xScale(d.category)) + .style("fill-opacity", opacity) + .style("stroke-opacity", opacity) + .style("fill", (dataPoint: BarChartDataPoint) => dataPoint.color) + .style("stroke", (dataPoint: BarChartDataPoint) => dataPoint.strokeColor) + .style("stroke-width", (dataPoint: BarChartDataPoint) => `${dataPoint.strokeWidth}px`); +``` + +set the formatMode for the `HtmlSubSelectionHelper` +```typescript + this.subSelectionHelper.setFormatMode(options.formatMode); +``` + + +disable data interactivity when the visual in formatMode +```typescript + if (this.formatMode) { + this.removeEventHandlers(barSelectionMerged); + } else { + this.addEventHandlers(barSelectionMerged); + } +``` + +When a subselection is sub-selected we will get it in the update, use `HtmlSubSelectionHelper` to render the subselection outlines +```typescript + const shouldUpdateSubSelection = options.type & (powerbi.VisualUpdateType.Data + | powerbi.VisualUpdateType.Resize + | powerbi.VisualUpdateType.FormattingSubSelectionChange); + if (this.formatMode && shouldUpdateSubSelection) { + this.subSelectionHelper.updateOutlinesFromSubSelections(options.subSelections, true); + } +``` \ No newline at end of file diff --git a/Tutorial/ReportPageTooltips.md b/Tutorial/ReportPageTooltips.md index 4bc775b..0a8d4b6 100644 --- a/Tutorial/ReportPageTooltips.md +++ b/Tutorial/ReportPageTooltips.md @@ -30,15 +30,14 @@ To support displaying report page tooltips, add "tooltips" definition to capabil `roles` optional. Once defined, instructs what data roles will be bound to the selected tooltip option in fields well. -For more information, see the Report Page Tooltips usage guidlines [Report Page Tooltips](https://powerbi.microsoft.com/en-us/blog/power-bi-desktop-march-2018-feature-summary/#tooltips). +For more information, see the Report Page Tooltips usage guidelines [Report Page Tooltips](https://powerbi.microsoft.com/en-us/blog/power-bi-desktop-march-2018-feature-summary/#tooltips). ## Applying report page tooltips For displaying the report page tooltip, upon calling ITooltipService.Show(options: TooltipShowOptions) or ITooltipService.Move(options: TooltipMoveOptions), the PowerBI host will consume the selectionId ('identities' property of 'options' argument above). -Therefore, the SelectionId should represent the selected data (category, series, etc) of the item you hovered above to be retreived by the tooltip. +Therefore, the SelectionId should represent the selected data (category, series, etc) of the item you hovered above to be retrieved by the tooltip. See more on building SelectionId under [Adding Selection and Interactions with Other Visuals](https://github.com/Microsoft/PowerBI-visuals/blob/master/Tutorial/Selection.md) Example of sending the selectionId to tooltip display calls: -![](images/ApplyReportPageTooltip.png) - +![](images/ApplyReportPageTooltip.png) \ No newline at end of file diff --git a/Tutorial/Selection.md b/Tutorial/Selection.md index cef5461..9e65aa2 100644 --- a/Tutorial/Selection.md +++ b/Tutorial/Selection.md @@ -11,22 +11,26 @@ Since each data point is unique, selection must be added to each data point. Add * Interface for BarChart data points. * * @interface - * @property {number} value - Data value for point. + * @property {PrimitiveValue} value - Data value for point. * @property {string} category - Corresponding category of data value. * @property {string} color - Color corresponding to data point. + * @property {string} strokeColor - Stroke color for data point column. + * @property {number} strokeWidth - Stroke width for data point column. * @property {ISelectionId} selectionId - Id assigned to data point for cross filtering * and visual interaction. */ -interface BarChartDataPoint { - value: number; +export interface BarChartDataPoint { + value: PrimitiveValue; category: string; color: string; + strokeColor: string; + strokeWidth: number; selectionId: ISelectionId; -}; +} ``` ## Assigning Selection Ids to Each Data Point -Since we iterate through the data points in `visualTransform` it is also the ideal place to create your selection ids. +Since we iterate through the data points in `createSelectorDataPoints` it is also the ideal place to create your selection ids. The host variable is a `IVisualHost`, which contains services that the visual may use such as color and selection builder. Use the selection builder factory method on `IVisualHost` to create a new selection id. @@ -35,16 +39,23 @@ Since we're making selection only based on the category, we only need to define **NOTE**: A new selection builder must be created per data point. ```typescript -for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) { - barChartDataPoints.push({ - category: category.values[i], - value: dataValue.values[i], - color: colorPalette.getColor(category.values[i]).value, - selectionId: host.createSelectionIdBuilder() + + for (let i = 0, len = Math.max(category.values.length, dataValue.values.length); i < len; i++) { + const color: string = getColumnColorByIndex(category, i, colorPalette); + + const selectionId: ISelectionId = host.createSelectionIdBuilder() .withCategory(category, i) - .createSelectionId() - }); -} + .createSelectionId(); + + barChartDataPoints.push({ + color, + strokeColor, + strokeWidth, + selectionId, + value: dataValue.values[i], + category: `${category.values[i]}`, + }); + } ``` For more information, see the section about using [Selection Id Builder](https://github.com/Microsoft/PowerBI-visuals/blob/master/Visual/Selection.md#creating-selection-ids-selectionidbuilder). @@ -54,25 +65,47 @@ Each bar on the bar chart can be interacted with once a selection id is assigned The bar chart will listen to click events. Use the selection manager factory method on `IVisualHost` to create selection manager. This allow for cross filtering and clearing selections. +Call `syncSelectionState` using selectionManager selectionIds and barSelection: ```typescript -let selectionManager = this.selectionManager; - -//This must be an anonymous function instead of a lambda because -//d3 uses 'this' as the reference to the element that was clicked. -bars.on('click', function(d) { - selectionManager.select(d.selectionId).then((ids: ISelectionId[]) => { - bars.attr({ - 'fill-opacity': ids.length > 0 ? BarChart.Config.transparentOpacity : BarChart.Config.solidOpacity - }); +this.selectionManager = options.host.createSelectionManager(); +this.selectionManager.registerOnSelectCallback(() => { + this.syncSelectionState(this.barSelection, this.selectionManager.getSelectionIds()); +}); - d3.select(this).attr({ - 'fill-opacity': BarChart.Config.solidOpacity +// .... + +private syncSelectionState( + selection: Selection, + selectionIds: ISelectionId[] + ): void { + if (!selection || !selectionIds) { + return; + } + + if (!selectionIds.length) { + const opacity: number = this.formattingSettings.generalView.opacity.value / 100; + selection + .style("fill-opacity", opacity) + .style("stroke-opacity", opacity); + return; + } + + const self: this = this; + + selection.each(function (barDataPoint: BarChartDataPoint) { + const isSelected: boolean = self.isSelectionIdInArray(selectionIds, barDataPoint.selectionId); + + const opacity: number = isSelected + ? BarChart.Config.solidOpacity + : BarChart.Config.transparentOpacity; + + d3Select(this) + .style("fill-opacity", opacity) + .style("stroke-opacity", opacity); }); - }); + } - (d3.event).stopPropagation(); -}); ``` -For more information, see the section about using [Selection Manager](https://github.com/Microsoft/PowerBI-visuals/blob/master/Visual/Selection.md#managing-selection-selectionmanager). +For more information, see the section about using [Selection Manager](https://github.com/Microsoft/PowerBI-visuals/blob/master/Visual/Selection.md#managing-selection-selectionmanager). \ No newline at end of file diff --git a/Tutorial/StaticObjects.md b/Tutorial/StaticObjects.md index a1097ef..f180b67 100644 --- a/Tutorial/StaticObjects.md +++ b/Tutorial/StaticObjects.md @@ -6,26 +6,18 @@ Objects can be toggled on the property pane. ![](images/PropertyPane.png) -See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/commit/7602bb5c34aca97f02ea8e713f841a4ce19929c7) for what was added at this step. - ## Define Object in Capabilities Define an objects property inside your capabilities. This defines the object you plan to display in the property pane. `enableAxis` is the internal name that will be referenced in the `dataView`. -`displayName` is the name that will be shown on the property pane. - `bool` is a `PrimitiveValue` and is typically used with static objects such as text boxes or switches. -**NOTE**: `show` is a special property on `properties`. It enables the switch on the actual object. Since show is a switch, it is typed as a `bool`. - ![](images/ObjectShowProperty.png) ```typescript "objects": { "enableAxis": { - "displayName": "Enable Axis", "properties": { "show": { - "displayName": "Enable Axis", "type": { "bool": true } } } @@ -33,37 +25,153 @@ Define an objects property inside your capabilities. This defines the object you } ``` -For more information, see the section about using [Objects](https://github.com/Microsoft/PowerBI-visuals/blob/master/Capabilities/Objects.md). +For more information, see the section about using [Objects](https://learn.microsoft.com/en-us/power-bi/developer/visuals/capabilities#objects-define-property-pane-options). -## Defining Property Settings +## Defining Formatting Pane Settings Model Although this is optional, it is best to localize most settings onto a single object so that all settings can be easily referenced. ```typescript -/** - * Interface for BarCharts viewmodel. - * - * @interface - * @property {BarChartDataPoint[]} dataPoints - Set of data points the visual will render. - * @property {number} dataMax - Maximum data value in the set of data points. - * @property {BarChartSettings} settings - Object property settings - */ -interface BarChartViewModel { - dataPoints: BarChartDataPoint[]; - dataMax: number; - settings: BarChartSettings; -}; + + private formattingSettingsService: FormattingSettingsService; + private formattingSettings: BarChartSettingsModel; + + + constructor(options: VisualConstructorOptions) { + // ... + + const localizationManager = this.host.createLocalizationManager(); + this.formattingSettingsService = new FormattingSettingsService(localizationManager); + + // ... + } + + + public update(options: VisualUpdateOptions) { + this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(BarChartSettingsModel, options.dataViews); + this.barDataPoints = createSelectorDataPoints(options, this.host); + this.formattingSettings.populateColorSelector(this.barDataPoints); + // ... + } +``` + +Formatting pane settings model : +```typescript + +import Card = formattingSettings.Card; +import Model = formattingSettings.Model; + +class EnableAxisCardSettings extends Card { + show = new formattingSettings.ToggleSwitch({ + name: "show", + displayName: undefined, + value: false, + topLevelToggle: true + }); + + fill = new formattingSettings.ColorPicker({ + name: "fill", + displayName: "Color", + value: { value: "#000000" } + }); + + name: string = "enableAxis"; + displayName: string = "Enable Axis"; + slices = [this.show, this.fill]; +} + + +class ColorSelectorCardSettings extends Card { + name: string = "colorSelector"; + displayName: string = "Data Colors"; + slices = []; +} + +class GeneralViewCardSettings extends Card { + opacity = new formattingSettings.NumUpDown({ + name: "opacity", + displayName: "Bars Opacity", + value: 100, + options: { + minValue: { + type: powerbiVisualsApi.visuals.ValidatorType.Min, + value: 0, + }, + maxValue: { + type: powerbiVisualsApi.visuals.ValidatorType.Max, + value: 100, + } + } + }); + + showHelpLink = new formattingSettings.ToggleSwitch({ + name: "showHelpLink", + displayName: "Show Help Button", + value: false + }); + + name: string = "generalView"; + displayName: string = "General View"; + helpLinkColor: string = "#80B0E0" + slices = [this.opacity, this.showHelpLink]; +} + +class AverageLineCardSettings extends Card { + show = new formattingSettings.ToggleSwitch({ + name: "show", + displayName: undefined, + value: false, + topLevelToggle: true + }); + + fill = new formattingSettings.ColorPicker({ + name: "fill", + displayName: "Color", + value: { value: "#888888" }, + }); + + showDataLabel = new formattingSettings.ToggleSwitch({ + name: "showDataLabel", + displayName: "Data Label", + value: false + }); + + name: string = "averageLine"; + displayName: string = "Average Line"; + analyticsPane: boolean = true; + slices = [this.show, this.fill, this.showDataLabel]; +} /** - * Interface for BarChart settings. - * - * @interface - * @property {{show:boolean}} enableAxis - Object property that allows axis to be enabled. - */ -interface BarChartSettings { - enableAxis: { - show: boolean; - }; +* BarChart formatting settings model class +*/ +export class BarChartSettingsModel extends Model { + enableAxis = new EnableAxisCardSettings(); + colorSelector = new ColorSelectorCardSettings(); + generalView = new GeneralViewCardSettings(); + averageLine = new AverageLineCardSettings(); + cards = [this.enableAxis, this.colorSelector, this.generalView, this.averageLine]; + + /** + * populate colorSelector object categories formatting properties + * @param dataPoints + */ + populateColorSelector(dataPoints: BarChartDataPoint[]) { + let slices = this.colorSelector.slices; + if (dataPoints) { + dataPoints.forEach(dataPoint => { + slices.push(new formattingSettings.ColorPicker({ + name: "fill", + displayName: dataPoint.category, + value: { value: dataPoint.color }, + selector: dataViewWildcard.createDataViewWildcardSelector(dataViewWildcard.DataViewWildcardMatchingOption.InstancesAndTotals), + altConstantSelector: dataPoint.selectionId.getSelector(), + instanceKind: powerbiVisualsApi.VisualEnumerationInstanceKinds.ConstantOrRule + })); + }); + } + } } + ``` ## Defining and Using Object Enumeration Utility Object property values are available as metadata on the `dataView`. However, there is currently no service to help retrieve these properties. @@ -95,65 +203,65 @@ export function getValue(objects: DataViewObjects, objectName: string, proper } ``` -See [objectEnumerationUtility.ts](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/blob/master/src/objectEnumerationUtility.ts) for source code. - ## Retrieving Property Values from DataView -`visualTransform` is the ideal place to manipulate the visual's viewmodel. We will continue this pattern and retrieve the object properties from the `dataView`. +`createSelectorDataPoints` is the ideal place to manipulate the visual's data points. We will continue this pattern and retrieve the object properties from the `dataView`. -Define the default state of the property and use getValue to retrieve the property from the `dataView`. +Define the default state of the property: ```typescript -let defaultSettings: BarChartSettings = { - enableAxis: { - show: false, - } -}; -let barChartSettings: BarChartSettings = { - enableAxis: { - show: getValue(objects, 'enableAxis', 'show', defaultSettings.enableAxis.show), - } +class EnableAxisCardSettings extends Card { + show = new formattingSettings.ToggleSwitch({ + name: "show", + displayName: undefined, + value: false, + topLevelToggle: true + }); + + fill = new formattingSettings.ColorPicker({ + name: "fill", + displayName: "Color", + value: { value: "#000000" } + }); + + name: string = "enableAxis"; + displayName: string = "Enable Axis"; + slices = [this.show, this.fill]; } ``` -## Populate Property Pane with `enumerateObjectInstances` -`enumerateObjectInstances` is an optional method on `IVisual`. Its purpose is to enumerate through all objects and to place them within the property pane. -Each object will be called with `enumerateObjectInstances`. The object's name will be available on `EnumerateVisualObjectInstancesOptions`. +And `formattingSettings` object will get the right value from `dataView` or default value if it wasn't customized in `populateFormattingSettingsModel` method: +```typescript + public update(options: VisualUpdateOptions) { + this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(BarChartSettingsModel, options.dataViews); + this.barDataPoints = createSelectorDataPoints(options, this.host); + this.formattingSettings.populateColorSelector(this.barDataPoints); + + // ... + } +``` -For each object, define the property with its current state. +## Populate Property Pane with `getFormattingModel` +`getFormattingModel` is an optional method on `IVisual`. It returns properties pane formatting model content hierarchies, properties and latest formatting values, Then place them within the property pane properties pane. This method is called once every time we open properties pane or when the user edit any format property. +It can be built with the help of `formattingSettingsService` by calling method `buildFormattingModel`, Where it takes `formattingSettings` and convert it to PBI required `FormattingModel`/ ```typescript -/** - * Enumerates through the objects defined in the capabilities and adds the properties to the format pane - * - * @function - * @param {EnumerateVisualObjectInstancesOptions} options - Map of defined objects - */ -public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstanceEnumeration { - let objectName = options.objectName; - let objectEnumeration: VisualObjectInstance[] = []; - - switch(objectName) { - case 'enableAxis': - objectEnumeration.push({ - objectName: objectName, - properties: { - show: this.barChartSettings.enableAxis.show, - }, - selector: null - }); - }; - return objectEnumeration; -} + /** + * Returns properties pane formatting model content hierarchies, properties and latest formatting values, Then populate properties pane. + * This method is called once every time we open properties pane or when the user edit any format property. + */ + public getFormattingModel(): powerbiVisualsApi.visuals.FormattingModel { + return this.formattingSettingsService.buildFormattingModel(this.formattingSettings); + } ``` ## Control Property Logic in Update Once an object has been added to the property pane, each toggle will trigger an update. Add specific object logic in `if` blocks. ```typescript -if(settings.enableAxis.show) { + if (this.formattingSettings.enableAxis.show.value) { let margins = BarChart.Config.margins; height -= margins.bottom; } - ``` + ``` \ No newline at end of file diff --git a/Tutorial/Typings.md b/Tutorial/Typings.md index cb2b956..75690fb 100644 --- a/Tutorial/Typings.md +++ b/Tutorial/Typings.md @@ -1,8 +1,7 @@ # Installing Typings for d3 Installing typings will give you access to d3 types so you can utilize typescript types. -See [commit](https://github.com/Microsoft/PowerBI-visuals-sampleBarChart/commit/2bb0f64718864a27e7d4b9c5b1d35d267bba6202) for what was added at this step. -For a more indepth details about typings, visit their repo. [Typings Documentation](https://github.com/typings/typings) +For a more in depth details about typings, visit their repo. [Typings Documentation](https://github.com/typings/typings) ## Install Typings CLI In order to use typings in your project, you must first install typings to your computer. This is a one time installation. diff --git a/src/barChart.ts b/src/barChart.ts index f51f0b2..40ee050 100644 --- a/src/barChart.ts +++ b/src/barChart.ts @@ -111,7 +111,7 @@ const colorSelectorReferences: References = { cardUid: 'Visual-colorSelector-card', groupUid: 'colorSelector-group', fill: { - objectName: `${BarChartObjectNames.ColorSelector}`, + objectName: BarChartObjectNames.ColorSelector, propertyName: 'fill' } }; @@ -120,11 +120,11 @@ const enableAxisReferences: References = { cardUid: 'Visual-enableAxis-card', groupUid: 'enableAxis-group', fill: { - objectName: `${BarChartObjectNames.EnableAxis}`, + objectName: BarChartObjectNames.EnableAxis, propertyName: 'fill' }, show: { - objectName: `${BarChartObjectNames.EnableAxis}`, + objectName: BarChartObjectNames.EnableAxis, propertyName: 'show' } }; From 4b00515eb71b3079392f1e93bbd5da84da695985 Mon Sep 17 00:00:00 2001 From: Shafeeq Date: Mon, 18 Mar 2024 16:54:28 +0200 Subject: [PATCH 10/10] update onobject tutorial --- Tutorial/OnObject.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Tutorial/OnObject.md b/Tutorial/OnObject.md index 3c40419..8593398 100644 --- a/Tutorial/OnObject.md +++ b/Tutorial/OnObject.md @@ -114,6 +114,7 @@ const directEditReferences: References = { ``` implement the `VisualOnObjectFormatting` methods +Note: When providing a selector, make sure that it is the same selector as provided for the formatting model. ```typescript private getSubSelectionStyles(subSelections: CustomVisualSubSelection[]): powerbi.visuals.SubSelectionStyles | undefined { const visualObject = subSelections[0]?.customVisualObjects[0];