Earn the coveted Fabric Analytics Engineer certification. 100% off your exam for a limited time only!
I'm creating a custom visual which requires doughnut chart to be displayed over a map. To start with I'm trying to replicate this.
http://bl.ocks.org/d3noob/9267535
It has circles over a leaflet map. I got the leaflet map working but D3 part doesn't work. Please help me with this. If I get the circles on the map I can later replace them with doughnuts.
Visual.ts
module powerbi.extensibility.visual { export interface Data{ lat: number; lng: number; latlng: {}; status: string[]; itemCnt: number[]; } export class Visual implements IVisual { private target: HTMLElement; private divMap: HTMLElement; private divTable: HTMLElement; private map: L.Map; private basemap: L.TileLayer; private layer: L.TileLayer; constructor(options: VisualConstructorOptions) { console.log('Visual constructor', options); this.target = options.element; this.divMap = document.createElement("div"); this.divMap.id = "map"; this.divMap.style.height = "100%"; this.divMap.style.width = "100%"; options.element.appendChild(this.divMap); var L = typeof L !== 'undefined' ? L : window['L']; this.map = L.map('map'); this.map.setView([-41.28,174.77], 11); var mapLink = '<a href="http://openstreetmap.org">OpenStreetMap</a>'; this.layer = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© ' + mapLink + ' Contributors', maxZoom: 18, }); this.map.addLayer(this.layer); } public update(options: VisualUpdateOptions) { //update map size this.divMap.style.height = options.viewport.height.toString() + "px"; this.divMap.style.width = options.viewport.width.toString() + "px"; var svg = d3.select("#map").select("svg"), g = svg.append("g"); var data: Data[] = [ {lat:-41.28, lng:174.77, latlng:{}, status:['Under','Over','Normal'], itemCnt: [30,40,50]}, {lat:-41.29, lng:174.76, latlng:{}, status:['Under','Over','Normal'], itemCnt: [30,30,60]}, {lat:-41.23, lng:174.79, latlng:{}, status:['Under','Over','Normal'], itemCnt: [30,70,10]} ]; data.forEach(function(d) { d.latlng = new L.LatLng(<number>d.lat, <number>d.lng); }) var circle= g.selectAll("circle") .data(data) .enter().append("circle") .style("stroke", "black") .style("opacity", .6) .style("fill", "red") .attr("r", 20) this.map.on("viewreset", update); update(); function update() { circle.attr("transform", function(d) { return "translate("+ this.map.latLngToLayerPoint(new L.LatLng(d.lat, d.lng)).x +","+ this.map.latLngToLayerPoint(new L.LatLng(d.lat, d.lng)).y +")"; } ) } } } }
Visual.less
@import (less) "node_modules/leaflet/dist/leaflet.css";
Package.JSON
{ "name": "visual", "version": "1.1", "dependencies": { "@types/d3": "^3.5.40", "d3": "^3.5.17", "geojson": "^0.5.0", "leaflet": "^1.3.1", "powerbi-visuals-utils-dataviewutils": "1.2.0" }, "devDependencies": { "typescript": "^2.6.2" } }
pbiviz.JSON
{ "visual": { "name": "customMap", "displayName": "Custom Map", "guid": "custommap5A89ADFB5F694F71AB6D00C94383BB2B", "visualClassName": "Visual", "version": "1.0.0", "description": "", "supportUrl": "", "gitHubUrl": "" }, "apiVersion": "1.10.0", "author": { "name": "", "email": "" }, "assets": { "icon": "assets/icon.png" }, "externalJS": [ "node_modules/powerbi-visuals-utils-dataviewutils/lib/index.js", "node_modules/d3/d3.min.js", "node_modules/leaflet/dist/leaflet.js" ], "style": "style/visual.less", "capabilities": "capabilities.json", "dependencies": "dependencies.json", "stringResources": [] }
Solved! Go to Solution.
We replied with the fixed version of your code.
Could you please post the fixed code here if you are ok with sharing?
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
Thanks, @v-viig. You fix works. Here is the fixed visual.ts.
module powerbi.extensibility.visual { export interface Data { lat: number; lng: number; latlng: {}; status: string[]; itemCnt: number[]; } var L = typeof L !== 'undefined' ? L : window['L']; export class Visual implements IVisual { private target: HTMLElement; private divMap: HTMLElement; private divTable: HTMLElement; private map: L.Map; private basemap: L.TileLayer; private layer: L.TileLayer; constructor(options: VisualConstructorOptions) { console.log('Visual constructor', options); this.target = options.element; this.divMap = document.createElement("div"); this.divMap.id = "map"; this.divMap.style.height = "100%"; this.divMap.style.width = "100%"; options.element.appendChild(this.divMap); this.map = L.map('map'); this.map.setView([-41.28, 174.77], 11); var mapLink = '<a href="http://openstreetmap.org">OpenStreetMap</a>'; this.layer = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© ' + mapLink + ' Contributors', maxZoom: 18, }); this.map.addLayer(this.layer); L.svg().addTo(this.map); } public update(options: VisualUpdateOptions) { debugger; //update map size this.divMap.style.height = options.viewport.height.toString() + "px"; this.divMap.style.width = options.viewport.width.toString() + "px"; var svg = d3.select("#map").select("svg"), g = svg.append("g"); var data: Data[] = [ { lat: -41.28, lng: 174.77, latlng: {}, status: ['Under', 'Over', 'Normal'], itemCnt: [30, 40, 50] }, { lat: -41.29, lng: 174.76, latlng: {}, status: ['Under', 'Over', 'Normal'], itemCnt: [30, 30, 60] }, { lat: -41.23, lng: 174.79, latlng: {}, status: ['Under', 'Over', 'Normal'], itemCnt: [30, 70, 10] } ]; data.forEach(function (d) { d.latlng = new L.LatLng(<number>d.lat, <number>d.lng); }) var circle = g.selectAll("circle") .data(data) .enter().append("circle") .style("stroke", "black") .style("opacity", .6) .style("fill", "red") .attr("r", 20) const map = this.map; function update() { circle.attr("transform", function (d) { return "translate(" + map.latLngToLayerPoint(d.latlng as any).x + "," + map.latLngToLayerPoint(d.latlng as any).y + ")"; } ) } this.map.on("viewreset", update);
this.map.on("zoom", update); update(); } } }
What exactly issue have you faced? Can you sahre source code as a zip file?
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
I'm trying to create D3 circles on a leaflet map for a custom visual. I'm able to get the map but the D3 circles are not working. I have sent you my code.
We replied with the fixed version of your code.
Could you please post the fixed code here if you are ok with sharing?
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
Thanks, @v-viig. You fix works. Here is the fixed visual.ts.
module powerbi.extensibility.visual { export interface Data { lat: number; lng: number; latlng: {}; status: string[]; itemCnt: number[]; } var L = typeof L !== 'undefined' ? L : window['L']; export class Visual implements IVisual { private target: HTMLElement; private divMap: HTMLElement; private divTable: HTMLElement; private map: L.Map; private basemap: L.TileLayer; private layer: L.TileLayer; constructor(options: VisualConstructorOptions) { console.log('Visual constructor', options); this.target = options.element; this.divMap = document.createElement("div"); this.divMap.id = "map"; this.divMap.style.height = "100%"; this.divMap.style.width = "100%"; options.element.appendChild(this.divMap); this.map = L.map('map'); this.map.setView([-41.28, 174.77], 11); var mapLink = '<a href="http://openstreetmap.org">OpenStreetMap</a>'; this.layer = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© ' + mapLink + ' Contributors', maxZoom: 18, }); this.map.addLayer(this.layer); L.svg().addTo(this.map); } public update(options: VisualUpdateOptions) { debugger; //update map size this.divMap.style.height = options.viewport.height.toString() + "px"; this.divMap.style.width = options.viewport.width.toString() + "px"; var svg = d3.select("#map").select("svg"), g = svg.append("g"); var data: Data[] = [ { lat: -41.28, lng: 174.77, latlng: {}, status: ['Under', 'Over', 'Normal'], itemCnt: [30, 40, 50] }, { lat: -41.29, lng: 174.76, latlng: {}, status: ['Under', 'Over', 'Normal'], itemCnt: [30, 30, 60] }, { lat: -41.23, lng: 174.79, latlng: {}, status: ['Under', 'Over', 'Normal'], itemCnt: [30, 70, 10] } ]; data.forEach(function (d) { d.latlng = new L.LatLng(<number>d.lat, <number>d.lng); }) var circle = g.selectAll("circle") .data(data) .enter().append("circle") .style("stroke", "black") .style("opacity", .6) .style("fill", "red") .attr("r", 20) const map = this.map; function update() { circle.attr("transform", function (d) { return "translate(" + map.latLngToLayerPoint(d.latlng as any).x + "," + map.latLngToLayerPoint(d.latlng as any).y + ")"; } ) } this.map.on("viewreset", update);
this.map.on("zoom", update); update(); } } }
@v-viig hi there, I came across this and followed the steps you guys took but I got an error Invalid API version 1.10.0 Anyway idea how to fix this please?
Thank you
Pedzilla
What version of pbiviz do you ($ pbiviz --version)?
You might try updating API version by running pbiviz update 1.13.0 in the directory where you visual is locatted.
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
Thank you @v-viig Ive done that but got the error
TYPESCRIPT File 'C:/viz/d3leaflet/src/Clients/Typedefs/d3/d3.d.ts' not found
error TYPESCRIPT File 'C:/viz/d3leaflet/src/Clients/Typedefs/jquery-visible/
jquery-visible.d.ts' not found.
error TYPESCRIPT File 'C:/viz/d3leaflet/src/Clients/Typedefs/jquery/jquery.d
.ts' not found.
error TYPESCRIPT File 'C:/viz/d3leaflet/src/Clients/Typedefs/leaflet/leaflet
.d.ts' not found.
error TYPESCRIPT /src/visual.ts : (18,22) Cannot find namespace 'L'.
error TYPESCRIPT /src/visual.ts : (19,26) Cannot find namespace 'L'.
error TYPESCRIPT /src/visual.ts : (20,24) Cannot find namespace 'L'.
what have i done wrong please?
Thanks so much
Can you share the source code? Did you generate a custom visual by using pbiviz new command?
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
Hey there @v-viig
Thanks for replying...
I used exact codes shown in this thread actually.
I started off with pbiviz new command then I used your solution as per above.
Then run pbiviz start and got following error Invalid API version
Then tried again with pbiviz update as per your suggestion then got the final error Typescript etc...
Thank you so much - I feel like its not far off...
Can you share the source code to debug it from our side?
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
tsconfig.json
{ "compilerOptions": { "allowJs": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "target": "ES5", "sourceMap": true, "out": "./.tmp/build/visual.js" }, "files": [ ".api/v1.10.0/PowerBI-visuals.d.ts", "src/Clients/Typedefs/d3/d3.d.ts", "src/Clients/Typedefs/jquery/jquery.d.ts", "src/Clients/Typedefs/jquery-visible/jquery-visible.d.ts", "src/Clients/Typedefs/leaflet/leaflet.d.ts", "src/visual.ts" ] }
pbiviz.json
{ "visual": { "name": "customMap", "displayName": "Custom Map", "guid": "custommap5A89ADFB5F694F71AB6D00C94383BB2B", "visualClassName": "Visual", "version": "1.0.0", "description": "", "supportUrl": "", "gitHubUrl": "" }, "apiVersion": "1.10.0", "author": { "name": "", "email": "" }, "assets": { "icon": "assets/icon.png" }, "externalJS": [ "node_modules/powerbi-visuals-utils-dataviewutils/lib/index.js", "node_modules/d3/d3.min.js", "node_modules/fix.js", "node_modules/leaflet/dist/leaflet.js" ], "style": "style/visual.less", "capabilities": "capabilities.json", "dependencies": "dependencies.json", "stringResources": [] }
package.json
{ "name": "visual", "version": "1.1", "dependencies": { "@types/d3": "^3.5.41", "d3": "^3.5.17", "geojson": "^0.5.0", "leaflet": "^1.3.1", "powerbi-visuals-utils-dataviewutils": "1.2.0" }, "devDependencies": { "typescript": "^2.6.2" } }
visual.less
@import (less) "node_modules/leaflet/dist/leaflet.css";
Thank you @v-viig
Do you all of required files in src/Clients/Typedefs/ ?
It would be better if you could share source code as a zip file.
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
https://github.com/nujcharee/PowerBI/blob/master/d3leaflet.zip
Hi there, hope this is what you are looking for? Thank you so much hope you can help me @v-viig
Some files do not exist. This is why you face the errors.
Ignat Vilesov,
Software Engineer
Microsoft Power BI Custom Visuals
It still doesnt work and maybe i didnt do something right. I undestand from the thread that you have provided the final fix to the other users I wonder if this custom visual can be shared please? I think I have tried and failed in building it and if there's solution out there already and is open source - I will be most grateful.
Many thanks
Pedzilla
Hi @Anonymous,
You need to do several things to get the visual properly running. If I alter the following things I got the visual running like http://bl.ocks.org/d3noob/9267535:
pbiviz.json
tsconfig.json
package.json - 'nice to have'
Last step: open a command prompt and navigate to the base directory of the visual and enter npm install --save-dev @types/leaflet to install the typings files to correct the errors: Cannot find namespace 'L'.
Hi there
@jppp I followed that and I finally had a visual! Many thanks for this much appreciated.
However, one last question from me I hope - how come my map is default to New Zealand? There must be somewhere in the data that I didnt remove before running pbiviz package command. Must be rookie mistake but hope you could help please?
Thank you
Ped
User | Count |
---|---|
17 | |
11 | |
5 | |
4 | |
3 |