簡體   English   中英

帶有多個圖標的 Google Maps API 標記

[英]Google Maps API markers with multiple icons

我想使用 Google Maps JavaScript API 實現一個復雜的標記,該 API 結合了靜態圖像(PNG 文件)和可“動態”編輯的圖像,例如 SVG。 這就是我的目標:

谷歌地圖標記 PNG + SVG

我已經將“士兵”構建為 PNG 文件標記,並且一切正常。 但是,我似乎找不到將多個元素添加到標記的“圖標”屬性的方法。 我已閱讀所有 Google Maps API 文檔、參考和示例,並查看了此鏈接:

如何在 v3 中為 Google 地圖標記放置多個圖標?

該鏈接似乎並沒有完全幫助,因為我希望士兵下方的紅條能夠動態更改,因為它代表士兵的健康狀況。

有沒有人有一個可行的解決方案? 我不介意它不使用SVG並使用CSS甚至Canvas,只要它呈現一個長度可以動態調整的簡單矩形即可。

謝謝。

一種選擇是使用兩個單獨的標記,綁定在一起(如果您需要移動它們):

var soldier = new google.maps.Marker({
  position: map.getCenter(),
  map: map,
  draggable: true,
  icon: { url: "http://www.geocodezip.com/mapIcons/greenSoldier.png",
   scaledSize: new google.maps.Size(32,48)
  }
});
var health = new google.maps.Marker({
  position: soldier.getPosition(),
  map: map,
  icon: { path: "M 100 100 L 150 100 L 150 110 L 100 110 z",
  scale: 0.5,
  fillColor: "red",
  fillOpacity: 1.0,
  strokeColor: "black",
  strokeWeight: 2,
  anchor: new google.maps.Point(125,110)
  }
});
health.bindTo("position", soldier);

概念證明小提琴

結果地圖的截圖

代碼片段:

 function initialize() { var map = new google.maps.Map( document.getElementById("map_canvas"), { center: new google.maps.LatLng(37.4419, -122.1419), zoom: 13, mapTypeId: google.maps.MapTypeId.ROADMAP }); var soldier = new google.maps.Marker({ position: map.getCenter(), map: map, draggable: true, icon: { url: "https://www.geocodezip.net/mapIcons/greenSoldier.png", scaledSize: new google.maps.Size(32, 48) } }); var health = new google.maps.Marker({ position: soldier.getPosition(), map: map, icon: { path: "M 100 100 L 150 100 L 150 110 L 100 110 z", scale: 0.5, fillColor: "green", fillOpacity: 1.0, strokeColor: "black", strokeWeight: 2, anchor: new google.maps.Point(125, 110) } }); health.bindTo("position", soldier); setInterval(changeLength, 5000); var idx = 0; function changeLength() { var icon = health.getIcon(); icon.fillColor = colors[(idx) % colors.length]; icon.path = lengths[(idx++) % lengths.length]; health.setIcon(icon); } } google.maps.event.addDomListener(window, "load", initialize); var colors = ["green", "green", "yellow", "red"]; var lengths = ["M 100 100 L 150 100 L 150 110 L 100 110 z", "M 100 100 L 140 100 L 140 110 L 100 110 z", "M 100 100 L 130 100 L 130 110 L 100 110 z", "M 100 100 L 120 100 L 120 110 L 100 110 z" ]
 html, body, #map_canvas { height: 100%; width: 100%; margin: 0px; padding: 0px }
 <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script> <div id="map_canvas"></div>

正如所承諾的那樣,我已經包含了我完整的工作代碼。 此函數將標記繪制為畫布圖像。 士兵和他的生命條是分開繪制的,因為士兵通常是靜態的(除非我們想為他設置動畫,我們可以通過畫布來做)但是當他被擊中時,生命條會發生變化。 我已經在我的游戲中測試了代碼,它運行良好。

geocodezip,我最終沒有采納您的建議,主要原因是出於性能原因不想將游戲中的標記數量增加一倍。 一個玩家可以在游戲中擁有數百個單位,並且任何時候都可能有數百個玩家,因此將標記加倍以實現我想要的效果可能會影響性能。 不過,您的代碼很棒,我可能會在加倍標記不會對性能產生影響的情況下使用它。

代碼如下:

function createUnitMarker(latLng, unitData) {
    var img = new Image();
    img.crossOrigin = "Anonymous";
    img.src = 'http://yourservername.com/' + unitData.icon;

    img.onload = function() {
        // google maps markers can only be created inside the onload function, otherwise nothing is drawn

        // source: GitHub, viktorkelemen/Custom canvas google maps marker
        // create the marker and all associated elements
        var canvas, context;
        var color = "blue";
        var healthBar = { // this object controls aspects of the unit health bar
            width: 62,
            height: 10,
            x: 5,
            y: 82
        }

        canvas = document.createElement("canvas");
        context = canvas.getContext("2d");

        canvas.width = unitData.width;
        canvas.height = unitData.height;

        function drawBar(percent, color) {
            // this function draws the unit health bar

            // colours the health bar background grey
            context.fillStyle = "gray";
            context.fillRect(healthBar.x, healthBar.y, healthBar.width, healthBar.height);

            // fills the health bar with the passed colour, or empty it if the unit dies
            if (typeof percent == undefined || percent == null || percent == NaN) {
                percent = 100;
            }

            if (typeof color == undefined || color == null || color == NaN) {
                color = "green";
            }

            // we want to ensure that the health bar fill is always contained within the health bar width
            var width = Math.min(percent * healthBar.width, healthBar.width);
            width = Math.max(width, 0);

            // colour-code the health bar depending on health
            if (percent < 0.4) {
                color = "red";
            }

            else if (percent < 0.7) {
                color = "orange";
            }

            else {
                color = "green";
            }

            context.fillStyle = color;
            context.fillRect(healthBar.x, healthBar.y, width, healthBar.height);

            // places a black stroke around the health bar for greater visibility
            context.lineWidth = 2;
            context.strokeStyle = "black";
            context.strokeRect(healthBar.x, healthBar.y, healthBar.width, healthBar.height);
        }

        function drawIcon(img, width, height) {
            // this function draws the unit

            if (typeof img === "undefined" || img === null || img === "" || img === NaN) {
                img = img;
            }

            if (typeof width === "undefined" || width === null || width === "" || width === NaN) {
                width = unitData.width;
            }

            if (typeof height === "undefined" || height === null || height === "" || height === NaN) {
                height = unitData.height;
            }

            context.clearRect(0, 0, width, height);

            // save the canvas context
            context.save();

            // draw the image
            context.drawImage(img, 0, 0);

            context.restore();
        }

        drawIcon(img, unitData.width, unitData.height);

        // create an icon based on the png we want to use
        var icon = {
            url: canvas.toDataURL(),
            size: new google.maps.Size(unitData.width, unitData.height), // the dimensions in pixels of the marker image
            origin: new google.maps.Point(0, 0), // the origin for this image, where top left is (0, 0)
            labelOrigin: new google.maps.Point(25, 40), // the position of the label relative to the icon
            anchor: new google.maps.Point(unitData.width / 2, unitData.height / 2) // the anchor for this image, or where the "base point" is located
        }

        // this is the key unit object. it should store all information directly related to this unit
        var marker = new google.maps.Marker({
            position: latLng, // the lat/lon where the marker is drawn
            label: {
                color: "yellow",
                fontFamily: "Oswald",
                fontSize: "20px",
                fontWeight: "bold", // use CSS font-weight properties
                text: unitData.unit_ID.toString(),
                visibility: "hidden"
            },
            title: "Infantry", // title on hover
            icon: icon, // the icon to be drawn, using an image file or canvas
            animation: google.maps.Animation.DROP, // a bit of flair :)
            // every element below this point is game-specific and not part of the google maps api
            unitID: unitData.unit_ID, // the unique unit id for this unit as returned by the server
            etc: 0
        });

        // to add the marker to the map, call setMap()          
        marker.setMap(gv.map);

        // draw the health bar last so that it's always on top, and after we know the unit's current/max health
        var healthPercent = marker.current_health / marker.max_health;
        drawBar(healthPercent);

        // these are the key commands required every time we need to re-draw something on the unit
        icon.url = canvas.toDataURL(); // re-draws the canvas, usually because we have changed something above this line
        icon = JSON.parse(JSON.stringify(icon)); // stringifies the icon properties
        marker.setIcon(icon); // applies the changed icon properties to the icon

        marker.addListener('label_changed', function() {
            // this listener is intended to update the unit's health bar on attack. it's a bit of a hack as it relies on changes to the marker's label to fire an event. other options are changing a marker's title, or writing a custom event (which is more involved)
            // draw the health bar last so that it's always on top, and after we know the unit's current/max health
            healthPercent = this.current_health / this.max_health;
            drawBar(healthPercent);

            icon = {
                url: canvas.toDataURL(),
                size: new google.maps.Size(unitData.width, unitData.height), // the dimensions in pixels of the marker image
                origin: new google.maps.Point(0, 0), // the origin for this image, where top left is (0, 0)
                labelOrigin: new google.maps.Point(25, 40), // the position of the label relative to the icon
                anchor: new google.maps.Point(unitData.width / 2, unitData.height / 2) // the anchor for this image, or where the "base point" is located
            }

            // all we want to do is change the icon url, but we can't just pass it to setIcon as it will lose the other icon properties. instead, we clone the icon object and change the url in the clone, passing it to setIcon when selected
            icon = JSON.parse(JSON.stringify(icon));

            this.setIcon(icon);
        });
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM