Forum Discussion
Sliding legend
Hi Anonymous,
I've re-done the above in 2.3 for you. The process is closer to the install guide but there are still some issues in getting it to work. Here's the run-down:
Make sure that if you're running pbiviz start, then you've stopped it prior to installation as you'll get inconsistent results after package installation.
Package Installation
I had to downgrade until I could find one that will work. 1.7.0 will run, but colour seemed to stop working after 1.5, so run the following command to import:
npm i [email protected]
The installed packages have a dependency on d3, which it does install, but make sure that the typings are installed for it:
npm i @types/[email protected] --save-dev
To confirm, after instantiating a new visual and installing packages, my package.json looks like this, so you could just copy/paste and then run npm i to sync:
{
"name": "visual",
"dependencies": {
"powerbi-visuals-utils-chartutils": "^1.5.1",
"powerbi-visuals-utils-dataviewutils": "1.2.0"
},
"devDependencies": {
"@types/d3": "^3.5.42"
}
}tsconfig.json
Add the following to the files key in tsconfig.json before settings.ts:
"node_modules/powerbi-visuals-utils-formattingutils/lib/index.d.ts",
"node_modules/powerbi-visuals-utils-interactivityutils/lib/index.d.ts",
"node_modules/powerbi-visuals-utils-svgutils/lib/index.d.ts",
"node_modules/powerbi-visuals-utils-typeutils/lib/index.d.ts",
"node_modules/powerbi-visuals-utils-chartutils/lib/index.d.ts",The files key looks like this in mine:
"files": [
".api/v2.5.0/PowerBI-visuals.d.ts",
"node_modules/powerbi-visuals-utils-dataviewutils/lib/index.d.ts",
"node_modules/powerbi-visuals-utils-formattingutils/lib/index.d.ts",
"node_modules/powerbi-visuals-utils-interactivityutils/lib/index.d.ts",
"node_modules/powerbi-visuals-utils-svgutils/lib/index.d.ts",
"node_modules/powerbi-visuals-utils-typeutils/lib/index.d.ts",
"node_modules/powerbi-visuals-utils-chartutils/lib/index.d.ts",
"src/settings.ts",
"src/visual.ts"
]pbiviz.json
Add the following to the externalJS key in pbiviz.json:
"node_modules/d3/d3.min.js",
"node_modules/powerbi-visuals-utils-typeutils/lib/index.js",
"node_modules/powerbi-visuals-utils-svgutils/lib/index.js",
"node_modules/powerbi-visuals-utils-formattingutils/lib/index.js",
"node_modules/powerbi-visuals-utils-interactivityutils/lib/index.js",
"node_modules/powerbi-visuals-utils-chartutils/lib/index.js"The externalJS key looks like this in mine:
"externalJS": [
"node_modules/powerbi-visuals-utils-dataviewutils/lib/index.js",
"node_modules/d3/d3.min.js",
"node_modules/powerbi-visuals-utils-typeutils/lib/index.js",
"node_modules/powerbi-visuals-utils-svgutils/lib/index.js",
"node_modules/powerbi-visuals-utils-formattingutils/lib/index.js",
"node_modules/powerbi-visuals-utils-interactivityutils/lib/index.js",
"node_modules/powerbi-visuals-utils-chartutils/lib/index.js"
]visual.less
It shouldn't matter for this scenario, but to mirror the installation guide, make sure the following are present at the top of visual.less:
@import (less) "node_modules/powerbi-visuals-utils-interactivityutils/lib/index.css"; @import (less) "node_modules/powerbi-visuals-utils-chartutils/lib/index.css";
visual.ts
The solution in the previous post is largely unchanged, except for:
- The way dependencies are imported, e.g.:
import createLegend = powerbi.extensibility.utils.chart.legend.createLegend; import ILegend = powerbi.extensibility.utils.chart.legend.ILegend; import Legend = powerbi.extensibility.utils.chart.legend; import LegendData = powerbi.extensibility.utils.chart.legend.LegendData; import LegendIcon = powerbi.extensibility.utils.chart.legend.LegendIcon; import LegendPosition = powerbi.extensibility.utils.chart.legend.LegendPosition; import LegendDataPoint = powerbi.extensibility.utils.chart.legend.LegendDataPoint; - LegendDataPoint doesn't use markerShape as a property and this is icon in this version, so double-check this part of the code if you're amending your local version (the compiler will error if not correct), e.g.:
{ label: <string>c, color: this.host.colorPalette.getColor(<string>c).value, identity: this.host.createSelectionIdBuilder() .withCategory(categoryRole, i) .createSelectionId(), selected: false, icon: LegendIcon.Circle }
Again just to be sure, here's the full visual.ts:
/** powerbi.extensibility.utils.chart.legend */
import createLegend = powerbi.extensibility.utils.chart.legend.createLegend;
import ILegend = powerbi.extensibility.utils.chart.legend.ILegend;
import Legend = powerbi.extensibility.utils.chart.legend;
import LegendData = powerbi.extensibility.utils.chart.legend.LegendData;
import LegendIcon = powerbi.extensibility.utils.chart.legend.LegendIcon;
import LegendPosition = powerbi.extensibility.utils.chart.legend.LegendPosition;
import LegendDataPoint = powerbi.extensibility.utils.chart.legend.LegendDataPoint;
module powerbi.extensibility.visual {
"use strict";
export class Visual implements IVisual {
private target: HTMLElement;
private settings: VisualSettings;
private legend: ILegend;
private host: IVisualHost;
constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options);
this.target = options.element;
/** Assign visual host */
this.host = options.host;
/** Reserve element for legend */
this.legend = createLegend(
this.target,
false,
null,
true, /* scrollable */
LegendPosition.Top
);
}
public update(options: VisualUpdateOptions) {
this.settings = Visual.parseSettings(options && options.dataViews && options.dataViews[0]);
console.log('Visual update', options);
/** THIS ASSUMES THAT YOUR DATA VIEW WORKS, SO THERE'S NO ERROR HANDLING. YOU WILL AT LEAST
* NEED A VALUE IN THE CATEGORY DATA ROLE TO CONTINUE */
let categoryRole = options.dataViews[0].categorical.categories[0];
/** We're now going to create an array of LegendDataPoint objects to feed into our drawLegend
* method below.
* We're arbitrarily assigning a colour from the host's palette (theme) as it's required. You
* might want to sub this out with your own from your view model */
let myLegendDataPoints: LegendDataPoint[] = categoryRole.values.map(
(c, i) => (
{
label: <string>c,
color: this.host.colorPalette.getColor(<string>c).value,
identity: this.host.createSelectionIdBuilder()
.withCategory(categoryRole, i)
.createSelectionId(),
selected: false,
icon: LegendIcon.Circle
}
)
);
/** This actually draws the legend; note that although font settings aren't required, it will look
* 'wrong' if they're not supplied */
this.legend.drawLegend(
{
title: 'Test Legend',
fontSize: 10,
dataPoints: myLegendDataPoints
},
options.viewport
);
}
private static parseSettings(dataView: DataView): VisualSettings {
return VisualSettings.parse(dataView) as VisualSettings;
}
/**
* This function gets called for each of the objects defined in the capabilities files and allows you to select which of the
* objects and properties you want to expose to the users in the property pane.
*
*/
public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstance[] | VisualObjectInstanceEnumerationObject {
return VisualSettings.enumerateObjectInstances(this.settings || VisualSettings.getDefault(), options);
}
}
}At this point you can run pbiviz start and this will work as for the v3 example above.
Good luck!
Daniel
dm-p Daniel,
Thanks for detailed answer! It was very helpful.
I have some questions regarding it. I added it to my line chart, which has categorical dataview mapping, and can I pass to legend grouping of categorical data view? I tried using this:
let categoryRole = options.dataViews[0].categorical.values.grouped();
But it gave me error.
Also, I don't want to use selection id, if I leave it empty, I get error.
And finally, even though scrollable parameter is true, I can't scroll:
When I click on arrow, it doesn't work.
Regards,
Yerkhan
- dm-p7 years agoSuper User
Hi Anonymous,
I mentioned in my earlier post that you will need to have a selection ID for each entry, otherwise the legend utility will not work. Unfortunately for your case you cannot provide a null value here so will need to provide something valid. It's highly likely that this is causing your legend to break.
Daniel
- Anonymous7 years agoNot applicable
Hi dm-p ,
Got it regarding selection id. How does regular line chart works? It has date as axis, category as grouping for data, and legend is built based on category. I wanted to recreate it, but with cumulative values.
Regards,
Yerkhan
- dm-p7 years agoSuper User
Hi Anonymous,
I'm not entirely sure I follow - you can manage cumulative measures with the core line chart and DAX. Is there a specific feature you're trying to manage in your custom visual?
Thanks,
Daniel
- Anonymous6 years agoNot applicable
dm-p ,
I can't use DAX since I'm using live connection to OLAP cube. I wanted to recreate line chart, but make cumulative calculations inside of visual. However, by legend doesn't work, as I mentioned before.
Regards,
Yerkhan