Generate custom markers for Google Maps v3


I work in the same project with Google maps. New, version 3. New cards are good for everyone: there are fast ones, a nice design, and a cool client library for them. One problem is that the markers are single-color, but I need multi-colored. In this article we will solve this problem - we will make a small service that will render the repainted standard marker of the color we need.
The result, for the impatient, is available here .


Standard marker


image
The standard marker is taken by google maps at mt.googleapis.com/vt/icon/name=icons/spotlight/spotlight-poi.png&scale=2 (you can find this out using, for example, Firebug, by viewing the list of images uploaded by the page in the Network tab )
Depending on the scale parameter, the link returns images of different sizes:

scale
Image size
1
22px × 40px
2
44px × 80px
3
66px × 120px
4
88px × 160px


How to repaint a marker?


We will repaint the markers as follows:

  1. First, discolor the standard marker.


  2. Create a mask picture of the same size as the original marker, completely filled with the color in which we want to repaint the marker. These images will be a mask for blue.


  3. Apply a mask to the black and white image of the marker with overlap.


  4. And finally, let's restore transparency (by copying the alpha channel of the black and white marker).




Automation

It is most convenient to programmatically perform the image transformations we need to repaint the marker using the Imagemagick console utility package :
convert -size 88x160 xc:"#0000ff" mask.png # создаем маску
convert marker-bw.png  mask.png -compose Overlay -composite temp.png # накладываем оверлей
convert temp.png marker-bw.png -compose copy-opacity -composite ready.png # копируем альфа-канал


Server implementation


A server for uploading received images to the network is implemented on Node.js. Let's see how the request processing / getmarker? Scale = {size of the marker} & color = {HEX-code of the color of the marker} for receiving the marker with the given size and color occurs on it:

var colorRegexp = /^(?:[0-9a-f]{3}){1,2}$/i; //задаем регулярное выражение, по которому мы будем проверять правильность запрошенного цвета
var scales = ["22x40", "44x80", "66x120", "88x160"]; //создадим массив, описывающий доступные размеры маркера

app.get('/getmarker',function(req, res){

    //проверим переданный в метод цвет, либо установим цвет по умолчанию
    var color = req.query["color"];
    if (!color || !colorRegexp.test(color)){
        color = "f55850"
    } else {
        color.toLowerCase();
    }

    //проверим переданный в метод размер маркера, либо установим его по умолчанию
    var scale = req.query["scale"];
    var scale = new Number(req.query["scale"]);
    if (!scale){
        scale = 1;
    }
    scale--;
    if (scale < 0) scale = 0;
    if (scale > scales.length - 1) scale = scales.length - 1;
    
    //зададим имя файла, куда мы будем сохранять полученный маркер, чтобы не генерировать его заново при повторном запросе
    var filename = "./markers/marker-" + color + "-" + scale + ".png";

    fs.exists(filename, function(exists) {
        if (exists) {
            //если мы уже сгенерировали такой маркер, вернем готовую картинку
            console.log(filename + " exists, sended");
            res.sendfile(filename);
        } else {
            exec(
                //создаем цветовую маску
                'convert -size ' + scales[scale] + ' xc:#"' + color + '" mask' + color + scale +'.png \n' +
                //накладываем маску на черно-белое изображение маркера
                'convert marker-bw-' + scale + '.png  mask' + color + scale +'.png -compose Overlay -composite temp'  + color + scale +'.png \n' +
                //копируем прозрачность на временное изображение, полученное после оверлея
                'convert temp' + color + scale +'.png marker-bw-' + scale + '.png -compose copy-opacity -composite ' + filename,
                    console.log(filename + " created and sended");
                    res.sendfile(filename, function(){
                        //почистим мусор
                        exec('rm temp' + color + scale +'.png mask' + color + scale +'.png');
                    });
            );
        }
    });
});


Full code is available on GitHub .

Using markers on a Google map



The service is available at http://gmapsmarkergenerator.eu01.aws.af.cm . The markers themselves are gmapsmarkergenerator.eu01.aws.af.cm/getmarker?scale={ marker size} & color = {HEX marker color code}. How to use them on a map?
Consider an example running on the gmaps.js library :

var map = new GMaps({
    div: '#gmap',
    lat: 55.7722200,
    lng: 37.6155600,
    zoom: 11
});
map.addMarkers(
    [{
        "lat": "55.767293",
        "lng": "37.544298",
        "icon": "gmapsmarkergenerator.eu01.aws.af.cm/getmarker?scale=1&color=00ffff"
    },
    {
        "lat": "55.747215",
        "lng": "37.655428",
        "icon": "gmapsmarkergenerator.eu01.aws.af.cm/getmarker?scale=1&color=ff00ff"
    },
    {
        "lat": "55.741408",
        "lng": "37.629908",
        "icon": "gmapsmarkergenerator.eu01.aws.af.cm/getmarker?scale=1&color=ffff00"
    },
    {
        "lat": "55.799994",
        "lng": "37.618375",
        "icon": "gmapsmarkergenerator.eu01.aws.af.cm/getmarker?scale=1&color=ff0000"
    },
    {
        "lat": "55.730858",
        "lng": "37.561649",
        "icon": "gmapsmarkergenerator.eu01.aws.af.cm/getmarker?scale=1&color=00ff00"
    },
    {
        "lat": "55.800309",
        "lng": "37.639824",
        "icon": "gmapsmarkergenerator.eu01.aws.af.cm/getmarker?scale=1&color=0000ff"
    }]
);



As you can see, everything is very simple, you just need to specify the icon parameter for each marker.



Link to the
GitHub service