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

July 7 - July 17 | Round 2 of the Power BI Dataviz World Championships. Don't miss your chance! Learn more

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 [email protected]

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
FabCon and SQLCon Barcelona 2026

FabCon & SQLCon – Barcelona 2026

Join us in Barcelona for FabCon and SQLCon, the Fabric, Power BI, SQL, and AI community event. Save €200 with code FABCMTY200.

60 days of Data Days Carousel

Data Days 2026

Join Fabric Data Days 2026: 60 days of free live/on-demand sessions, challenges, study groups, and certification opportunities.

Power BI DataViz World Championships carousel

Power BI DataViz World Championships - June 2026

A new Power BI DataViz World Championship is coming this June! Don't miss out on submitting your entry.

Top Solution Authors