| | 260 | }, |
|---|
| | 261 | |
|---|
| | 262 | /** |
|---|
| | 263 | * Method: graphicRotate |
|---|
| | 264 | * If a point is to be styled with externalGraphic and rotation, VML fills |
|---|
| | 265 | * cannot be used to display the graphic, because rotation of graphic |
|---|
| | 266 | * fills is not supported by the VML implementation of Internet Explorer. |
|---|
| | 267 | * This method creates a olv:imagedata element inside the VML node, |
|---|
| | 268 | * DXImageTransform.Matrix and BasicImage filters for rotation and |
|---|
| | 269 | * opacity, and a 3-step hack to remove rendering artefacts from the |
|---|
| | 270 | * graphic and preserve the ability of graphics to trigger events. |
|---|
| | 271 | * Finally, OpenLayers methods are used to determine the correct |
|---|
| | 272 | * insertion point of the rotated image, because DXImageTransform.Matrix |
|---|
| | 273 | * does the rotation without the ability to specify a rotation center |
|---|
| | 274 | * point. |
|---|
| | 275 | * |
|---|
| | 276 | * Parameters: |
|---|
| | 277 | * node - {DOMElement} |
|---|
| | 278 | * xOffset - {Number} rotation center relative to image, x coordinate |
|---|
| | 279 | * yOffset - {Number} rotation center relative to image, y coordinate |
|---|
| | 280 | */ |
|---|
| | 281 | graphicRotate: function(node, xOffset, yOffset) { |
|---|
| | 282 | var style = style || node._style; |
|---|
| | 283 | var options = node._options; |
|---|
| | 284 | |
|---|
| | 285 | var aspectRatio, size; |
|---|
| | 286 | if (!(style.graphicWidth && style.graphicHeight)) { |
|---|
| | 287 | // load the image to determine its size |
|---|
| | 288 | var img = new Image(); |
|---|
| | 289 | img.onreadystatechange = OpenLayers.Function.bind(function() { |
|---|
| | 290 | if(img.readyState == "complete" || |
|---|
| | 291 | img.readyState == "interactive") { |
|---|
| | 292 | aspectRatio = img.width / img.height; |
|---|
| | 293 | size = Math.max(style.pointRadius * 2, |
|---|
| | 294 | style.graphicWidth || 0, |
|---|
| | 295 | style.graphicHeight || 0); |
|---|
| | 296 | xOffset = xOffset * aspectRatio; |
|---|
| | 297 | style.graphicWidth = size * aspectRatio; |
|---|
| | 298 | style.graphicHeight = size; |
|---|
| | 299 | this.graphicRotate(node, xOffset, yOffset) |
|---|
| | 300 | } |
|---|
| | 301 | }, this); |
|---|
| | 302 | img.src = style.externalGraphic; |
|---|
| | 303 | |
|---|
| | 304 | // will be called again by the onreadystate handler |
|---|
| | 305 | return; |
|---|
| | 306 | } else { |
|---|
| | 307 | size = Math.max(style.graphicWidth, style.graphicHeight); |
|---|
| | 308 | aspectRatio = style.graphicWidth / style.graphicHeight; |
|---|
| | 309 | } |
|---|
| | 310 | |
|---|
| | 311 | var width = Math.round(style.graphicWidth || size * aspectRatio); |
|---|
| | 312 | var height = Math.round(style.graphicHeight || size); |
|---|
| | 313 | node.style.width = width; |
|---|
| | 314 | node.style.height = height; |
|---|
| | 315 | |
|---|
| | 316 | // Three steps are required to remove artefacts for images with |
|---|
| | 317 | // transparent backgrounds (resulting from using DXImageTransform |
|---|
| | 318 | // filters on svg objects), while preserving awareness for browser |
|---|
| | 319 | // events on images: |
|---|
| | 320 | // - Use the fill as usual (like for unrotated images) to handle |
|---|
| | 321 | // events |
|---|
| | 322 | // - specify an imagedata element with the same src as the fill |
|---|
| | 323 | // - style the imagedata element with an AlphaImageLoader filter |
|---|
| | 324 | // with empty src |
|---|
| | 325 | var image = document.getElementById(node.id + "_image"); |
|---|
| | 326 | if (!image) { |
|---|
| | 327 | image = this.createNode("olv:imagedata", node.id + "_image"); |
|---|
| | 328 | node.appendChild(image); |
|---|
| | 329 | } |
|---|
| | 330 | image.style.width = width; |
|---|
| | 331 | image.style.height = height; |
|---|
| | 332 | image.src = style.externalGraphic; |
|---|
| | 333 | image.style.filter = |
|---|
| | 334 | "progid:DXImageTransform.Microsoft.AlphaImageLoader(" + |
|---|
| | 335 | "src='', sizingMethod='scale')"; |
|---|
| | 336 | |
|---|
| | 337 | var rotation = style.rotation * Math.PI / 180; |
|---|
| | 338 | var sintheta = Math.sin(rotation); |
|---|
| | 339 | var costheta = Math.cos(rotation); |
|---|
| | 340 | |
|---|
| | 341 | // do the rotation on the image |
|---|
| | 342 | var filter = |
|---|
| | 343 | "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + |
|---|
| | 344 | ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta + |
|---|
| | 345 | ",SizingMethod='auto expand')\n" |
|---|
| | 346 | |
|---|
| | 347 | // set the opacity (needed for the imagedata) |
|---|
| | 348 | var opacity = style.graphicOpacity || style.fillOpacity; |
|---|
| | 349 | if (opacity && opacity != 1) { |
|---|
| | 350 | filter += |
|---|
| | 351 | "progid:DXImageTransform.Microsoft.BasicImage(opacity=" + |
|---|
| | 352 | opacity+")\n"; |
|---|
| | 353 | } |
|---|
| | 354 | node.style.filter = filter; |
|---|
| | 355 | |
|---|
| | 356 | // do the rotation again on a box, so we know the insertion point |
|---|
| | 357 | var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); |
|---|
| | 358 | var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); |
|---|
| | 359 | imgBox.rotate(style.rotation, centerPoint); |
|---|
| | 360 | var imgBounds = imgBox.getBounds(); |
|---|
| | 361 | |
|---|
| | 362 | node.style.left = Math.round( |
|---|
| | 363 | parseInt(node.style.left) + imgBounds.left); |
|---|
| | 364 | node.style.top = Math.round( |
|---|
| | 365 | parseInt(node.style.top) - imgBounds.bottom); |
|---|