Forum Discussion

kal-tahrawi's avatar
kal-tahrawi
Frequent Visitor
8 years ago
Solved

Power bi custom visual and leaflet library

I cloned power bi and leaflet project from GitHub and the following is the project link:
https://github.com/woodbuffalo/powerbi-leaflet

 

powerbi-leaflet/pbiviz.json

 

 {
    "visual": {
        "name": "wBRecoveryStatus",
        "displayName": "WB Recovery Status",
        "guid": "PBI_CV_7844889B_1C25_49B0_A895_4FF3BB38DCF1",
        "visualClassName": "LeafletMap",
        "version": "1.0.0",
        "description": "",
        "supportUrl": "",
        "gitHubUrl": ""
    },
    "apiVersion": "1.1.0",
    "author": {
        "name": "",
        "email": ""
    },
    "assets": {
        "icon": "assets/icon.png"
    },
    "externalJS": [],
    "style": "style/visual.less",
    "capabilities": "capabilities.json"
}

powerbi-leaflet/tsconfig.json

 

{
    "compilerOptions": {
        "allowJs": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "target": "ES5",
        "sourceMap": true,
        "out": "./.tmp/build/visual.js"
    },
    "files": [
        ".api/v1.1.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"
    ]
}

powerbi-leaflet/src/visual.ts

export class LeafletMap implements IVisual {
    private dataView: DataView;
    private map: L.Map;
    private basemap: L.TileLayer;
    private markerLayer: L.LayerGroup<L.CircleMarker>;

    constructor(options: VisualConstructorOptions) {
        console.log('constructor called');
        let $mapDiv = $('<div></div>')
            .attr('id', 'map')
            .css('height', 500)
            .css('width', 700);

        $(options.element).append($mapDiv);

        this.basemap = L.tileLayer('https://d5nra9v0s4zer.cloudfront.net/base-tiles-2016/{z}/{y}/{x}');

        this.map = L.map('map', {
            center: new L.LatLng(56.7050482, -111.4407939),
            zoom: 12,
            maxZoom: 18,
            minZoom: 12
        });

        this.map.addLayer(this.basemap);
    }

    public static converter(dataView: DataView) {
        const {columns, rows} = dataView.table;
        const c10 = d3.scale.category10();

        const datas = rows.map(function (row, idx) {
            let data = row.reduce(function (d, v, i) {
                const role = Object.keys(columns[i].roles)[0]
                d[role] = v;
                return d;
            }, {});

            data.color = c10(data.category);

            return data;
        });

        return datas;
    }

    public update(options: VisualUpdateOptions) {
        console.log('update called');

        $('#map')
            .css('height', options.viewport.height)
            .css('width', options.viewport.width);

        this.map.invalidateSize(true);

        if (!options.dataViews && !options.dataViews[0]) return;

        if (this.markerLayer) this.map.removeLayer(this.markerLayer);

        this.dataView = options.dataViews[0];
        const data = LeafletMap.converter(this.dataView);

        const markers = data.map(function (d) {
            const latlng = L.latLng([d.latitude, d.longitude]);
            let marker = L.circleMarker(latlng, {color: d.color, fillOpacity: 1});

            const category = d.category ? d.category : 'NA';
            marker.bindPopup(d.tooltip + ' : ' + category);
            marker.on('mouseover', function (evt) {
                marker.openPopup();
            });

            return marker;
        });

        this.markerLayer = L.layerGroup(markers);
        this.map.addLayer(this.markerLayer);
    }

    public destroy() {
        console.log('destroy called');
        this.map.remove();
    }
}

 

Everything is working fine but when I compiled the project the map is not rendered even when I added fields (lat, long), please advise!

  • v-viig's avatar
    v-viig
    8 years ago

    You might workaround this error by including these lines into a new file and including this file into externalJS property of pbiviz.json (please note that this file should be specified before leaflet):

    window.devicePixelRatio = Object.defineProperty(window, "devicePixelRatio", {
        get: function() {
            return window.window.devicePixelRatio;
        },
        enumerable: true,
    });
    
    
    window.outerWidth = Object.defineProperty(window, "outerWidth", {
        get: function() {
            return window.window.outerWidth;
        }
    });
    
    window.outerHeight = Object.defineProperty(window, "outerHeight", {
        get: function() {
            return window.window.outerHeight;
        }
    });

    Please let us know if you have any extra questions.

     

    Ignat Vilesov,

    Software Engineer

     

    Microsoft Power BI Custom Visuals

    [email protected]

3 Replies

    • kal-tahrawi's avatar
      kal-tahrawi
      Frequent Visitor

      Thank you so much for your help, I have a quetion when the project was comiled on OS operating syetem the map was rendered succssfully but when i used the windows i have this error 

      Uncaught TypeError: Illegal invocation
      at <anonymous>:526:25347
      at $t (<anonymous>:526:140)
      at Window.<anonymous> (<anonymous>:526:150)
      at <anonymous>:842:20
      at Object.r [as injectJsCode] (VM1610 visualhostcore.min.js:2)
      at i.loadWithoutResourcePackage (VM1611 visualsandbox.min.js:1)
      at i.executeMessage (VM1611 visualsandbox.min.js:1)
      at i.onMessageReceived (VM1611 visualsandbox.min.js:1)
      at VM1611 visualsandbox.min.js:1
      at e.invokeHandler (VM1610 visualhostcore.min.js:2) any advise?
      • v-viig's avatar
        v-viig
        Community Champion

        You might workaround this error by including these lines into a new file and including this file into externalJS property of pbiviz.json (please note that this file should be specified before leaflet):

        window.devicePixelRatio = Object.defineProperty(window, "devicePixelRatio", {
            get: function() {
                return window.window.devicePixelRatio;
            },
            enumerable: true,
        });
        
        
        window.outerWidth = Object.defineProperty(window, "outerWidth", {
            get: function() {
                return window.window.outerWidth;
            }
        });
        
        window.outerHeight = Object.defineProperty(window, "outerHeight", {
            get: function() {
                return window.window.outerHeight;
            }
        });

        Please let us know if you have any extra questions.

         

        Ignat Vilesov,

        Software Engineer

         

        Microsoft Power BI Custom Visuals

        [email protected]