1

I've been working with some google maps recently, and I needed to rotate the icon for a map marker. I did some research, and came across This Answer.

Unfortunately, it's not working properly. It won't render the image I need. The URL produced by canvas.toDataURL is a blank image (of the correct size).

Here is the code:

var latlong0=new google.maps.LatLng(44.422036688671, -73.857908744819);    function initialize() {
  var mapOptions = {
    center: { lat: 44.422036688671, lng: -73.857908744819},
    zoom: 0
  };
  var map = new google.maps.Map(document.getElementById('map-canvas'),
      mapOptions);
  var airplane = 'img/airplane_icon.png';

  var infowindow0=new google.maps.InfoWindow({
      content: `
      <div>
        <p class='spectxt'>&lt;Flight #&gt;</p>
    <div style='font-size:10px;'>
          <p class='gentxtl'>Airline: <span class='acptxt'>Aero Test Ltd</span></p>
      <p class='gentxtl'>Aircraft: <span class='acptxt'>Boeing 717-200 HGW</span></p>
      <p class='gentxtl'>From: <span class='acptxt'>YYZ</span></p>
      <p class='gentxtl'>To: <span class='acptxt'>YHZ</span></p>
        </div>
      </div>
      `
    });

  var mark0=new google.maps.Marker({
    position: latlong0,
    map: map,
    title:'Aircraft',
    icon: {
            url: RotateIcon
                .makeIcon(
                    '/img/airplane_icon.png')
                .setRotation({deg: 78})
                .getUrl()
        }
  });
  mark0.setMap(map);mark0.addListener('click', function() {
      infowindow0.open(map, mark0);
    });    }
google.maps.event.addDomListener(window, 'load', initialize);

The RotateIcon code:

  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 || 50;
    this.options.height = this.options.height || this.rImg.height || 50;
    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');
};

The image is on the same domain as the web page, and both resources are regular http (no https). Chrome DevTools reports no warnings or errors. canvas.toDataURL outputs this

I'm using Chrome 48 on Windows 8.1

I've noticed something else odd with it. If I change the URL to /img/logo.png, it creates the image I want, but with the wrong sizing. canvas.toDataURL outputs this

-EDIT-
/img/airplane_icon.png can be found here
/img/logo.png can be found here

-EDIT 2-
So, I made a test page, and found it working.... So I went back to my first page, and noticed that if I have <img src="/img/airplane_icon.png"> after the map canvas, the page will work, but if I remove it, the page will not. Strange. For now I'm just going to add a display:none to the img, but does anyone know why the img has to be included for the page to work?

Community
  • 1
  • 1
Homberto
  • 165
  • 1
  • 4
  • 14
  • Please provide a [Minimal, Complete, Tested and Readable example](http://stackoverflow.com/help/mcve) that demonstrates the issue, including a copy of the icon you are using. If I take an airplane icon from the web, your code seems to work correctly for me ([fiddle](http://jsfiddle.net/geocodezip/wgh6ko6t/3/)). – geocodezip Feb 21 '16 at 06:54
  • I get a 404 for the airplane... – geocodezip Feb 21 '16 at 07:34
  • Fixed. Of course I used the wrong link in the edit. The code itself uses the correct link. – Homberto Feb 21 '16 at 17:26
  • [Your code as posted works for me](http://www.geocodezip.com/v3_SO_rotatePNGicon_orig.html). Please provide a [Minimal, Complete, Tested and Readable example](http://stackoverflow.com/help/mcve) that demonstrates the issue – geocodezip Feb 21 '16 at 18:39
  • There are issues in IE (surprize, surprize...), but they are invalid character (`) and unterminated string constant, which can be addressed. – geocodezip Feb 21 '16 at 20:14
  • Seems like a problem with the asynchronous load of the image if it is not already available in the cache. – geocodezip Feb 21 '16 at 20:25

1 Answers1

1

Seems like a problem with the asynchronous load of the image if it is not already available in the cache. One option to address that is to load the icon as a data URI:

var airplaneIcon = new RotateIcon({
  url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAgMAAABjUWAiAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABh0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC41ZYUyZQAAAAlQTFRF////AH8OAH8OqhPhTgAAAAJ0Uk5TADqwnxSKAAAAZ0lEQVQoz2NgoCJQQOYwrkTmMa0aijy2VQ5IvKxVS5ClViFJZgF5S5ClEJJZYN4SZCmYpBaUtwDGm7RKCsGbAHSLFIw3AewyqQUD5XepVRNwhQTjqlUrcYULF5DXgOAtYchqoF5yAwBuvj9B9E9ozgAAAABJRU5ErkJggg==',
  height: 50,
  width: 50
})
var mark0 = new google.maps.Marker({
  position: latlong0,
  map: map,
  title: 'Aircraft',
  icon: {
  // size: new google.maps.Size(128, 128),
    scaledSize: new google.maps.Size(20, 20),
    anchor: new google.maps.Point(10, 10),
    url: airplaneIcon.setRotation({
        deg: 78
    })
    .getUrl()
  }
});

proof of concept fiddle

code snippet:

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 || 50;
  this.options.height = this.options.height || this.rImg.height || 50;
  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');
};

var map;
var latlong0 = new google.maps.LatLng(44.422036688671, -73.857908744819);

function initialize() {
  var mapOptions = {
    center: {
      lat: 44.422036688671,
      lng: -73.857908744819
    },
    zoom: 5
  };
  map = new google.maps.Map(document.getElementById('map-canvas'),
    mapOptions);
  var airplane = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAgMAAABjUWAiAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABh0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC41ZYUyZQAAAAlQTFRF////AH8OAH8OqhPhTgAAAAJ0Uk5TADqwnxSKAAAAZ0lEQVQoz2NgoCJQQOYwrkTmMa0aijy2VQ5IvKxVS5ClViFJZgF5S5ClEJJZYN4SZCmYpBaUtwDGm7RKCsGbAHSLFIw3AewyqQUD5XepVRNwhQTjqlUrcYULF5DXgOAtYchqoF5yAwBuvj9B9E9ozgAAAABJRU5ErkJggg==';

  var infowindow0 = new google.maps.InfoWindow({
    content: `
      <div>
        <p class='spectxt'>&lt;Flight #&gt;</p>
    <div style='font-size:10px;'>
          <p class='gentxtl'>Airline: <span class='acptxt'>Aero Test Ltd</span></p>
      <p class='gentxtl'>Aircraft: <span class='acptxt'>Boeing 717-200 HGW</span></p>
      <p class='gentxtl'>From: <span class='acptxt'>YYZ</span></p>
      <p class='gentxtl'>To: <span class='acptxt'>YHZ</span></p>
        </div>
      </div>
      `
  });
  var airplaneIcon = new RotateIcon({
    url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAgMAAABjUWAiAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAOwgAADsIBFShKgAAAABh0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMC41ZYUyZQAAAAlQTFRF////AH8OAH8OqhPhTgAAAAJ0Uk5TADqwnxSKAAAAZ0lEQVQoz2NgoCJQQOYwrkTmMa0aijy2VQ5IvKxVS5ClViFJZgF5S5ClEJJZYN4SZCmYpBaUtwDGm7RKCsGbAHSLFIw3AewyqQUD5XepVRNwhQTjqlUrcYULF5DXgOAtYchqoF5yAwBuvj9B9E9ozgAAAABJRU5ErkJggg==',
    height: 50,
    width: 50
  })
  var mark0 = new google.maps.Marker({
    position: latlong0,
    map: map,
    title: 'Aircraft',
    icon: {
      // size: new google.maps.Size(128, 128),
      scaledSize: new google.maps.Size(20, 20),
      anchor: new google.maps.Point(10, 10),
      url: airplaneIcon.setRotation({
          deg: 78
        })
        .getUrl()
    }
  });
  mark0.setMap(map);
  mark0.addListener('click', function() {
    infowindow0.open(map, mark0);
  });
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map-canvas {
  height: 100%;
  width: 100%;
  margin: 0px;
  padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id="map-canvas"></div>
geocodezip
  • 158,664
  • 13
  • 220
  • 245