32

How could I rotate an image (marker image) on a Google map V3?

  • There is an excellent example for V2 here, exactly doing what I need. But for GMap2! They do it with a rotating canvas.
  • Image rotating with JS / JQuery is frequently used, there are multiple answers about this. But how could I apply this to my maps image?
  • One mentioned approach is to have different images for different angles and to switch among them - this is NOT what I want. I do not like to have so many images, I want to rotate by code.

Remark: There are similar questions, but all for V2 and not V3 (as far I can tell). I need it for V3.

Horst Walter
  • 13,663
  • 32
  • 126
  • 228

17 Answers17

20

My js class for solving this problem is:

var RotateIcon = function(options){
    this.options = options || {};
    this.rImg = options.img || new Image();
    this.rImg.src = this.rImg.src || this.options.url || '';
    this.options.width = this.options.width || this.rImg.width || 52;
    this.options.height = this.options.height || this.rImg.height || 60;
    var canvas = document.createElement("canvas");
    canvas.width = this.options.width;
    canvas.height = this.options.height;
    this.context = canvas.getContext("2d");
    this.canvas = canvas;
};
RotateIcon.makeIcon = function(url) {
    return new RotateIcon({url: url});
};
RotateIcon.prototype.setRotation = function(options){
    var canvas = this.context,
        angle = options.deg ? options.deg * Math.PI / 180:
            options.rad,
        centerX = this.options.width/2,
        centerY = this.options.height/2;

    canvas.clearRect(0, 0, this.options.width, this.options.height);
    canvas.save();
    canvas.translate(centerX, centerY);
    canvas.rotate(angle);
    canvas.translate(-centerX, -centerY);
    canvas.drawImage(this.rImg, 0, 0);
    canvas.restore();
    return this;
};
RotateIcon.prototype.getUrl = function(){
    return this.canvas.toDataURL('image/png');
};

Call it like this:

var marker = new google.maps.Marker({
    icon: {
        url: RotateIcon
            .makeIcon(
                'https://ru.gravatar.com/userimage/54712272/b8eb5f2d540a606f4a6c07c238a0bf40.png')
            .setRotation({deg: 92})
            .getUrl()
    }})

See live example here http://jsfiddle.net/fe9grwdf/39/

Christiaan Westerbeek
  • 10,619
  • 13
  • 64
  • 89
ErDmKo
  • 593
  • 4
  • 10
  • @ErDmKo: Tried to use it with external image as specified but doesn't seem to work. http://jsfiddle.net/fe9grwdf/42/ – Mrudang Vora Feb 09 '16 at 09:43
  • @MrudangVora i have now seme error "Image from origin 'https://ru.gravatar.com' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://fiddle.jshell.net' is therefore not allowed access." and it means we need something like this http://humaan.com/custom-html-markers-google-maps/ in case when we have external image – ErDmKo Feb 10 '16 at 09:45
  • 3
    Thank you for this snippet. But note that the browser loads asynchronously so it is possible that you call `getUrl()` before the image is loaded and you have a blank marker. `setRotation` and `getUrl` should be wrapped in promises to solve this. – Clint Aug 29 '17 at 14:17
  • Great solution, I just had to add a listener to await `rImg.onload` before `canvas.drawImage` would work. – Duncan Lukkenaer Nov 23 '20 at 13:20
  • Hw should i do setRotation and getUrl wrapped in promises in react? please help me – Chathuranga Kasthuriarachchi Dec 31 '20 at 10:02
11

I have found two extensions to the Google MAP V3: infobox.js and markerwithlabel.js Both can handle an image DOM element as content, which in turn I can rotate via the jQuery image rotate plugin.

This even works without setting the marker's image again after rotation.

Edit: As of questions / comments below:

The extension for label is required, because it can handle other DOM elements. So I can add arbitrary HTML as label, in my particular case I add the image. And then I do rotate this image (child of the label) with the rotate plugin. So assign the image an id in order to easily access it. Actually I am using one label just for the image, and another for descriptive text.

Edit 2: Due to Stephan's comment on the DOM readiness

In my code I have found the following lines. This shows that I force a draw on the label before rotating the image.

    if (!this._drawn) myImageLabel.draw(); // 1st time force a draw, otherwise rotating the image will fail because an asynchronously drawn object has not all tags in place
    if (this.heading != 0) this.rotateImage(this.heading, true);

Edit 3: Code example how to create the Infobox.js

this._img = document.createElement('img');
... further manipulations of _img / Size / Id / ...
var planeImageLabelOptions = {
            content: this._img,
            disableAutoPan: true,
            boxStyle: planeImageLabelBoxStyle,
            pixelOffset: new google.maps.Size(-imgOffsetW / 2, -imgOffsetH / 2),
            closeBoxURL: "",
            position: latlng,
            zIndex: this.altitude < 0 ? 100 : this.altitude
 };
 var planeImageLabel = new InfoBox(planeImageLabelOptions);
Horst Walter
  • 13,663
  • 32
  • 126
  • 228
  • Could you give a coded example of how you might achieve this with the aforementioned extensions and plugin? – hitautodestruct Dec 13 '11 at 09:09
  • Rotating image: $(img).rotate(degrees); See the extension's docu for "how to add a DOM element as label", just create the DOM element and rotate it. – Horst Walter Dec 16 '11 at 22:58
  • i've tried to do this with markerwithlable.js but the jquery just cant grab the object. If i set labelClass: "label" then $('.label').rotate(30); nothing happens... what exactly are you doing to make the thing rotate? thanks – user1051849 Oct 03 '12 at 13:20
  • I have this label, the label contains the image (as HTML img), but I do rotate the image DOM element, not the label element => $(image).rotate(30). – Horst Walter Oct 05 '12 at 11:12
  • so instead of supplying a marker icon and a label you put everything inside the label? – Stephan Oct 22 '12 at 14:09
  • That's the trick. The extension for label is required, because it can handle other DOM elements. So I can add arbitrary HTML as label, in my particular case I add the image. And then I do rotate this image (child of the label) with the rotate plugin. – Horst Walter Oct 22 '12 at 15:09
  • 2
    when do you rotate the image? I mean, do you do something like the following? `var marker = new MarkerWithLabel({ position: p, map: map, labelContent: "some html with "}); $("#myimg").rotate(35);` Because I tried in this way, but it doesn't work (cause the dom hasn't been modified yet to insert the image). Any hint on this? I'm using jQM. (although perhaps all this is a different question...) – Stephan Oct 23 '12 at 12:19
  • Yes I do. I have a comment in my code, showing that I have basically faced the same issue. I have explicitly forced a draw on the label (can only check the code, not really what it does right now), then I have rotated the image. Will insert this hint above as well. – Horst Walter Oct 23 '12 at 13:17
  • This is my entity which contains the data. It has a display method, which draws itself onto the map. In "this" display does the following. Create label (as in your code), call draw on label, then rotate label. The rotate is encapsulated in a method only doing some checks, it is equivalent to your $("#myimg").rotate(35); – Horst Walter Oct 23 '12 at 15:12
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/18483/discussion-between-stephan-and-horst-walter) – Stephan Oct 23 '12 at 15:32
  • I made a mistake above on your comment, I am using Infobox.js for the image, and Infobox.js has the draw method. All the rest is true. – Horst Walter Oct 23 '12 at 20:33
  • 1
    For whoever is still stuck with rotating the icon because of the too-soon call of "rotate", there is a way I found, by making a callback when the googlemaps is loaded. See http://stackoverflow.com/questions/13947566/how-can-i-put-an-alert-after-loading-google-map – Jonathan Bibas Nov 11 '14 at 23:36
10

I also had a hard time to figure out the way to rotate .png marker. I solved it like below. You can create many markers with same custom image and rotate a specific marker you want to rotate. I hope it helpful to you.

var id = 'my_marker_01';
var img_url = "../img/car.png";
var my_icon = img_url + "#" + id;
var marker = new google.maps.Marker({
    icon: my_icon,
    ...
});

var rotate = 45;
$(`img[src="${my_icon}"]`).css(
    {'-webkit-transform' : 'rotate('+ rotate +'deg)',
       '-moz-transform' : 'rotate('+ rotate +'deg)',
       '-ms-transform' : 'rotate('+ rotate +'deg)',
       'transform' : 'rotate('+ rotate +'deg)'}); 
swj
  • 111
  • 1
  • 6
7

How could I rotate an image (marker image) on a Google map V3?

I had the same problem and I solved it with the next code:

var gmap;
NgMap.getMap(function(map){
    gmap = map;
});

I suppose that you have a variable with the icon, for example:

var imagePath = 'img/customMarker.png';

First, we need to create our marker options:

var markerOptions = {
    location: [x, y],
    title:'some text',
    draggable: true,
    .
    .
    .
    icon: imagePath
};

Let's create a marker:

var marker = new google.maps.Marker(markerOptions);

And we have to set the map:

marker.setMap(map);

Now if you want to rotate the image you need to do the next:

  • Change the imagePath variable's value to 'img/customMarker.png#yourId'
  • Set rotation value with css (e.g. with JQuery)

Let's see

imagePath = 'img/customMarker.png#markerOne';

$('img[src="img/customMarker.png#markerOne"]').css({
     'transform': 'rotate(45deg)'
});

Of course you can do it fancier:

function rotateMarker(selector, degree){
     $('img[src="img/customMarker.png#'+selector+'"]').css({
         'transform': 'rotate('+degree+'deg)'
     });
}

And your call:

rotateMarker('markerOne', 45);

That's all.

I hope it could be helpful.

varun kalra
  • 213
  • 2
  • 7
  • 1
    I'm sorry, i forgot something: we need an additional property in our markerOptions variable: var markerOptions = { location: [x, y], title:'some text', draggable: true, . . . icon: imagePath, optimized:false }; – Jesus Gilberto Valenzuela Dec 11 '15 at 00:30
  • Probably this is not safe. Possible that the image is not yet in the map since something is happening asynchronously. – Ethan Oct 18 '17 at 19:26
  • The only problem I have found with this is being able to rotate that marker after the fact https://stackoverflow.com/questions/68877756/google-maps-js-custom-marker-image – exceptionsAreBad Aug 25 '21 at 10:30
  • I have found a solution to the clipping when you use this answer. See my solution at https://stackoverflow.com/questions/68877756/google-maps-js-custom-marker-image – exceptionsAreBad Aug 29 '21 at 17:36
5

I have done the rotation in v3 with the following code:

<canvas id="carcanvas" width="1" height="1"></canvas>


    if (document.getElementById('carcanvas').getContext) {
        var supportsCanvas = true;
    } else {
        var supportsCanvas = false;
    }

    var rImg = new Image();
    rImg.src='/images/cariconl.png';

    // Returns the bearing in radians between two points.
    function bearing( from, to ) {
        // Convert to radians.
        var lat1 = from.latRadians();
        var lon1 = from.lngRadians();
        var lat2 = to.latRadians();
        var lon2 = to.lngRadians();
        // Compute the angle.
        var angle = - Math.atan2( Math.sin( lon1 - lon2 ) * Math.cos( lat2 ), Math.cos( lat1 ) * Math.sin( lat2 ) - Math.sin( lat1 ) * Math.cos( lat2 ) * Math.cos( lon1 - lon2 ) );
        if ( angle < 0.0 )
            angle  += Math.PI * 2.0;
        if (angle == 0) {angle=1.5;}
        return angle;
    }

    function plotcar() {
        canvas = document.getElementById("carcanvas").getContext('2d');
        var cosa = Math.cos(angle);
        var sina = Math.sin(angle);
        canvas.clearRect(0,0,32,32);
        canvas.save();
        canvas.rotate(angle);
        canvas.translate(16*sina+16*cosa,16*cosa-16*sina);
        canvas.drawImage(rImg,-16,-16);
        canvas.restore();
    }

and in the animation method :

if (supportsCanvas) {
                    angle = bearing(new google.maps.LatLng(lat1, lng1),new google.maps.LatLng(lat2, lng2));
                    plotcar();
                }

I hope that help.

Muhammad Alaa
  • 608
  • 1
  • 10
  • 15
  • hi, thank I can rotate my png image but after rotated around a pic have a black background, how to a transparent background? – Amir Farahani Sep 14 '20 at 12:09
5

You did not state it in your question, but I am assuming that you want this rotation in relation to a line between point a and point b, which would be their path. In order to make a google svg icon that can be rotated, you will want to use the google symbol class object to define the properties of your marker symbol. This does not use a full .svg file, but only the d attribute of the path. Note that the google symbol class can only take one path per marker.

Additional attributes for color, stroke, width, opacity, etc. may be set after the marker has been created with javascript (updating the marker object properties directly), or with CSS (updating the marker properties by adding and removing classes).

As an example, the following will create an arrow marker that can be dragged, and it will be rotated around the point on the map that is the lat and long for the marker even after it is moved.

The HTML

<body id="document_body" onload="init();">
  <div id="rotation_control">
    Heading&deg;<input id="rotation_value" type="number" size="3" value="0" onchange="setRotation();" />
  </div>
  <div id="map_canvas"></div>
</body>

The CSS (yes,verbose... I hate ugly)

#document_body {
    margin:0;
    border: 0;
    padding: 10px;
    font-family: Arial,sans-serif;
    font-size: 14px;
    font-weight: bold;
    color: #f0f9f9;
    text-align: center;
    text-shadow: 1px 1px 1px #000;
    background:#1f1f1f;
  }
  #map_canvas, #rotation_control {
    margin: 1px;
    border:1px solid #000;
    background:#444;
    -webkit-border-radius: 4px;
       -moz-border-radius: 4px;
            border-radius: 4px;
  }
  #map_canvas { 
    width: 100%;
    height: 360px;
  }
  #rotation_control { 
    width: auto;
    padding:5px;
  }
  #rotation_value { 
    margin: 1px;
    border:1px solid #999;
    width: 60px;
    padding:2px;
    font-weight: bold;
    color: #00cc00;
    text-align: center;
    background:#111;
    border-radius: 4px;
  }

The Javascript (in plain vanilla flavor for understanding core concepts)

var map, arrow_marker, arrow_options;
var map_center = {lat:41.0, lng:-103.0};
var arrow_icon = {
  path: 'M -1.1500216e-4,0 C 0.281648,0 0.547084,-0.13447 0.718801,-0.36481 l 17.093151,-22.89064 c 0.125766,-0.16746 0.188044,-0.36854 0.188044,-0.56899 0,-0.19797 -0.06107,-0.39532 -0.182601,-0.56215 -0.245484,-0.33555 -0.678404,-0.46068 -1.057513,-0.30629 l -11.318243,4.60303 0,-26.97635 C 5.441639,-47.58228 5.035926,-48 4.534681,-48 l -9.06959,0 c -0.501246,0 -0.906959,0.41772 -0.906959,0.9338 l 0,26.97635 -11.317637,-4.60303 c -0.379109,-0.15439 -0.812031,-0.0286 -1.057515,0.30629 -0.245483,0.33492 -0.244275,0.79809 0.0055,1.13114 L -0.718973,-0.36481 C -0.547255,-0.13509 -0.281818,0 -5.7002158e-5,0 Z',
  strokeColor: 'black',
  strokeOpacity: 1,
  strokeWeight: 1,
  fillColor: '#fefe99',
  fillOpacity: 1,
  rotation: 0,
  scale: 1.0
};

function init(){
  map = new google.maps.Map(document.getElementById('map_canvas'), {
    center: map_center,
    zoom: 4,
    mapTypeId: google.maps.MapTypeId.HYBRID
  });
  arrow_options = {
    position: map_center,
    icon: arrow_icon,
    clickable: false,
    draggable: true,
    crossOnDrag: true,
    visible: true,
    animation: 0,
    title: 'I am a Draggable-Rotatable Marker!' 
  };
  arrow_marker = new google.maps.Marker(arrow_options);
  arrow_marker.setMap(map);
}

function setRotation(){
  var heading = parseInt(document.getElementById('rotation_value').value);
  if (isNaN(heading)) heading = 0;
  if (heading < 0) heading = 359;
  if (heading > 359) heading = 0;
  arrow_icon.rotation = heading;
  arrow_marker.setOptions({icon:arrow_icon});
  document.getElementById('rotation_value').value = heading;
}

And the best yet, doing it this way assures the marker is a Google MVC object, giving it all the additional methods provided by the MVC object.

If you must have multi-colored images as your marker, then creating a .png sprite sheet with a rendition of the image at all the angles you want it to be shown, and then problematically select the correct image to use based on the computed bearing between the two points you are using. However,this would not be an SVG image, but a regular marker image.

Hope this helps in making some decisions regarding your map markers.

Epiphany
  • 1,886
  • 1
  • 20
  • 14
  • It doesn't seem to do anything to set rotation as a property of icon, both as an update to icon / options.icon, or in the construction of the marker. – Ethan Oct 18 '17 at 19:31
  • I think this is the only correct answer here. Simply put, update the rotation in the marker icon options hash, then use the `setOptions` method on the marker to set the icon to the updated hash. That's it. – Michael Chaney Jun 13 '19 at 03:24
5

Nobody mentioned about using pre-rotated icons. Depending on your application, you could take one icon and rotate it +10 degrees, +20 degrees ... +350 degrees and instead of rotating marker itself, just assign different icon to it - one out of 36 if 10 degrees resolution is good enough. That's also very light on client's resources.

In the example below I generated 36 icons, every one of them is 10 degrees rotated. Their names are: icon0.png, icon10.png, icon20.png, ... icon340.png, icon350.png, icon360.png. The 0 and 360 are the very same icon (e.g symlink)

var rotation = 123 // degrees
var iconName = "icon" + (Math.round(rotation/10)*10).toString() + ".png"
var marker = new google.maps.Marker({
    icon: iconName
})
Ryan Tapel
  • 119
  • 2
  • 7
3

I was able to solve this pretty easily but using the marker.icon.rotation option pointing to a custom symbol that uses the svg path syntax.

$scope.triangle = {
  path: 'M 0 0 L -35 -100 L 35 -100 z',
  fillColor: '#3884ff',
  fillOpacity: 0.7,
  scale: 1,
  strokeColor: '#356cde',
  rotation: 90,
  strokeWeight: 1

}; 

If using angular-google-maps it is trivial to bind a ui control to change the triangle.rotation.

Like I did with this slider.

<slider  ng-model="triangle.rotation" floor="0" ceiling="359" step="5" precsion="1"></slider>

But you could use a forum too.

here is my plunker http://plnkr.co/edit/x0egXI

3

This is how i implemented my image rotated, I considered the marker in the form of overlay and that overlay is position to the position, Below code will be added .

Without using any additional library it is rotated,And you need to workaround to add click events and mouse events for the overlay, not similar to marker click events.

With googleMap markers customization, there will be addition memory usage in the map. This will also reduce the memory consumption of custom markers in your map.

 <html>
    <head>
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
    <style>html, body {
        height: 100%;
        margin: 0;
        padding: 0;
    }
    #map_canvas {
        height: 100%;
    }
    div.htmlMarker {
        color: red;
        cursor: pointer;
    }

    </style>
    </head>
    <body onload="initialize()">
        <div id="map_canvas"></div>
    </body>

    <script>
    var overlay;

    function initialize() {
        var myLatLng = new google.maps.LatLng(40, -100);
        var mapOptions = {
            zoom: 10,
            center: myLatLng,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        };

        var gmap = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);

        function HTMLMarker(lat, lng, rotation) {
            this.lat = lat;
            this.lng = lng;
             this.rotation = rotation;
            this.pos = new google.maps.LatLng(lat, lng);
        }

        HTMLMarker.prototype = new google.maps.OverlayView();
        HTMLMarker.prototype.onRemove = function () {}

        //Initilize your html element here
        HTMLMarker.prototype.onAdd = function () {
            div = document.createElement('DIV');
            div.style.position='absolute';
            div.style.transform='rotate('+this.rotation +'deg)';
            div.style.MozTransform='rotate('+this.rotation +'deg)';
            div.className = "htmlMarker";
           //image source use your own image in src
            div.innerHTML = '<img src="prudvi.png" alt="Mountain View" style="width:25px;height:22px">' ;
            var panes = this.getPanes();
            panes.overlayImage.appendChild(div);
            this.div=div;
        }

        HTMLMarker.prototype.draw = function () {
            var overlayProjection = this.getProjection();
            var position = overlayProjection.fromLatLngToDivPixel(this.pos);
            var panes = this.getPanes();
            this.div.style.left = position.x + 'px';
            this.div.style.top = position.y - 30 + 'px';
        }

        //Added 50 marker with random latlng location and random rotation,
        for (i = 0; i < 50; i++) {
        var PoslatLng = new google.maps.LatLng(myLatLng.lat() + Math.random() - 0.5, myLatLng.lng() + Math.random() - 0.5);
        var htmlMarker = new HTMLMarker(myLatLng.lat() + Math.random() - 0.5,myLatLng.lng() + Math.random() - 0.5, Math.floor(Math.random() * 359));
        htmlMarker.setMap(gmap);
    google.maps.event.addListener(htmlMarker, 'click', function() {
        console.log('clciked')
        gmap.setZoom(8);
        gmap.setCenter(htmlMarker.getPosition());
      });
        }
    }
    </script>
  </html>
prudvi raju
  • 505
  • 1
  • 5
  • 19
2

The easiest way may be to use the rotation property of google.maps.Symbol. Just set it as a property of your icon when creating or updating your marker:

new google.maps.Marker({
  position: map.getCenter(),
  icon: {
    path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW,
    scale: 7,
    rotation: 193
  },
  map: map
});

Plunker

Codebling
  • 10,764
  • 2
  • 38
  • 66
  • Not 100% sure but rotation seems to do nothing for me. I believe it only works for svg type icons. – Ethan Oct 18 '17 at 19:32
2

The idea is to first draw the rotated marker image on a hidden canvas.

Say, you have a hidden canvas:

<canvas id="carCanvas" width="50" height="50" style="display:none"></canvas>

Now you can do this:

function updateCarMarker(i,lat, lng, icon = "img/carIcon.png") {
    var latLong = new google.maps.LatLng(lat, lng);
    if (!carMarkers[i]){
        var carImage = new Image();
        carImage.onload = ()=>{
            drawMovedCar(i,latLong,carImage);
        }
        carImage.src=icon;
    } else {
        drawMovedCar(i,latLong,carMarkers[i].carImage);
    }
}

function drawMovedCar(i,latLong,I){
    let m=carMarkers[i];
    let canvas = document.getElementById("carCanvas");
    let C = canvas.getContext('2d');
    if (m){
        var distance = google.maps.geometry.spherical.computeDistanceBetween(
                                                               m.getPosition(), latLong);
        var deg = (distance<2)?carMarkers[i].deg
                              :google.maps.geometry.spherical.computeHeading(m, latLong);
        carMarkers[i].setMap(null);
     } else {
        var deg=0;
     }
    C.save();
        C.clearRect(0, 0, canvas.width, canvas.height);
        C.translate(canvas.width/2,canvas.height/2);
        C.rotate(deg * Math.PI / 180);
        C.scale(0.4,0.4);
        C.drawImage(I,-I.width/2,-I.height/2,I.width,I.height);           
    C.restore();
    if (!m){
        m = new google.maps.Marker({
            position: latLong,
            map: map,
            icon: canvas.toDataURL("image/png",1)
        });
        m.deg = deg;
        m.carImage = I;
        carMarkers[i]=m;  
    } else {
        m.setIcon(canvas.toDataURL("image/png",1));
        m.setPosition(latLong);
    }
}

The above is my original code. I have left it intact so that you can see my other optimizations.

Chong Lip Phang
  • 8,755
  • 5
  • 65
  • 100
2

You could call the yourmarker.setIcon(canvas.toDataUrlOrSomeThig) every time the image changes. I don't see anything in the api reference for using the canvas element directly, except if you implement you own google.maps.OverlayView.

If you only want animation you could use a gif, and add the marker option optimized: false to it.

Gerben
  • 16,747
  • 6
  • 37
  • 56
  • I did not know this toDataUrl function, but found this one here (http://stackoverflow.com/questions/934012/get-image-data-in-javascript) - will try whether the marker will really recognize this. - nice idea – Horst Walter Jul 23 '11 at 15:47
  • Use canvas.toDataURL("image/png"); don't remove the 'date:...' part like in your link. – Gerben Jul 23 '11 at 15:55
  • At least in IE9 I get "object does not support method or property". Code: var canv = document.getElementById("c"); var u = canv.toDataURL("image/png"); and in HTML: Plane – Horst Walter Jul 25 '11 at 13:46
  • Obviously this is not my very own problem, see http://stackoverflow.com/questions/633724/internet-explorer-todataurl-alternative Unfortunately this renders this (nice) approach invalid for my scenario. Thanks anyway, good hint. – Horst Walter Jul 25 '11 at 13:56
1

Using MarkerWithLabel Library, you can achieve that in such way:

var ico = document.createElement('img');
ico.src = 'ImageSource';
ico.setAttribute('style', 'transform:rotate('30deg);');
mapMarkers[0].labelContent = ico;
mapMarkers[0].label.draw();
lelODude
  • 11
  • 1
  • 1
1

Assuming you only use that image within Google Maps, you can do the following

bearing = 20

document.querySelectorAll('img[src="/images/imageName"]').forEach((node) => {

    node.style['transform'] = `rotate(${bearing}deg)`
    node.style['webkitTransform'] = `rotate(${bearing}deg)`
    node.style['MozTransform'] = `rotate(${bearing}deg)`
    node.style['msTransform'] = `rotate(${bearing}deg)`
    node.style['OTransform'] = `rotate(${bearing}deg)`
})

This reaches down the dom tree and sets the transform for the marker icon to rotate the degrees you want. The image imageName should be facing North

Not to sure if the webkit, Moz, ms and O version are needed but hey ‍♂️ cant hurt

N Kuria
  • 153
  • 1
  • 5
1

If you are using SVG, Then this is the best way to rotate it.

let marker_, svg_, size_ = 100, rotation_ = 50


// Get SVG
fetch('https://upload.wikimedia.org/wikipedia/commons/7/78/Space-shuttle.svg')
.then(response => response.text())
.then(text => {
  svg_ = text;
  svg_ = svg_
    .replace(/^<\?(.+)\?>$/gm, '') // unsupported unnecessary line
    // You can replace anything you want, but first of all check your svg code
    .replace(/width.+\Wheight\S+/, 
      'width="{{width}}" height="{{height}}" transform="{{transform}}" ')
    
  // Load Map
  initMap()
})

function getIcon(rotation){
return {url:`data:image/svg+xml;charset=utf-8,
      ${encodeURIComponent(svg_
      .replace('{{width}}', 100)
      .replace('{{height}}', 100)
      .replace('{{transform}}', `rotate(${rotation},0,0)`))}`,anchor: new google.maps.Point(50, 50),
      origin: new google.maps.Point(0, 0)}

}


// Map
function initMap() {
  const position = {lat: 36.720426, lng: -4.412573};
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 19,
    center: position
  })
  marker_ = new google.maps.Marker({
    position: position,
    map: map,
    icon: getIcon(rotation_)
  })
}

// Change rotation
$input_ = document.querySelector('input')
$input_.value = rotation_
$input_.onchange = () => {
  marker_.setIcon(getIcon(parseInt($input_.value))
  )
} 
* {
  padding: 0;
  margin: 0;
}

#map {
  width: 100%;
  height: 100vh;
}

input {
  position: fixed;
  z-index: 1;
  margin: 100px;
  padding: 10px;
  border-radius: 2px;
  background-color: red;
  border: none;
  color: white;
  font-family: 'Roboto';
  width: 70px;
}
<script src="https://maps.google.com/maps/api/js"></script>
<input type="number" placeholder="rotation">
<div id="map"></div>
Sami Al-Subhi
  • 4,406
  • 9
  • 39
  • 66
0

I have found an easy way to rotate the png image marker for the google marker. Create an custom marker overriding google.maps.OverlayView and rotate the image simply with css/inline style

export const createCustomMarker = ({ OverlayView = google.maps.OverlayView, ...args }) => {

class GoogleMarker extends OverlayView {

    options: any = {};
    div: any = null;
    innerHtml: any = null;

    constructor(options) {
        super();
        this.options = options;
        this.setMap(options.map);
    }

    createDiv() {
        const options = this.options;
        this.div = document.createElement('div');
        this.div.style.position = 'absolute';
        this.setRotation(this.options.rotation);
        if (options.icon) {
            this.setInnerHtml(this.getInnerImageHtml(options));
        }
    }

    getInnerImageHtml(options) {
        const size = this.getSize(options);
        const label = this.options.label;
        const labelHtml = label ? `<span style="color:black;margin-left: -40px;width: 100px;text-align: center;display: block;font-weight:bold;">${label}</span>` : "";
        return `<img style="height:${size.height}px;width:${size.width}px" id="${options.id || ''}" src="${options.icon}">${labelHtml}`;
    }

    addListeners() {
        const self = this;
        google.maps.event.addDomListener(this.div, 'click', event => {
            google.maps.event.trigger(self, 'click');
        });

        this.div.onmouseenter = function () {
            debugger
            google.maps.event.trigger(self, 'onmouseenter');
        }

        this.div.onmouseover = function () {
            google.maps.event.trigger(self, 'onmouseover');
        }

        this.div.onmouseleave = function () {
            google.maps.event.trigger(self, 'onmouseleave');
        }

        this.div.onmouseout = function () {
            google.maps.event.trigger(self, 'onmouseout');
        }
    }

    appendDivToOverlay(appendDiv: any) {
        const panes: google.maps.MapPanes = this.getPanes();
        panes.floatPane.appendChild(appendDiv);
    }

    setRotation(degrees: number) {
        if (this.div) {
            this.div.style.transform = 'rotate(' + degrees + 'deg)';
        }
        this.options.rotation = degrees;
    }

    getRotation() {
        return this.options.rotation;
    }

    setInnerHtml(html: string) {
        this.innerHtml = html;
        this.div.innerHTML = this.innerHtml;
    }

    private positionDiv(div: any, options: any) {
        if (div != null) {
            const point = this.getProjection().fromLatLngToDivPixel(options.latlng);
            if (point) {
                const size = this.getSize(options);
                const anchor = options.anchor ? options.anchor : new google.maps.Point((size.width / 2), (size.height / 2))
                const leftAnchor = anchor.x;
                const topAnchor = anchor.y;
                div.style.left = `${point.x - leftAnchor}px`;
                div.style.top = `${point.y - topAnchor}px`;
            }
        }
    }

    private getSize(options) {
        const size = options.size || { height: 52, width: 52 };
        return size;
    }

    draw() {
        if (!this.div) {
            this.createDiv();
            this.appendDivToOverlay(this.div);
            this.addListeners();
        }
        this.positionDiv(this.div, this.options);
    }

    remove() {
        if (this.div) {
            this.div.parentNode.removeChild(this.div);
            this.div = null;
        }
    }

    setVisible(value: boolean) {
        if (this.div) {
            this.div.style["display"] = value ? "block" : "none";
        }
    }

    getVisible() {
        if (this.div) {
            return this.div.style["display"] == "none";
        }
        return false;
    }

    setPosition(position) {
        this.options.latlng = position;
        this.infoOptions.latlng = position;
        this.positionDiv(this.div, this.options);
    }

    getPosition() {
        return this.options.latlng;
    }

    getDraggable() {
        return false;
    }

    isHTML(html: string) {
        return /<([A-Za-z][A-Za-z0-9]*)\b[^>]*>(.*?)<\/\1>/.test(html);
    }
}
return new GoogleMarker(args)

}

After creating this custom marker - Initialize the marker in the following way

import { createCarMarker } from "./marker.component"; // dynamic path to component

let marker = createCarMarker({
        id: id, // will add id to the parent container div
        latlng: new google.maps.LatLng(0, 0), // replace latitude-longitude with your values
        map: this.map,
        size: new google.maps.Size(52, 52), // replace the image size with your values
        rotation: markerData.direction, // Provide values in degrees
        icon: iconUrl, // Replace it with your image url
        label: markerLabel // Provide marker label. Optional field
    });

Now simply rotate the marker using the following method

marker.setRotation(180); // You just need to call only this method every-time the degrees changes.

To listen the changes on the marker.

google.maps.event.addDomListener(marker, 'click', function (event) {

    });

    google.maps.event.addListener(marker, 'onmouseenter', function (event) {

    });

    google.maps.event.addListener(marker, 'onmouseleave', function (event) {

    });

    google.maps.event.addListener(marker, 'onmouseover', function (event) {

    });

    google.maps.event.addListener(marker, 'onmouseout', function (event) {

    });

You can customize the listeners or add new/update in the custom marker class according to your requirement.

Sumit Kumar
  • 249
  • 1
  • 7
-1
var icon = {
   path: aeroplanePath/image,
   fillColor: '#0000FF',
   fillOpacity: .6,
   anchor: new google.maps.Point(0,0),
   strokeWeight: 0,
   scale: 1,
   rotation: 180
}


var marker = new google.maps.Marker({
   position: positions[k],
   icon: icon,
   draggable: true,
   title: "BOING-707",    
});
Dave Cousineau
  • 12,154
  • 8
  • 64
  • 80
Chandu D
  • 505
  • 3
  • 17
  • 1
    Icon doesn't support rotation: https://developers.google.com/maps/documentation/javascript/3.exp/reference#Icon – PanMan Jan 11 '17 at 15:39