Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Register now to learn Fabric in free live sessions led by the best Microsoft experts. From Apr 16 to May 9, in English and Spanish.

Reply
Anonymous
Not applicable

Use Google Map API in custom visual

hello,

I'm currently trying to display a google map on my custom visual that I'm developing.

In fact, I don't know how can I import the namespece, and the API.

Here is the code I'm trying to use :

 
    <script>
      var map;
      function initMap() {
        map = new google.maps.Map(document.getElementById('map'), {
          center: {lat: -34.397, lng: 150.644},
          zoom: 8
        });
      }
    </script>

    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAyARcNvQVVfuYxt8JGT2ndho2_010AWkQ&callback=initMap"
    async defer></script>

  </div>
 
 
 

Thank you

1 ACCEPTED SOLUTION
v-viig
Community Champion
Community Champion

Hello @Anonymous,

 

I suppose that you might use these code below and apply it to your case:

 

constructor(options: VisualConstructorOptions) {
    d3.select(options.element)
        .append('script')
        .attr({
            type: 'text/javascript',
            src: 'https://maps.googleapis.com/maps/api/js?key=AIzaSyAyARcNvQVVfuYxt8JGT2ndho2_010AWkQ',
            async: true
        })
        .on('load', () => {
            this.initMap();
        });

    this.element = options.element;
}

private initMap() {
    const google = window['google'] || window.window['google'];

    this.map = new google.maps.Map(this.element, {
        center: { lat: -34, lng: 150 },
        zoom: 8
    });
}

View solution in original post

12 REPLIES 12
mhuancahuari
New Member

Hola, llegaste a importar el typescript de google maps para npm?.

 

Si no lo hiciste revisa primero esto aqui: 

https://www.npmjs.com/package/@types/googlemaps

 

Luego debes de mapear el typescript dentro de tu definición de tipos en el archivo:

 

".\typings\index.d.ts"

 

Agrega la referencia alli, y luego podras usarlo en tu CustomVisual.

mhuancahuari
New Member

llegaste a importar la libreria de TypeScript para Google Maps de NPM?

 

si no lo hiciste revisa este link

 

https://www.npmjs.com/package/@types/googlemaps

mhuancahuari
New Member

Hola Skizofree,

No he usado google masp sobre powerBi, pero intentaste importar el typescript dentro del Proyecto CustomVisual que estas realizando?

 

Revisa esto aqui.

https://www.npmjs.com/package/@types/googlemaps

 

Luego mapea el TypeScript dentro de tu proyecto para que puedas utilizar esos tipos (verifica el archivo ".\typings\index.d.ts")

Segundamente deberás agregar la referencia al nuevo typescript instalado  algo como:
/// <reference path="globals/googlemaps/google.maps.d.ts" />

 

Luego en tu codigo visual.ts (nombre por defecto de tu archivo typescript)

ya puedes usar referencias a los objetos MVC de Google maps

como declarar  variables:

 

private myMap: google.maps.Map;

 

usar asignaciones de variables:

var marker = new google.maps.Marker({ position: myLatLng , map: myMap});

 

 

y no olvides insertar en tu código la instancia del script de google maps a la página como:

 

let script = document.createElement('script');
script.type = 'text/javascript';
script.src= "https://maps.googleapis.com/maps/api/js?libraries=visualization";
document.body.appendChild(script);

 

Si te fue bien, me comentas a marco.huancahuari@gmail.com

v-chuncz-msft
Community Support
Community Support

@Anonymous, One way is to append the above html to options.element using JavaScript directly.
Community Support Team _ Sam Zha
If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.
Anonymous
Not applicable

@v-chuncz-msft I already tried that without any result .. Are you sure we can use APIs within custom visual ?

@Anonymous,

 

Yes, I've tested it, though not very elegant.

Community Support Team _ Sam Zha
If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.
Anonymous
Not applicable

@v-chuncz-msft so what's wrong with my code ? if its working for you ? I cant get it xD

After several investigations I think the issue comes witht the wrraper "sanbox-host", since I need to put the div with a specific height.

Can you please Tell me how you did it ?

 

thank you very much for your help.

@Anonymous,

 

See script below as an example.

        constructor(options: VisualConstructorOptions) {
			let mapDiv = document.createElement('div');
			mapDiv.id = 'map';
			mapDiv.style.height = "400px";
			options.element.appendChild(mapDiv);
			
			let js = document.createElement('script');
			js.innerHTML = "var map;"
							+ "function initMap() {"
							+ "map = new google.maps.Map(document.getElementById('map'), {"
							+ "center: {lat: -34.397, lng: 150.644},"
							+ "zoom: 8"
							+ "});"
							+ "}";
			options.element.appendChild(js);
			
			js = document.createElement('script');
			js.src='https://maps.googleapis.com/maps/api/js?key=AIzaSyAyARcNvQVVfuYxt8JGT2ndho2_010AWkQ&callback=initMap';
			options.element.appendChild(js);
Community Support Team _ Sam Zha
If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.
Anonymous
Not applicable

@v-chuncz-msft thank you very much; Its working now. I only have one more question. In your code you handled everything as innerHTML but can I embed this in my code for further processing for instance if I want to do calcustions, call classes and methods ... ? This is the code I was working on but not working :

 

module powerbi.extensibility.visual {


    /**
     * Function that converts queried data into a view model that will be used by the visual
     *
     * @function
     * @param {VisualUpdateOptions} options - Contains references to the size of the container
     *                                        and the dataView which contains all the data
     *                                        the visual had queried.
     * @param {IVisualHost} host            - Contains references to the host which contains services
     */

    export class BarChart implements IVisual {
        private div: d3.Selection<SVGElement>;
        private host: IVisualHost;
        private barChartContainer: d3.Selection<SVGElement>;
        private barContainer: d3.Selection<SVGElement>;
        private bars: d3.Selection<SVGElement>;
        private target: HTMLElement;
        private g: d3.Selection<SVGAElement>;
        private object:any;
        private css: d3.Selection<SVGAElement>;
        private script: d3.Selection<SVGAElement>;
        private map : google.maps.Map;



        static Config = {
            xScalePadding: 0.1,
        };

        /**
         * Creates instance of BarChart. This method is only called once.
         *
         * @constructor
         * @param {VisualConstructorOptions} options - Contains references to the element that will
         *                                             contain the visual and a reference to the host
         *                                             which contains services.
         */
        constructor(options: VisualConstructorOptions) {
            this.host = options.host;
            this.target = options.element;

         // this.target.innerHTML = "<script src=\"https://maps.googleapis.com/maps/api/js?key=AIzaSyAyARcNvQVVfuYxt8JGT2ndho2_010AWkQ&callback=initMap\",async defer></script>");

            let script = document.createElement('script');
            script.type = 'text/javascript';
            script.src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAyARcNvQVVfuYxt8JGT2ndho2_010AWkQ&callback=initMap";
            script.async = true;
            document.body.appendChild(script);


            this.div = d3.select(options.element)
            .append('div');

          

           
        }

        /**
         * Updates the state of the visual. Every sequential databinding and resize will call update.
         *
         * @function
         * @param {VisualUpdateOptions} options - Contains references to the size of the container
         *                                        and the dataView which contains all the data
         *                                        the visual had queried.
         */
        public update(options: VisualUpdateOptions) {
         //   let viewModel: BarChartViewModel = visualTransform(options, this.host);
            let width = options.viewport.width;
            let height = options.viewport.height;

            this.div.attr({id:"zakaria",width: width, height : height}); 
            
            function initMap(){
                this.map = new google.maps.Map(document.getElementById('zakaria'),{
                    center : {lat:-34,lng:150},
                    zoom : 8

                });

              
            }


        }

        /**
         * Destroy runs when the visual is removed. Any cleanup that the visual needs to
         * do should be done here.
         *
         * @function
         */
        public destroy(): void {
            //Perform any cleanup tasks here
        }
    }
}

whats wrong with it ? 

 

Thank you very much again (y)

v-viig
Community Champion
Community Champion

Hello @Anonymous,

 

I suppose that you might use these code below and apply it to your case:

 

constructor(options: VisualConstructorOptions) {
    d3.select(options.element)
        .append('script')
        .attr({
            type: 'text/javascript',
            src: 'https://maps.googleapis.com/maps/api/js?key=AIzaSyAyARcNvQVVfuYxt8JGT2ndho2_010AWkQ',
            async: true
        })
        .on('load', () => {
            this.initMap();
        });

    this.element = options.element;
}

private initMap() {
    const google = window['google'] || window.window['google'];

    this.map = new google.maps.Map(this.element, {
        center: { lat: -34, lng: 150 },
        zoom: 8
    });
}
Anonymous
Not applicable

Hi All,

 

I am having problems trying to integrate Javascript Google Maps in a new custom visual i am developing using

nodejs and pbiviz tools. I am stuck trying to connect latitude and longitude in the map.

This geograpy data are comming from SQL Server and dataset is correctly imported in PowerBI.

 

These are the tools i am using:

 

{
  "name": "visual",
  "scripts": {
    "pbiviz": "pbiviz",
    "start": "pbiviz start",
    "package": "pbiviz package",
    "lint": "tslint -c tslint.json -p tsconfig.json"
  },
  "dependencies": {
    "@babel/runtime": "7.6.0",
    "@babel/runtime-corejs2": "7.6.0",
    "@types/d3": "^5.7.2",
    "@types/googlemaps": "^3.39.3",
    "core-js": "^3.6.4",
    "d3": "^5.15.0",
    "powerbi-visuals-utils-dataviewutils": "2.2.1"
  },
  "devDependencies": {
    "powerbi-visuals-api": "^2.6.2",
    "ts-loader": "6.1.0",
    "tslint": "^5.18.0",
    "tslint-microsoft-contrib": "^6.2.0",
    "typescript": "3.6.3"
  }
}

 

Regarding to the code, i have Visual class, and i created with it:

  • Data model to hold latitude and longitud 
  • constructor to init map with the location of my country (Dominican Republic)
  • update method: reference to the data model and data comming from Sql Server in which it has a table containing all latitude and longitude
  • converter method with dummy data to test

 

 

/*
*  Power BI Visual CLI
*
*  Copyright (c) Microsoft Corporation
*  All 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 "./../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 d3 from './../node_modules/d3';
import { VisualSettings } from "./settings";

module geo.data {
    export interface StreamData{
        caseDataPoints: CaseModel[][];
    }
    export interface CaseModel {
        latitude: number;
        longitude: number;
        color?: string;
    }
}

export class Visual implements IVisual {
    private target: HTMLElement;
    private div: d3.Selection<SVGElement>;
    private script: d3.Selection<SVGAElement>;
    private map : google.maps.Map;
    private case_geo_data: geo.data.CaseModel;

    constructor(options: VisualConstructorOptions) {
        let mapDiv = document.createElement('div');
        mapDiv.id = 'map';
        mapDiv.style.height = "550px";
        options.element.appendChild(mapDiv);        
        
        var dr = {lat: 18.483402, lng: -69.929611};
        
        let js = document.createElement('script');
        js.innerHTML = "var map;"
                        + "function initMap() {"
                        + "map = new google.maps.Map(document.getElementById('map'), {"
                        + "center: {lat: 18.483402, lng: -69.929611},"
                        + "zoom: 8"
                        + "});"
                        + "}";
        options.element.appendChild(js);
        
        js = document.createElement('script');
        js.src='https://maps.googleapis.com/maps/api/js?key=APIKey&callback=initMap';
        options.element.appendChild(js);
    }

    public update(options: VisualUpdateOptions) {
        console.log('Visual update', options);
        let width = options.viewport.width;
        let height = options.viewport.height;

        if (!options.dataViews) return;
        console.log("has data");

        var dataViewCase: DataView = options.dataViews[0];
        var data = Visual.converter(dataViewCase);
        var caseDataPoints = data.caseDataPoints;
        var viewport = options.viewport;        
        
        /*
        var uluru = {lat: -25.344, lng: 131.036};
        this.div.attr({id:"test1", width: width, height:height});

        
        function initMap(){
            this.map = new google.maps.Map(document.getElementById('test1'),{
                center : uluru,
                zoom : 8

            });

          
        }
        */
    }

    public static converter(dataView: DataView): geo.data.StreamData {
        return{
            caseDataPoints: [
                [
                 {latitude:5.3884, longitude:100.306},
                 {latitude:5.34738, longitude:100.295}
                ],
                [ 
                  {latitude:5.3894, longitude:100.302},
                  {latitude:5.4079, longitude:100.292},
                  {latitude:5.4191, longitude:100.329}
                ]
            ]
        }
    }

    private static parseSettings(dataView: DataView): VisualSettings {
        return <VisualSettings>VisualSettings.parse(dataView);
    }


}

 

 

My problems are with the update method, need to connect map with the latitud and longitude comming from DB.

At this moment, after checking davaview data, it only shows latitude.

I have two dataroles defined as geography data:

1- Case_Latitude

2- Case_Longitud

 

And this is my dataviewMappings

 

 

"dataViewMappings": [
        {
            "categorical": {
                "categories": {
                    "for": {
                        "in": "Case_Latitude"
                    },
                    "dataReductionAlgorithm": {
                        "top": {}
                    }
                },
                "values": {
                    "select": [
                        {
                            "bind": {
                                "to": "Case_Latitude"
                            }    
                        }
                    ]
                }
            }
        }
    ]

 

 

I need help, please, if possible Mr. @v-viig @Anonymous @v-chuncz-msft and others. It has been kind of difficult to me, because i haven't could debbug, and that is why i openned question regarding to debug issues in the debug forum.

 

Appreaciate this help!!

Thanks.

 

Anonymous
Not applicable

@Anonymous Did you complete this visual? Is the source code available somwhere?

Helpful resources

Announcements
Microsoft Fabric Learn Together

Microsoft Fabric Learn Together

Covering the world! 9:00-10:30 AM Sydney, 4:00-5:30 PM CET (Paris/Berlin), 7:00-8:30 PM Mexico City

PBI_APRIL_CAROUSEL1

Power BI Monthly Update - April 2024

Check out the April 2024 Power BI update to learn about new features.

April Fabric Community Update

Fabric Community Update - April 2024

Find out what's new and trending in the Fabric Community.