npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

logicify-gmap

v0.1.14

Published

Create google maps based on angular framework.

Downloads

14

Readme

What is this repository for?

  • This product is a wrapper for google maps api based on angular.
  • Stable Version 0.1.14

NPM

For developers

  • node.js and npm
 npm install grunt-cli -g
 npm install bower -g
 npm install
 grunt logicifyGmap

Usage

JSFiddle example

example

bower install logicify-gmap

or

npm install logicify-gmap

At first you need include google api reference into your html file.

Something like that:

<script src="https://maps.googleapis.com/maps/api/js?v=3.20"></script>
You need to be sure that this api is loaded before angular.js
Inject module into your angular app
var app = angular.module('myApp', [ "LogicifyGMap" ]);
Inject map (directive)

place it in your html file

<logicify-gmap center="gmOpts.center"
               gm-options="gmOpts"
               gm-ready="ready"
               css-options="cssOpts">
</logicify-gmap>
  • center - center map (is LatLng object from google api);
  • gm-options - (javascript object) is google maps options google api
  • gm-ready - (function) callback function fires when directive is rendered and passes on gmap Object.

From controller

var app = angular.module('myApp', [ "LogicifyGMap" ]);
app.controller('myCtrl',['$scope',function($scope){
    $scope.cssOpts = {width: '50%', height: '50%', 'min-width': '400px', 'min-height': '200px'};
    $scope.gmOpts = {zoom: 10, center: new google.maps.LatLng(-1, 1)};
    $scope.ready = function(gmap){
        $scope.gmap = gmap; //it's google maps object (not wrapped)
    };
}]);
  • css-options - is javascript object is needed for injecting css into map element
Custom X (close) button for info window.
     .gm-style-iw+div{
         display:none
         }

where .gm-style-iw is a class of container element, and next div is close button!

Inject map controls (directive)

html

<logicify-gmap center="gmOpts.center"
               gm-options="gmOpts"
               gm-ready="ready"
               css-options="cssOpts">
    <logicify-gmap-control
    control-position="position"
    control-index="1"
    events="controlEvents">
        <button>Push me</button>
        <input type="file">
    </logicify-gmap-control>
</logicify-gmap>

script

$scope.index = 1;
$scope.position = google.maps.ControlPosition.BOTTOM_LEFT;
$scope.controlEvents = {
                click: function (event) {
                    //it's google.maps.event
                },
                fileSelect: function(file){
                    //this method binds on file input inside logicify-gmap-control directive
                    //it's DOM event
                }
            };

controlEvents - it's just a javascript object. Each key should be an event name ('click','mouseover'...) and value is a callback function.

Info window

It's angular supported. So you can use angular inside info window template (directives, scope, controller...).

Inject 'InfoWindow' service from 'logicify-gmap' api.

module.controller('myCtrl', ['$scope', '$timeout', 'InfoWindow', function ($scope, $timeout, InfoWindow) {
            $scope.markers = [];
            $scope.cssOpts = {width: '50%', height: '50%', 'min-width': '400px', 'min-height': '200px'};
            $scope.gmOpts = {zoom: 10, center: new google.maps.LatLng(-1, 1)};
            $scope.closeInfoWindow = function (infowindow) {
                infowindow.close(true); //destroy scope and info window element
                //or
                //infowindow.close();  //just close info window
            };
            $scope.ready = function (map) {
                var infowindow = new InfoWindow({templateUrl: 'template.html'}); //it's not infowindow now. (object like "javascript promise", but not a promise)
                function attach(marker) {
                    google.maps.event.addListener(marker, 'click', function (markerObj) { //on marker click
                        infowindow.$ready(function (wnd) { // pass infowindow object
                            wnd.open(map, marker); //open infowindow
                        });
                    });
                }

                //loop all markers
                for (var i = 10; i < 15; i++) {
                    var pos = new google.maps.LatLng(-1 + 1 / i, 1 + 1 / i);//random position
                    var marker = new google.maps.Marker({    //create new marker
                        id: 'marker_' + i,
                        name: 'is_' + i,
                        position: pos,
                        map: map
                    });
                    $scope.markers.push(marker);
                    attach(marker);//attach listener
                }
            };

        }]);

template.html

<div>
    <label>{{$infoWND.anchor.id}}</label>
    <button ng-click="closeInfoWindow($infoWND)">Close me</button>
</div>
  • when you try to create info window object
var infowindow = new InfoWindow({templateUrl: 'template.html'});

It's not an infowindow yet. Because rendering template and apply scope digest takes some time.

 infowindow.$ready(function (wnd) {
                            //do something with 'wnd'
                        });

And now 'wnd' is info window object.

you can use $infoWND object in the template.html. $infoWND.anchor is a marker!

Many info windows in one time:

$scope.ready = function (map) {

                function attach(marker) {
                    var infowindow = new InfoWindow({templateUrl: 'template.html'}); //create new infowindow for each marker
                    google.maps.event.addListener(marker, 'click', function (markerObj) { //on marker click
                        infowindow.$ready(function (wnd) { // pass infowindow object
                            wnd.open(map, marker); //open infowindow
                        });
                    });
                }

                //loop all markers
                for (var i = 10; i < 15; i++) {
                    var pos = new google.maps.LatLng(-1 + 1 / i, 1 + 1 / i);//random position
                    var marker = new google.maps.Marker({    //create new marker
                        id: 'marker_' + i,
                        name: 'is_' + i,
                        position: pos,
                        map: map
                    });
                    $scope.markers.push(marker);
                    attach(marker);//attach listener
                }
            };

If you want more than one info window on google map, you just need create it for each marker!

var infowindow = new InfoWindow({templateUrl: 'template.html'}); //in the loop

Closing info window can be done in two ways:

  1. Destroy scope and element. Please careful with this param, because to render it again - takes more time then just apply scope digest.
infowindow.close(true)
  1. Just hide window (proper way).
infowindow.close();
Note that after opening info window (wnd.open(map)) you can access to wnd.$scope (property "$scope" only, not "scope")!

why only after opening? Because "open" method rewrites infowindow scope and applies digest. So you can access the scope only after calling method "open".

XML overlays support

jsfiddle example

There is a way to display xml overlays on google map using "xml-overlays" directive. Note that we are using geoxml3 library to parse xml files. XML files can be: .zip, .kmz, .kml, or just a string. Kml\kmz object can contain:

 var list = [
        {url:'some url of kml or kmz file here'},
        {file: instance of Blob here},
        {content: just string value}
 ]

Basic usage:

include this file to your html:

  • geoxml3.js
HTML
<div ng-controller="TestController">
    <logicify-gmap
            center="gmOpts.center"
            gm-options="gmOpts"
            gm-ready="ready"
            css-options="cssOpts">
        <logicify-gmap-control
                control-position="position"
                control-index="1"
                events="controlEvents">
            <button>Push me</button>
        </logicify-gmap-control>
        <xml-overlays
                kml-collection="kmlCollection"
                gmap-events="kmlEvents">
        </xml-overlays>
    </logicify-gmap>
</div>
JS
app.controller('TestController', ['$scope', '$timeout', 'InfoWindow', function ($scope, $timeout, InfoWindow) {
        $scope.markers = [];
        $scope.controlEvents = {
            click: function (event) {
                $scope.kmlCollection = [
                    {url: 'tristate_area.kml'}
                ];
            }
        };
        $scope.cssOpts = {
            width: '80%',
            height: '60%',
            'min-width': '400px',
            'min-height': '200px'
        };
        $scope.gmOpts = {
            zoom: 16,
            center: new google.maps.LatLng(-1, 1)
        };
        $scope.kmlCollection = [
            {url: 'cta.kml'}
        ];
        $timeout(function () {
            $scope.kmlCollection.push({url: 'tristate_area.kml'});
        }, 3000);
        $timeout(function () {
            $scope.kmlCollection.pop();
        }, 6000);
        $timeout(function () {
            $scope.kmlCollection = [{url: 'tristate_area.kml'},{url: 'cta.kml'}];
        }, 9000);
        $scope.kmlEvents = {};
        $scope.position = google.maps.ControlPosition.BOTTOM_LEFT;
        $scope.index = 1;
    }]);
Events
 <xml-overlays
                kml-collection="kmlCollection"
                gmap-events="kmlEvents">
 </xml-overlays>
var kmlEvents = {
    onAfterParse:function(doc){
        //doc - array with documents
    },
    onAfterParseFailed:function(err){

    },
    onAfterCreateGroundOverlay:function(groundOverlayGMapMVCObject){
    },
    onAfterCreatePolygon:function(polygonMVCObject,placemark){
        //all mvc objects has methods "get" & "set"
    },
    onAfterCreatePolyLine:function(polyLineMVCObject,placemark){

    }
};

Also you can include all events from geoxml3 lib

Options:

all options described on geoxml3 repository There is one more option fit-bounds-afterAll

<xml-overlays
                kml-collection="kmlCollection"
                gmap-events="kmlEvents"
                fit-bounds-afterAll="false">
</xml-overlays>

This option is true by default. When you are disabling this option the last layer will be displayed on the map. To view all layers you need modify zoom and center of the map by mouse. If this options is enabled, then all layers will be displayed on the map, and you don't need to scroll and dragging the map to view all layers

Progress callback

Html example

<xml-overlays
                kml-collection="kmlCollection"
                gmap-events="kmlEvents"
                on-progress="callback">
</xml-overlays>

Progress object structure

callback = function(progress){
    progress = {
            done: Integer,
            errors: Integer,
            total: Integer
        };
}

Progress callback calls each time when xml file downloaded and parsed (or parsing is failed).

Infowindow

You can create and inject infowindow to your overlays. But if you want to be able to access overlay MVC object from infowindow scope then you need just add property to infowindow object.

 $scope.overlaysInfowindow = new InfoWindow({templateUrl: 'infowindow.html'});
 $scope.overlaysInfowindow.$ready(overlayInfowindowReady); //w8 for downloading template
 function overlayInfowindowReady(wnd) {
     wnd.$onOpen = function (gObj) {   //method "open" of infowindow calls by geoxml3 parser, so you don't need call "infowindow.open(map,marker)" like for markers
        wnd.$scope.mvcObject = gObj;   //when infowindow opened then calls "$onOpen" callback with google mvc object
        gObj.setDraggable(true);
   };
 }

HTML

<div class="infowindow">
    {{mvcObject.title}}
    {{mvcObject.get('fillColor')}}
    ...etc
</div>

see more information about google mvc object

Load kml\kmz file via HTML file input:

jsfiddle example

How it works

The kml\kmz collection is instance of "SmartCollection" (you can inject it just by adding "SmartCollection"-service to your dependency). SmartCollection - is angular service. SmartCollection instanceOf Array === true.

var file1 = {url:'http://some url'}, file2 = {url:'http://some url'}, file3 = {url:'http://some url'};
scope.kmlCollection = [file1,file2,file3]; //create new collection
scope.kmlCollection = [file1, file2, file3] //delete old collection and crete new one (all those files will be downloaded again)
scope.kmlCollection.push({url:'http://different url'}); //only this file will be downloaded and parsed.
//next example
scope.kmlCollection.splice(1,scope.kmlCollection.length) // delete last 2 items (file1 wouldn't be reloaded)
scope.kmlCollection = [file1]; //reload file1 and delete rest

Drawing support

####### First of all you need to see

google maps spec.

Usage:
  • Add dependency injection for google maps drawing api (taken from google maps drawing spec):
<script type="text/javascript"
  src="https://maps.googleapis.com/maps/api/js?&libraries=drawing">
</script>

As can you see dependency injection it's just url param.

  • Include this html into gmap directive:
<logicify-gmap
            center="gmOpts.center"
            gm-options="gmOpts"
            gm-ready="ready"
            css-options="cssOpts">
        <logicify-gmap-draw
                gmap-events="draw.events"
                draw-options="draw.options">
        </logicify-gmap-draw>
</logicify-gmap>
  • Implement JS logic to be able manipulate the map (controller code):
scope.draw = {
            //put all drawing things in one place
            events: {
                drawing: {},
                overlays: {
                    click: function (e, map) {
                        var self = this;
                        //note that "this" can be overlay or marker, you need to be careful, because marker doesn't have "center" property and overlay has.
                        if (scope.overlaysInfowindow) {
                            scope.overlaysInfowindow.$ready(function (wnd) {
                                wnd.setPosition(e.latLng);//info window position
                                wnd.open(map);
                                wnd.$scope.mvcObject = self;
                                wnd.$scope.applyConfig = applyConfig;
                            });
                        }
                    }
                }
            },
            //see google maps spec about drawing options
            options: {
                drawingMode: google.maps.drawing.OverlayType.MARKER,
                drawingControl: true,
                drawingControlOptions: {
                    position: google.maps.ControlPosition.TOP_CENTER,
                    drawingModes: [
                        google.maps.drawing.OverlayType.MARKER,
                        google.maps.drawing.OverlayType.CIRCLE,
                        google.maps.drawing.OverlayType.POLYGON,
                        google.maps.drawing.OverlayType.POLYLINE,
                        google.maps.drawing.OverlayType.RECTANGLE
                    ]
                },
                markerOptions: {icon: 'beachflag.png'},
                circleOptions: {
                    fillColor: '#ffff00',
                    fillOpacity: 1,
                    strokeWeight: 5,
                    editable: true,
                    zIndex: 1
                }
            }
        };
        scope.cssOpts = {
            width: '80%',
            height: '60%',
            'min-width': '400px',
            'min-height': '200px'
        };
        scope.gmOpts = {
            zoom: 16,
            center: new google.maps.LatLng(-1, 1)
        };
        function applyConfig(mvcObject) {
            /**
             * Redraw overlay
             */
            mvcObject.setMap(null);
            mvcObject.setMap(scope.gmap);
        }

        scope.ready = function (map) {
            scope.gmap = map;
            scope.overlaysInfowindow = new infoWindow({templateUrl: 'infowindow.html'});
        };
Custom lines (requires drawing manager)

If you want custom lines, overlay borders then you need to do the next:

  • include css file to your html (gmap-minimum-ui.css) to allow dropdown to work correctly (gmap-dropdown based on css transitions)
  • include html code to your gmap directive (into logicify-gmap-draw directive):
<script type="text/ng-template" id="dropdown.html">
        <div class="custom-holder">
            <span class="custom-title" title="it's google baby <(^_^)>">G(.)(.)gle</span>
            <div gmap-dropdown gmap-dropdown-items="polyLineTypes" on-dropdown-select-item="onSelectPolyLineType"></div>
        </div>
</script>
<logicify-gmap
            center="gmOpts.center"
            gm-options="gmOpts"
            gm-ready="ready"
            css-options="cssOpts">
        <logicify-gmap-draw
                gmap-events="draw.events"
                draw-options="draw.options">
            <gmap-extended-draw
                    line-types-control-position="lineTypesControlPosition"
                    gmap-dropdown-template-url="dropDownTemplate">
                    gmap-dropdown-template="dropDownContent">
            </gmap-extended-draw>
        </logicify-gmap-draw>
    </logicify-gmap>

if you wouldn't define line-types-control-position attribute, then directive will append this dropdown to current element, so you will be able to draw it out of map

  • write some javascript in your controller:
scope.lineTypesControlPosition = google.maps.ControlPosition.TOP_CENTER; //let's say that it will be at top-center
//scope.dropDownTemplate = 'dropdown.html';
//you can define your own dropdown template(bootstrap for example)
//scope.dropDownContent = <div>Dropdown here</div>
//define dropdown template as string
//if you wouldn't define any template, then 'gmap-extended-draw' directive will use internal directive 'gmap-dropdown',
//so you don't need define your own dropdown
scope.draw = {//draw options here, see example above};
scope.cssOpts = {
    width: '90%',
    height: '90%',
    'min-width': '400px',
    'min-height': '200px'
};

scope.gmOpts = {
    zoom: 16,
    center: new google.maps.LatLng(-1, 1)
};
scope.ready = function (map) {
    scope.gmap = map;
};

######Note that if you would use your own dropdown, then please keep following rules:

  • "onSelectPolyLineType(item)" use this callback name in your html to select;
  • Use "current" object name to access selected item;
  • "polyLineTypes" use this object name to display poly line types in the dropdown; Example for custom bootstrap dropdown:
<div class="dropdown">
  <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
    <span class="gmap-dropdown-header" ng-bind="current.name||current"></span>
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
    <li ng-repeat="item in dropDownItems" ng-click="onSelectItemLocally(item)"><a ng-bind="item.name || item"></a></li>
  </ul>
</div>

jsfiddle example

Extending line types

You can extend list of supported line types (dotted, dashed, arrow-dotted etc.)

<logicify-gmap
            center="gmOpts.center"
            gm-options="gmOpts"
            gm-ready="ready"
            css-options="cssOpts">
        <logicify-gmap-draw
                gmap-events="draw.events"
                draw-options="draw.options">
            <gmap-extended-draw
                    line-types-control-position="lineTypesControlPosition"
                    gmap-dropdown-template-url="dropDownTemplate"
                    override-line-types="overrideLineTypes"
                    on-after-drawing-overlay="onAfterDraw">
            </gmap-extended-draw>
        </logicify-gmap-draw>
    </logicify-gmap>

As can you see there are few attributes added. override-line-types="overrideLineTypes" and on-after-drawing-overlay="onAfterDraw" Controller code below:

scope.lineTypesControlPosition = google.maps.ControlPosition.TOP_CENTER;
scope.overrideLineTypes = function (lineTypesArray) {
    var icon = {
        path: 'M0 0, L5 10, 10 -5', //svg path definition
        strokeWeight: 2,
        scale: 0.4
    };
    var layer = {
        name: 'Nice line',
        icons: [{icon: icon, offset: '100%', repeat: '20px'}],
        parentOptions: {
            strokeOpacity: 0
        }
    };
    lineTypesArray.push(layer);
    return lineTypesArray;//return array back to directive (Required!!!!!)
};
//will not fires if marker or circle was added
scope.onAfterDraw = function (lineType) {
    this.set('fillColor','#0af10a');
    //this - overlay
    //lineType - is an item from array of line types
    //this.border - is poly line around rectangle or polygon, because only those figures can't be styled with strokeStyle (strokeOpacity of overlay is 0)
    //border can be null if overlay is polyLine!!!! Otherwise it will be google MVC object always
    if(this.border!=null){
        //do something here
    }
};

What is "icons" in lineTypesArray exactly? For example:

var dottedIcon =  {
    path: 'M 0,-1 0,1', //it's svg path definition, please see w3 spec
    //options below
    strokeOpacity: 1,
    strokeWeight: 4,
    scale: 0.2
}
var arrow = {//arrow definition here}
var lineType = {
    name: 'My name is dotted line', //name displayed in dropdown list
    icons: [dottedIcon, arrow], //set dotted line here
    //those options will be applied to overlay
    parentOptions: {
        strokeOpacity: 0 //should be a 0, because you are drawing dotted line, we don't need any border
    }
}

You should check w3 org spec at first

svg path definition

Please see on-after-drawing-overlay callback.

This callback fires when custom lines applied to overlay (rectangle, polyline, polygon only). Border of shapes can't be styled as dotted or dashed for example, so we decided remove border of the shape overlay, and draw polyline instead. So each "overlay" object passed via this callback should have "overlay.border" property (it's poly line).

Editable mode.

You need to put all overlays to some collection. And then by clicking on some control, just set "editable" to true for all overlays.

scope.drawOptions = {
    events: {
        drawing: {
            overlaycomplete: function (e) {
                var self = this;
                overlaysCollection.push(e.overlay);
            }
        }
    }
};
scope.onAfterDraw = function (lineType) {
    overlaysCollection.push(this);
};
scope.toggleEditMode = function(){
    scope.isEditModeEnabled = !scope.isEditModeEnabled;
    overlaysCollection.forEach(function(overlay){
        overlay.set("editable",scope.isEditableModeEnabled);
        if(overlay.border){
            //do something with custom border (if it's polyline)
            border.set("editable", scope.isEditableModeEnabled)
        }
    });
};
If you want remove overlay you can do the next:
$scope.draw = {
    	events: {
            drawing: {
                overlaycomplete: function (e) {
                    //add listener
                    google.maps.event.addListener(e.overlay, 'click', function (e) {
                        if (window.event.ctrlKey) {
                            this.setMap(null);
                            if (this.border && typeof this.border.setMap === 'function') {
                                this.border.setMap(null);
                            }
                            //when overlay removed, we don't need any listeners on it
                            google.maps.event.clearInstanceListeners(this);
                        }
                    });
                }
            }
        }
	};
Please don't forget cleanup after you self. Remove all listeners from google instance if it's not needed any more.

jsfiddle example

Color picker

You can pick a color for lines and shapes. You need to do the next:

<logicify-gmap
            center="gmOpts.center"
            gm-options="gmOpts"
            gm-ready="ready"
            css-options="cssOpts">
        <logicify-gmap-draw
                gmap-events="draw.events"
                draw-options="draw.options">
            <gmap-extended-draw
                    line-types-control-position="lineTypesControlPosition"
                    gmap-dropdown-template-url="dropDownTemplate"
                    override-line-types="overrideLineTypes"
                    on-after-drawing-overlay="onAfterDraw"
                    gmap-color-picker=""
                    color-picker-control-position="colorPickerControlPosition"
                    enable-opacity-range="true">
            </gmap-extended-draw>
        </logicify-gmap-draw>
    </logicify-gmap>

Or

<logicify-gmap
            center="gmOpts.center"
            gm-options="gmOpts"
            gm-ready="ready"
            css-options="cssOpts">
        <logicify-gmap-draw
                gmap-events="draw.events"
                draw-options="draw.options">
            <gmap-extended-draw
                    line-types-control-position="lineTypesControlPosition"
                    gmap-dropdown-template-url="dropDownTemplate"
                    override-line-types="overrideLineTypes"
                    on-after-drawing-overlay="onAfterDraw">
                        <gmap-color-picker
                                color-picker-control-position="colorPickerControlPosition"
                                enable-opacity-range="true"
                                gmap-color-picker-template-url="dropDownTemplate"
                                gmap-color-picker-template="dropDownContent"
                                override-destinations="overrideCallback">
                        </gmap-color-picker>
            </gmap-extended-draw>
        </logicify-gmap-draw>
    </logicify-gmap>
scope.colorPickerControlPosition = google.maps.ControlPosition.TOP_CENTER;
//scope.colorPickerTemplate = 'colorPicker.html';
//you can define your own color picker template(bootstrap for example)
//scope.colorPickerContent = <div>Color picker here</div>
//define colorPicker template as string
//if you wouldn't define any template, then 'gmap-color-picker' directive will use internal html,
//so you don't need define your own color picker

you can override destinations (border, fill). Attribute "override-destinations" contains overrideCallback. This callback calls when directive initialize.

scope.overrideCallback = function(destinations){
    destinations.forEach(function(destination){
        destination.name += ' color or opacity';//you can see on the button "Fill color or opacity"
    });
    return destinations; //required!!! You need return array back to directive.
}

For custom color pickers you need to keep next rules:

  • if there's opacity input, then "onSelectOpacity" callback should be called in your html
  • ng-model is "destinations[destination].opacity.value" or "destinations[destination].color.value"
  • Destination name could be "Border" or "Fill" (or you can override it, but only two cases), for example in your html: "destinations[destination].name" Example html:
<input min="1" max="100" type="range" ng-change="onSelectOpacity()" ng-model="destinations[destination].opacity.value"/>
  • Button "toggle destination" should call "toggleDestination" callback (you can use any DOM event for this, "ng-click" for example)
  • For color picker you should use "onSelectColor" callback in your html
  • Note that all examples are with ng-model. So all callbacks ("onSelectOpacity" or "onSelectColor") calls to update drawing manager only, because it's in a parent directive

Example for color picker and change destination button:

<button ng-click="toggleDestination()" ng-bind="destinations[destination].name"></button>
<input type="color" ng-model="destinations[destination].color.value" ng-change="onSelectColor()"/>
Internal color picker - it's html5 input (type="color"). Please see browser capability

##Auto complete address search support Note that "places" library is required.

Your html

<logicify-gmap
            center="gmOpts.center"
            gm-options="gmOpts"
            gm-ready="ready"
            css-options="cssOpts">
        <gmap-auto-complete
                auto-complete-place-holder="placeHolder"
                default-zoom-on-placeChange="16"
                gmap-on-place-changed="onPlaceChanged"
                auto-complete-control-position="autoCompleteControlPosition"
                enable-auto-complete-type-selectors="true"
                enable-default-marker="enableDefaultMarker"
                on-reverse-address-complete="onReverseAddressComplete">
        </gmap-auto-complete>
</logicify-gmap>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>

Controller code:

scope.autoCompleteControlPosition = google.maps.ControlPosition.TOP_CENTER;
scope.placeHolder = 'Enter location';
scope.enableDefaultMarker = false;
scope.onPlaceChanged = function (map, place, inputValue) {
//if no infowindow then create
    if (!scope.placesInfoWindow) {
        scope.placesInfoWindow = new infoWindow({templateUrl: 'place.html'});
    }
    //if no marker then create
    if (!scope.placeMarker) {
        scope.placeMarker = new google.maps.Marker({
            id: 'places_marker',
            map: map
        });
    }
    var position = null;
    if (!place.geometry) {
        //if no geometry then check for latitude and longitude in address box
        var searchFor = inputValue;
        if (typeof searchFor === 'string' && searchFor.length > 0) {
            var splitLatLon = searchFor.split(','),
                latitude = splitLatLon[0] * 1,
                longitude = splitLatLon[1] * 1;
            if (splitLatLon.length == 2 && angular.isNumber(latitude) && angular.isNumber(longitude) && !isNaN(latitude) && !isNaN(longitude)) {
                position = {lat: latitude, lng: longitude};
                map.setCenter(position);
            }
        }
        //if no position then do nothing
        if (!position) {
            scope.placeMarker.setVisible(false);
            scope.placesInfoWindow.$ready(function (wnd) {
                wnd.close();
            });
            return;
        }
     } else {
        //if there's geometry
        position = place.geometry.location;
     }
     scope.placeMarker.setPosition(position);
     scope.placeMarker.setVisible(true);
     scope.placesInfoWindow.$ready(function (wnd) {
        wnd.place = place;
        wnd.open(map, scope.placeMarker);
     });
};

jsfiddle example

Reverse auto complete search

For example we handle 'dragend' event of marker.

scope.onReverseAddressComplete = function (searchResults) {
    return searchResults[0].formatted_address.split(',').splice(0, 1).join(',');
};
scope.placeMarker.setDraggable(true);
google.maps.event.addListener(scope.placeMarker, 'dragend', function () {
    //broadcast event to directive scope, and pass marker position
    scope.$broadcast('gmap-auto-complete:reverse', this.position);
});

Take a look please on "onReverseAddressComplete" callback. This callback fires each time if there are some results while searching by position (only for reverse). You just need define attribute in the directive element (on-reverse-address-complete="callback") and you can modify address string that will be displayed in the input.

jsfiddle example

Marker cluster

We don't provide any support for markers and clustering. If you want to use markers, please use standard google maps api (such as google.maps.Marker). See examples on top of this page (for markers creation).

Why we don't support this feature?

Because markers collection can be huge. And watching this collection by angular "$watch" can cause performance issues. So all markers staff rely on user.

Example

How to use clustering: At first you need include script "markerclusterer.js" (direct raw link)

Here is git reference

You can use bower install to get this library:

bower install js-marker-cluster

And then you can find this script in "src" folder!

here is examples page