Get certified in Microsoft Fabric—for free! For a limited time, the Microsoft Fabric Community team will be offering free DP-600 exam vouchers. Prepare now
Hello everyone!
I developed a custom visual and I want to add tooltips. I have installed the package like described in the Microsoft documentation. If I want to add a mouse event with the tooltips to the dots I get this error:
Here is my code, if I forgot an import statement or something else is totally wrong, I am happy to know about 🙂
Thank you already in advance 😄
/*
* Power BI Visual CLI
*
* Copyright (c) Microsoft CorporationAll rights reserved.
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the ""Software""), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
'use strict';
import 'core-js/stable';
import 'regenerator-runtime/runtime'; /* Right here */
import '../style/visual.less';
import './../style/visual.less';
import powerbi from 'powerbi-visuals-api';
import VisualConstructorOptions = powerbi.extensibility.visual.VisualConstructorOptions;
import VisualUpdateOptions = powerbi.extensibility.visual.VisualUpdateOptions;
import IVisual = powerbi.extensibility.visual.IVisual;
import EnumerateVisualObjectInstancesOptions = powerbi.EnumerateVisualObjectInstancesOptions;
import VisualObjectInstance = powerbi.VisualObjectInstance;
import DataView = powerbi.DataView;
import VisualObjectInstanceEnumerationObject = powerbi.VisualObjectInstanceEnumerationObject;
import IVisualHost = powerbi.extensibility.visual.IVisualHost;
import ISandboxExtendedColorPalette = powerbi.extensibility.ISandboxExtendedColorPalette;
import { VisualSettings } from './settings';
import { valueFormatter } from "powerbi-visuals-utils-formattingutils";
import { createTooltipServiceWrapper } from "powerbi-visuals-utils-tooltiputils";
import VisualTooltipDataItem = powerbi.extensibility.VisualTooltipDataItem;
import ITooltipService = powerbi.extensibility.ITooltipService;
import * as d3 from 'd3';
import { DateTimeUnit } from 'powerbi-visuals-utils-formattingutils/lib/src/formattingService/iFormattingService';
// Build Interface for Data Structure
interface ILineChartRow {
milestone: string,
report_date: Date,
vor_ende: Date,
tooltip: VisualTooltipDataItem[];
}
// Interface for diagonale
interface IDiagonal {
begin: Date
end: Date
}
export class Visual implements IVisual {
private target: HTMLElement;
private settings: VisualSettings;
private container: d3.Selection<HTMLDivElement, any, HTMLDivElement, any>; // private container: d3.Selection<any, any, any, any>;???
private svg: d3.Selection<SVGElement, any, any, any>
constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options);
this.target = options.element;
/** Create the chart container when the visual loads */
this.container = d3.select(this.target)
.append('div')
.attr('id', 'my_dataviz');
createTooltipServiceWrapper(
options.host.tooltipService,
options.element
)
}
public update(options: VisualUpdateOptions) {
console.log('Visual update', options);
this.settings = Visual.parseSettings(options && options.dataViews && options.dataViews[0]);
/** Clear down existing plot */
this.container.selectAll('*').remove();
/** Test 1: Data view has both fields added */
let dataViews = options.dataViews;
console.log('Test 1: Valid data view...');
if (!dataViews
|| !dataViews[0]
|| !dataViews[0].table
|| !dataViews[0].table.rows
|| !dataViews[0].table.columns
|| !dataViews[0].metadata
) {
console.log('Test 1 FAILED. No data to draw table.');
return;
}
let table = dataViews[0].table
//
// Map Data in JSON Structure
let data: ILineChartRow[] = table.rows.map(
(cat, idx) => (
{
milestone: <string>table.rows[idx][0],
report_date: <Date>table.rows[idx][1],
vor_ende: <Date>table.rows[idx][2],
tooltip: [{
displayName: "Milestone",
value: `${table.rows[idx][0]}`
}]
}
)
);
// Format Dates
let parseDate = d3.timeParse("%d.%m.%Y")
data.forEach(function(d: any){
d.report_date = parseDate(d.report_date),
d.vor_ende = parseDate(d.vor_ende)
})
// Create groups for every milestone
let sumstat = d3.nest<ILineChartRow>()
.key(d => d.milestone)
.entries(data)
// Check the result
console.log(sumstat)
// Add Project Begin and and from formatting pane
let diagonale: IDiagonal = {
begin: parseDate(this.settings.dataPoint.projektStart),
end: parseDate(this.settings.dataPoint.projektEnd)
}
// Set Dimensions
let margin = {top: 10, right: 30, bottom: 30, left: 60},
width = options.viewport.width - margin.left - margin.right,
height = options.viewport.height - margin.top - margin.bottom;
// Append the svg object to the body of the page
var svg = this.container
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform',
'translate(' + margin.left + ',' + margin.top + ')');
// Set Minimum and Maximum Values for the axes
/* let minDate_report_date = d3.min(data, function(d){ return d.report_date})
let maxDate_report_date = d3.max(data, function(d){ return d.report_date}) */
// Set Minimum and Maximum for the report date
let minDate_report_date = parseDate(this.settings.dataPoint.projektStart)
let maxDate_report_date = parseDate(this.settings.dataPoint.projektEnd)
// Define x position
let x = d3.scaleTime()
.domain([minDate_report_date,maxDate_report_date])
.range([0,width]);
// Define y0 position
let y0 = d3.scaleTime()
.domain([minDate_report_date,maxDate_report_date])
.range([height,0])
// Define y1 position
let y1 = d3.scaleTime()
.domain([minDate_report_date,maxDate_report_date])
.range([height,0])
// Add diagonal Line first so it is behind the dots
/* svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "darkgrey")
.attr("stroke-width", 1.5)
.attr("d", d3.line<ILineChartRow>()
.x(function(d) {return x(d.report_date)})
.y(function(d) { return y1(d.report_date)})) */
svg.append("line")
.attr("y1", y1(minDate_report_date))
.attr("y2", y1(maxDate_report_date))
.attr("x1", x(minDate_report_date))
.attr("x2", x(maxDate_report_date))
.style("stroke", "darkgrey")
.attr("stroke-width", 1.5)
// Add Milestone lines
svg.selectAll(".line")
.data(sumstat)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke", this.settings.dataPoint.fillLine)
.attr("stroke-width", this.settings.dataPoint.thickness)
.attr("d", function(d){
return d3.line<ILineChartRow>()
.x(function(d) { return x(d.report_date); })
.y(function(d) { return y0(d.vor_ende); })
(d.values)
})
// Add Milestone Dots
svg.append('g')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) { return x(d.report_date); } )
.attr("cy", function (d) { return y0(d.vor_ende); } )
.attr("r", this.settings.dataPoint.thickness * 1.15)
.style("fill", this.settings.dataPoint.fillLine)
// HERE OCCURS THE ERROR
.on("mouseover", (d) => {
let mouse = d3.mouse(this.svg.node())
let x = mouse[0]
let y = mouse[]
})
// Add rectangle to hide something
svg.append("rect")
.attr("x", 0 - margin.left)
.attr("y", 0)
.attr("width", margin.left)
.attr("height", options.viewport.height)
.attr("fill", "white")
// Add X axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add Y0 axis
svg.append("g")
.call(d3.axisLeft(y0))
// Add Y1 axis
svg.append("g")
.attr("transform", "translate( " + width + ", 0 )")
.call(d3.axisRight(y1) // Remove the axis ticks
.ticks(0))
.call(g => g.select(".domain")
.remove()) // Remove the axis itself
// Loop iterates through sumstat object and places for every first Item of "Vorr_Ende" a textfield
// As text is the i version of the key of the sumstat object used
console.log("this is my sumstat *-*: ", sumstat)
// Labels placed next to y axis
/* for ( let i = 0; i < Object.keys(sumstat).length; i++) {
svg.append("g").selectAll("text")
.data(sumstat)
.enter()
.append("text")
.attr("x", 10)
.attr("y", y1(sumstat[i].values[0].vor_ende)-2)
.attr("font-size", 10)
.style("fill", "darkgrey")
.text(sumstat[i].key)
}
*/
// Labels placed at the end of the lines
for ( let i = 0; i < Object.keys(sumstat).length; i++) {
svg.append("g").selectAll("text")
.data(sumstat)
.enter()
.append("text")
.attr("x", x(sumstat[i].values[Object.keys(sumstat[i].values).length - 1].report_date) + 8)
.attr("y", y1(sumstat[i].values[Object.keys(sumstat[i].values).length - 1].vor_ende) + 3)
.attr("font-size", this.settings.dataPoint.radius) // gets infos from the settings.ts file
.style("fill", this.settings.dataPoint.fillLabel)
.text(sumstat[i].key)
}
}
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);
}
}
Solved! Go to Solution.
Hi @Anonymous
Here is an example code to add tooltips to custom visual. Try it and compare it with your codes.
For reference: Sample code
...
private renderTooltip(selection: Selection<Line | Task | MilestonePath>): void {
this.tooltipServiceWrapper.addTooltip(
selection,
(tooltipEvent: TooltipEventArgs<TooltipEnabledDataPoint>) => {
return tooltipEvent.data.tooltipInfo;
});
}
...
Here is a post with similar requirement like yours.
For reference:
Custom Visual Tooltip Data Option
Best Regards,
Rico Zhou
If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.
Hi @Anonymous
Here is an example code to add tooltips to custom visual. Try it and compare it with your codes.
For reference: Sample code
...
private renderTooltip(selection: Selection<Line | Task | MilestonePath>): void {
this.tooltipServiceWrapper.addTooltip(
selection,
(tooltipEvent: TooltipEventArgs<TooltipEnabledDataPoint>) => {
return tooltipEvent.data.tooltipInfo;
});
}
...
Here is a post with similar requirement like yours.
For reference:
Custom Visual Tooltip Data Option
Best Regards,
Rico Zhou
If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.
Check out the October 2024 Power BI update to learn about new features.
Learn from experts, get hands-on experience, and win awesome prizes.
User | Count |
---|---|
19 | |
6 | |
3 | |
3 | |
3 |