Javascript 谷歌地图 V3 上的旋转图像/标记图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6800613/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rotating image / marker image on Google map V3
提问by Horst Walter
How could I rotate an image (marker image) on a Google map V3?
如何在 Google 地图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 answersabout 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.
- 没有为V2一个很好的例子在这里,到底做什么,我需要的。但是对于 GMap2!他们用旋转的画布来做。
- 经常使用 JS / JQuery 旋转图像,对此有多种答案。但是我怎么能把它应用到我的地图图像上呢?
- 提到的一种方法是为不同的角度使用不同的图像并在它们之间切换 - 这不是我想要的。我不喜欢有这么多图像,我想通过代码旋转。
Remark: There are similar questions, but all for V2 and not V3 (as far I can tell). I need it for V3.
备注:有类似的问题,但都是针对 V2 而不是 V3(据我所知)。我需要它用于 V3。
采纳答案by Muhammad Alaa
I have done the rotation in v3 with the following code:
我已经使用以下代码在 v3 中完成了旋转:
<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.
我希望有帮助。
回答by ErDmKo
My js class for solving this problem is:
我解决这个问题的js类是:
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/
在此处查看现场示例http://jsfiddle.net/fe9grwdf/39/
回答by Horst Walter
I have found two extensions to the Google MAP V3: infobox.jsand markerwithlabel.jsBoth can handle an image DOM element as content, which in turn I can rotate via the jQuery image rotate plugin.
我发现了 Google MAP V3 的两个扩展:infobox.js和markerwithlabel.js两者都可以将图像 DOM 元素作为内容处理,而我又可以通过 jQuery图像旋转插件进行旋转。
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.
label 的扩展是必需的,因为它可以处理其他 DOM 元素。所以我可以添加任意 HTML 作为标签,在我的特殊情况下我添加图像。然后我用旋转插件旋转这个图像(标签的子元素)。因此,为图像分配一个 id 以便轻松访问它。实际上,我仅将一个标签用于图像,另一个用于描述性文本。
Edit 2: Due to Stephan's comment on the DOM readiness
编辑 2:由于 Stephan 对 DOM 准备情况的评论
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
编辑 3:代码示例如何创建 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);
回答by swj
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.
我也很难找出旋转 .png 标记的方法。我像下面这样解决了它。您可以使用相同的自定义图像创建多个标记并旋转要旋转的特定标记。我希望它对你有帮助。
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)'});
回答by Jesus Gilberto Valenzuela
How could I rotate an image (marker image) on a Google map V3?
如何在 Google 地图 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)
- 将 imagePath 变量的值更改为 'img/customMarker.png#yourId'
- 使用 css 设置旋转值(例如使用 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.
我希望它会有所帮助。
回答by Epiphany
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.
您没有在问题中说明这一点,但我假设您希望这种旋转与 a 点和 b 点之间的线相关,这将是它们的路径。为了制作可以旋转的 google svg 图标,您需要使用 google 符号类对象来定义标记符号的属性。这不使用完整的 .svg 文件,而只使用路径的 d 属性。请注意,google 符号类每个标记只能采用一条路径。
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).
可以在使用 javascript(直接更新标记对象属性)或使用 CSS(通过添加和删除类更新标记属性)创建标记后设置颜色、笔画、宽度、不透明度等附加属性。
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
HTML
<body id="document_body" onload="init();">
<div id="rotation_control">
Heading°<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)
CSS(是的,冗长......我讨厌丑陋)
#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)
Javascript(用于理解核心概念的纯香草风格)
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.
最好的是,这样做可以确保标记是 Google MVC 对象,并为其提供 MVC 对象提供的所有其他方法。
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.
如果您必须使用多色图像作为标记,则创建一个 .png 精灵表,其中包含您希望显示的所有角度的图像再现,然后根据计算的方位选择要使用的正确图像有问题在您使用的两点之间。但是,这不是 SVG 图像,而是常规标记图像。
Hope this helps in making some decisions regarding your map markers.
希望这有助于对您的地图标记做出一些决定。
回答by Kyle Bowerman
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.
我能够很容易地解决这个问题,但是使用了指向使用 svg 路径语法的自定义符号的 marker.icon.rotation 选项。
$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.
如果使用angular-google-maps,绑定一个ui控件来改变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
这是我的 plunker http://plnkr.co/edit/x0egXI
回答by prudvi raju
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.
使用 googleMap 标记自定义,地图中将增加内存使用量。这也将减少地图中自定义标记的内存消耗。
<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>
回答by Ryan Tapel
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.
没有人提到使用预旋转图标。根据您的应用程序,您可以使用一个图标并将其旋转 +10 度、+20 度 ... +350 度,而不是旋转标记本身,只需为其分配不同的图标 - 如果 10 度分辨率良好,则为 36 分之一足够的。这对客户的资源来说也很轻。
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)
在下面的示例中,我生成了 36 个图标,每个图标都旋转了 10 度。它们的名称是:icon0.png, icon10.png, icon20.png, ... icon340.png, icon350.png, icon360.png。0 和 360 是完全相同的图标(例如符号链接)
var rotation = 123 // degrees
var iconName = "icon" + (Math.round(rotation/10)*10).toString() + ".png"
var marker = new google.maps.Marker({
icon: iconName
})
回答by Chong Lip Phang
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>
<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.
以上是我的原始代码。我把它完好无损,这样你就可以看到我的其他优化。