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
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!
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!