Forum Discussion
d3 v4 and selectionManager
- 8 years ago
It seems d3v4 handles selections in a different they in comparison to d3v3.
We'd recommend to take a look at this fixed version.
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
We'd recommned to ask developer of d3 or d3 types about this issue.
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
- az24518 years agoResolver I
Alright, i have found out how d3 selections work:
private chartSelection: d3.Selection<d3.BaseType, ChartDataPoint, d3.BaseType, any>; private svg: d3.Selection<SVGElement, {}, HTMLElement, any>; private g: d3.Selection<SVGElement, {}, HTMLElement, any>;But the problem seems to be something else because the syncSelectionState(): void
dont work (no Errors are shown). That means i can not click on a specific datapoint.
It also seems to be that by installing the newest version of d3 ([email protected] @types/[email protected]) it also installed a different version of typescript (there is are new typescript folder in my node_modules). So the syntax changed a bit.
//For e.g. instead of this.svg.attr({ width: width, height: height }); //I now have to write it like this: this.svg .attr('width', width) .attr('height', height);However, the selectionIds actually exist for each datapoint (I can for e.g. change the color of each datapoint over formatting options)
this.datapoint.selectionId.getSelector()
I cant understand why the selectionManager wont work, where it should be working now.
Here is my whole code for download: MyGoogleDrive
Is there someone who is also using d3 v4 and managed to get selectionManager working?
I would be very thankful!
- v-viig8 years agoCommunity Champion
It seems d3v4 handles selections in a different they in comparison to d3v3.
We'd recommend to take a look at this fixed version.
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
- az24518 years agoResolver I
Hi Ignat,
works fine for me.
Thank you very much!
For everyone who has the same issue follow these steps:
1. STEP: Change the selection datatype to the new d3 v4 format to something like this:
private chartSelection: d3.Selection<d3.BaseType, ChartDataPoint, d3.BaseType, any>; // Needed to display datapoints private svg: d3.Selection<SVGElement, {}, HTMLElement, any>; // SVG-Element (Container) private g: d3.Selection<SVGElement, {}, HTMLElement, any>; // SVG-Element (group 'g')2. STEP: Add <SVGElement> when calling the constructor:
constructor(options: VisualConstructorOptions) { this.host = options.host; this.selectionManager = options.host.createSelectionManager(); this.selectionManager.registerOnSelectCallback(() => { this.syncSelectionState(this.chartSelection, this.selectionManager.getSelectionIds() as ISelectionId[]); }); this.svg = d3.select(options.element).append<SVGElement>('svg'); this.g = this.svg.append<SVGElement>('g'); }3. STEP: When creating the datapoints, you have to add the d3 event directly to it. That means if your code look something similar like this:
// Create a SVG-Element (datapoints) this.chartSelection = this.g .append('g') .selectAll('.dot') .data(viewModel.dataPoints); this.chartSelection .enter() .append('circle') .attr('r', 5) .merge(this.chartSelection) .classed('dot', true) .attr('cx', d => x(<number>d.gesamtKosten)) .attr('cy', d => y(<number>d.anzahlKostenstellen)) .attr('fill', d => d.color); this.syncSelectionState( this.chartSelection, this.selectionManager.getSelectionIds() as ISelectionId[] ); this.chartSelection.on('click', (d) => { // Allow selection only if the visual is rendered in a view that supports interactivity (e.g. Report) if (this.host.allowInteractions) { const isCrtlPressed: boolean = (d3.event as MouseEvent).ctrlKey; this.selectionManager .select(d.selectionId, isCrtlPressed) .then((ids: ISelectionId[]) => { this.syncSelectionState(this.chartSelection, ids); }); (<Event>d3.event).stopPropagation(); } }); this.chartSelection .exit() .remove(); // Clear selection when clicking outside a dot this.svg.on('click', (d) => { if (this.host.allowInteractions) { this.selectionManager .clear() .then(() => { this.syncSelectionState(this.chartSelection, []); }); } });Change it to this:
// Create a SVG-Element (datapoints) this.chartSelection = this.g .append('g') .selectAll('.dot') .data(viewModel.dataPoints); this.chartSelection .enter() .append('circle') .on('click', (d) => { // Allow selection only if the visual is rendered in a view that supports interactivity (e.g. Report) if (this.host.allowInteractions) { const isCrtlPressed: boolean = (d3.event as MouseEvent).ctrlKey; this.selectionManager .select(d.selectionId, isCrtlPressed) .then((ids: ISelectionId[]) => { this.syncSelectionState(this.g.selectAll(".dot"), ids); }); (<Event>d3.event).stopPropagation(); } }) .attr('r', 5) .merge(this.chartSelection) .classed('dot', true) .attr('cx', d => x(<number>d.gesamtKosten)) .attr('cy', d => y(<number>d.anzahlKostenstellen)) .attr('fill', d => d.color);
this.syncSelectionState( this.g.selectAll(".dot"), this.selectionManager.getSelectionIds() as ISelectionId[] ); this.chartSelection .exit() .remove(); // Clear selection when clicking outside a dot this.svg.on('click', (d) => { if (this.host.allowInteractions) { this.selectionManager .clear() .then(() => { this.syncSelectionState(this.chartSelection, []); }); } });4. STEP: Edit the syncSelectionState():
private syncSelectionState( selection: d3.Selection<d3.BaseType, any, d3.BaseType, any>, selectionIds: ISelectionId[] ): void { ... }I hope this helps!