diff --git a/css/ol.css b/css/ol.css index 13232a0105..79d5385efe 100644 --- a/css/ol.css +++ b/css/ol.css @@ -1,17 +1,32 @@ .ol-attribution { position: absolute; text-align: right; - color: #eeeeee; bottom: 0; right: 0; - background: rgba(0,60,136,0.3); font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif; padding: 6px; } .ol-attribution a { - color: white; text-decoration: none; } + +/* rgba is not supported on IE <= 8, fall back to black text so that it's readable */ +.ol-attribution { + color: #000000; +} +.ol-attribution:not([ie8andbelow]) { + color: #eeeeee; + background: rgba(0,60,136,0.3); +} + +/* white links are unreadable on IE <= 8 with no background, fall back to blue links */ +.ol-attribution a { + color: #7b98bc; +} +.ol-attribution a:not([ie8andbelow]) { + color: white; +} + .ol-attribution ul { margin: 0; padding: 0; @@ -32,20 +47,26 @@ white-space: nowrap; } .ol-full-screen { - background: rgba(255,255,255,0.4); + /* IE <= 8 doesn't support rgba, fall back to a light grey */ + background: #eee; border-radius: 4px; padding: 2px; position: absolute; right: 8px; top: 8px; } +.ol-full-screen:not([ie8andbelow]) { + /* IE <= 8 doesn't support rgba, fall back to a light grey */ + background: rgba(255,255,255,0.4); +} @media print { .ol-full-screen { display: none; } } .ol-full-screen a { - background: rgba(0,60,136,0.5); + /* IE <= 8 doesn't support rgba, fall back to a light blue */ + background: #7b98bc; color: white; display: block; font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif; @@ -59,6 +80,10 @@ text-decoration: none; width: 22px; } +.ol-full-screen a:not([ie8andbelow]) { + /* IE <= 8 doesn't support rgba, fall back to a light blue */ + background: rgba(0,60,136,0.5); +} a.ol-full-screen-false:after { content: "\2194"; } @@ -73,6 +98,11 @@ a.ol-full-screen-true:after { border-radius: 2px; } .ol-full-screen a:hover { + /* IE <= 8 doesn't support rgba, fall back to a light blue */ + background: #4c6079; +} +.ol-full-screen a:hover:not([ie8andbelow]) { + /* IE <= 8 doesn't support rgba, fall back to a light blue */ background: rgba(0,60,136,0.7); } .ol-logo { @@ -92,17 +122,22 @@ a.ol-full-screen-true:after { .ol-mouse-position { top: 8px; right: 8px; - position: absolute; + position: absolute; } .ol-scale-line { - background: rgba(0,60,136,0.3); + /* IE <= 8 doesn't support rgba, fall back to a light blue */ + background: #95b9e6; border-radius: 4px; bottom: 8px; left: 8px; padding: 2px; position: absolute; } +.ol-scale-line:not([ie8andbelow]) { + /* IE <= 8 doesn't support rgba, fall back to a light blue */ + background: rgba(0,60,136,0.3); +} .ol-scale-line-inner { border: 1px solid #eeeeee; border-top: none; @@ -124,15 +159,25 @@ a.ol-full-screen-true:after { -ms-user-select: none; user-select: none; -webkit-tap-highlight-color: rgba(0,0,0,0); + + cursor: default; +} +.ol-viewport .ol-unselectable:not([ie8andbelow]) { + cursor: auto; } .ol-zoom { position: absolute; top: 8px; left: 8px; - background: rgba(255,255,255,0.4); + /* IE <= 8 doesn't support rgba, fall back to a light grey */ + background-color: #eee; border-radius: 4px; padding: 2px; } +/* IE <= 8 doesn't support rgba, fall back to a light grey */ +.ol-zoom:not([ie8andbelow]) { + background-color: rgba(255,255,255,0.4); +} @media print { .ol-zoom { display: none; @@ -152,7 +197,12 @@ a.ol-full-screen-true:after { height: 22px; width: 22px; line-height: 19px; - background: rgba(0,60,136,0.5); + /* IE <= 8 doesn't support rgba, fall back to a light blue */ + background-color: #7b98bc; +} +.ol-zoom a:not([ie8andbelow]) { + /* IE <= 8 doesn't support rgba, fall back to a light blue */ + background-color: rgba(0,60,136,0.5); } .ol-touch .ol-zoom a { font-size: 20px; @@ -163,28 +213,28 @@ a.ol-full-screen-true:after { .ol-zoom a:hover { color: #fff; text-decoration: none; - background: rgba(0,60,136,0.7); + /* IE <= 8 doesn't support rgba, fall back to a lighter blue */ + background-color: #4c6079; +} +.ol-zoom a:hover:not([ie8andbelow]) { + /* IE <= 8 doesn't support rgba, fall back to a lighter blue */ + background-color: rgba(0,60,136,0.7); } .ol-zoom-in { border-radius: 2px 2px 0 0; } -.ol-zoom-in:before { - content: "+"; -} .ol-zoom-out { border-radius: 0 0 2px 2px; } -.ol-zoom-out:before { - content: "\2212"; -} .ol-zoomslider { position: absolute; top: 67px; left: 8px; - background: rgba(255, 255, 255, 0.4); + /* IE <= 8 doesn't support rgba, fall back to a light grey */ + background: #eee; border-radius: 4px; width: 28px; height: 200px; @@ -193,26 +243,40 @@ a.ol-full-screen-true:after { padding: 0; margin: 0; } +.ol-zoomslider:not([ie8andbelow]) { + /* IE <= 8 doesn't support rgba, fall back to a light grey */ + background: rgba(255, 255, 255, 0.4); +} .ol-zoomslider-thumb { position: absolute; display: block; padding: 0; margin: 2px; - background: rgba(0,60,136,0.5); + /* IE <= 8 doesn't support rgba, fall back to a lighter blue */ + background: #7b98bc; border-radius: 2px; outline: none; overflow: hidden; height: 20px; width: 24px; } +.ol-zoomslider-thumb:not([ie8andbelow]) { + /* IE <= 8 doesn't support rgba, fall back to a lighter blue */ + background: rgba(0,60,136,0.5); +} .ol-zoom-extent { position: absolute; - background: rgba(255,255,255,0.4); + /* IE <= 8 doesn't support rgba, fall back to a light grey */ + background: #eee; border-radius: 4px; left: 8px; padding: 2px; top: 65px; } +.ol-zoom-extent:not([ie8andbelow]) { + /* IE <= 8 doesn't support rgba, fall back to a light grey */ + background: rgba(255,255,255,0.4); +} @media print { .ol-zoom-extent { display: none; @@ -230,9 +294,14 @@ a.ol-full-screen-true:after { text-align: center; height: 22px; width: 22px; - background-color: rgba(0, 60, 136, 0.5); + /* IE <= 8 doesn't support rgba, fall back to a lighter blue */ + background-color: #7b98bc; border-radius: 2px; } +.ol-zoom-extent a:not([ie8andbelow]) { + /* IE <= 8 doesn't support rgba, fall back to a lighter blue */ + background-color: rgba(0, 60, 136, 0.5); +} .ol-touch .ol-zoom-extent a { font-size: 20px; height: 30px; @@ -240,6 +309,11 @@ a.ol-full-screen-true:after { line-height: 26px; } .ol-zoom-extent a:hover { + /* IE <= 8 doesn't support rgba, fall back to a lighter blue */ + background-color: #4c6079; +} +.ol-zoom-extent a:hover:not([ie8andbelow]) { + /* IE <= 8 doesn't support rgba, fall back to a lighter blue */ background-color: rgba(0, 60, 136, 0.7); } .ol-zoom-extent a:after { diff --git a/examples/accessible.html b/examples/accessible.html index 3cdaf170b0..4ca8f48fa5 100644 --- a/examples/accessible.html +++ b/examples/accessible.html @@ -52,6 +52,7 @@ + diff --git a/examples/animation.html b/examples/animation.html index abedf3c0fe..a2457641ad 100644 --- a/examples/animation.html +++ b/examples/animation.html @@ -55,6 +55,7 @@ + diff --git a/examples/bind-input.html b/examples/bind-input.html index d45f73b874..4bcb50ee93 100644 --- a/examples/bind-input.html +++ b/examples/bind-input.html @@ -80,6 +80,7 @@ + diff --git a/examples/brightness-contrast.html b/examples/brightness-contrast.html index de9ec3fb24..63189a0acd 100644 --- a/examples/brightness-contrast.html +++ b/examples/brightness-contrast.html @@ -65,6 +65,7 @@ + diff --git a/examples/canvas-tiles.html b/examples/canvas-tiles.html index 7b817b74fd..639d7d3ef6 100644 --- a/examples/canvas-tiles.html +++ b/examples/canvas-tiles.html @@ -43,6 +43,7 @@ + diff --git a/examples/custom-controls.html b/examples/custom-controls.html index 563757a222..d1133e6baf 100644 --- a/examples/custom-controls.html +++ b/examples/custom-controls.html @@ -81,6 +81,7 @@ + diff --git a/examples/d3.html b/examples/d3.html index bc19211ad8..7d56ff152b 100644 --- a/examples/d3.html +++ b/examples/d3.html @@ -43,6 +43,7 @@ + diff --git a/examples/device-orientation.html b/examples/device-orientation.html index 54942cca60..069e77687d 100644 --- a/examples/device-orientation.html +++ b/examples/device-orientation.html @@ -49,6 +49,7 @@ + diff --git a/examples/drag-rotate-and-zoom.html b/examples/drag-rotate-and-zoom.html index 7573e373b8..4dc8775023 100644 --- a/examples/drag-rotate-and-zoom.html +++ b/examples/drag-rotate-and-zoom.html @@ -43,6 +43,7 @@ + diff --git a/examples/draw-features.html b/examples/draw-features.html index d2bdf15e1a..5b75037fe4 100644 --- a/examples/draw-features.html +++ b/examples/draw-features.html @@ -51,6 +51,7 @@ + diff --git a/examples/dynamic-data.html b/examples/dynamic-data.html index 89fb754092..2f5edf1bbf 100644 --- a/examples/dynamic-data.html +++ b/examples/dynamic-data.html @@ -42,6 +42,7 @@ + diff --git a/examples/epsg-4326.html b/examples/epsg-4326.html index 36b4ef918e..96995c3b90 100644 --- a/examples/epsg-4326.html +++ b/examples/epsg-4326.html @@ -42,6 +42,7 @@ + diff --git a/examples/export-map.html b/examples/export-map.html index 56b21b05b3..a53cbbd384 100644 --- a/examples/export-map.html +++ b/examples/export-map.html @@ -47,6 +47,7 @@ + diff --git a/examples/full-screen-drag-rotate-and-zoom.html b/examples/full-screen-drag-rotate-and-zoom.html index acdf4b94a6..ab47d82c0d 100644 --- a/examples/full-screen-drag-rotate-and-zoom.html +++ b/examples/full-screen-drag-rotate-and-zoom.html @@ -55,6 +55,7 @@ + diff --git a/examples/full-screen.html b/examples/full-screen.html index a7e8963129..be4e885553 100644 --- a/examples/full-screen.html +++ b/examples/full-screen.html @@ -55,6 +55,7 @@ + diff --git a/examples/geojson.html b/examples/geojson.html index 26135d4e76..24aaa51ce5 100644 --- a/examples/geojson.html +++ b/examples/geojson.html @@ -42,6 +42,7 @@ + diff --git a/examples/getfeatureinfo.html b/examples/getfeatureinfo.html index 8d4b054528..4d7bd3b6f7 100644 --- a/examples/getfeatureinfo.html +++ b/examples/getfeatureinfo.html @@ -48,6 +48,7 @@ + diff --git a/examples/hue-saturation.html b/examples/hue-saturation.html index 087ed33496..f9c7b79869 100644 --- a/examples/hue-saturation.html +++ b/examples/hue-saturation.html @@ -65,6 +65,7 @@ + diff --git a/examples/layer-clipping-webgl.html b/examples/layer-clipping-webgl.html index 36f869e78c..97a58d91a9 100644 --- a/examples/layer-clipping-webgl.html +++ b/examples/layer-clipping-webgl.html @@ -47,6 +47,7 @@ + diff --git a/examples/layer-clipping.html b/examples/layer-clipping.html index 90077e3166..0db4de0d6c 100644 --- a/examples/layer-clipping.html +++ b/examples/layer-clipping.html @@ -42,6 +42,7 @@ + diff --git a/examples/layer-swipe.html b/examples/layer-swipe.html index 48303a95bf..a3f1281986 100644 --- a/examples/layer-swipe.html +++ b/examples/layer-swipe.html @@ -43,6 +43,7 @@ + diff --git a/examples/localized-openstreetmap.html b/examples/localized-openstreetmap.html index 769f29591f..5cb6ef7d23 100644 --- a/examples/localized-openstreetmap.html +++ b/examples/localized-openstreetmap.html @@ -42,6 +42,7 @@ + diff --git a/examples/mapguide-untiled.html b/examples/mapguide-untiled.html index 3aed063b9b..ac111b1926 100644 --- a/examples/mapguide-untiled.html +++ b/examples/mapguide-untiled.html @@ -42,6 +42,7 @@ + diff --git a/examples/min-max-resolution.html b/examples/min-max-resolution.html index a0e4c32ef8..59af04e66b 100644 --- a/examples/min-max-resolution.html +++ b/examples/min-max-resolution.html @@ -51,6 +51,7 @@ + diff --git a/examples/mouse-position.html b/examples/mouse-position.html index 4d739fd45f..990b88f828 100644 --- a/examples/mouse-position.html +++ b/examples/mouse-position.html @@ -50,6 +50,7 @@ + diff --git a/examples/moveend.html b/examples/moveend.html index d0ab0d623a..aa9484b59f 100644 --- a/examples/moveend.html +++ b/examples/moveend.html @@ -45,6 +45,7 @@ + diff --git a/examples/navigation-controls.html b/examples/navigation-controls.html index 46a6944043..fbf1129649 100644 --- a/examples/navigation-controls.html +++ b/examples/navigation-controls.html @@ -47,6 +47,7 @@ + diff --git a/examples/popup.html b/examples/popup.html index 95e1bac848..97f1e9ac6c 100644 --- a/examples/popup.html +++ b/examples/popup.html @@ -97,6 +97,7 @@ + diff --git a/examples/preload.html b/examples/preload.html index 771e952b1e..81e2f998ec 100644 --- a/examples/preload.html +++ b/examples/preload.html @@ -46,6 +46,7 @@ + diff --git a/examples/rotation.html b/examples/rotation.html index 9636f063ca..14f62a60cf 100644 --- a/examples/rotation.html +++ b/examples/rotation.html @@ -43,6 +43,7 @@ + diff --git a/examples/rtree.html b/examples/rtree.html index 80f1f8e21c..89f1e99432 100644 --- a/examples/rtree.html +++ b/examples/rtree.html @@ -42,6 +42,7 @@ + diff --git a/examples/scale-line.html b/examples/scale-line.html index a41b33ea4b..f284b30607 100644 --- a/examples/scale-line.html +++ b/examples/scale-line.html @@ -47,6 +47,7 @@ + diff --git a/examples/select-features.html b/examples/select-features.html index a764084d44..a6e12c207f 100644 --- a/examples/select-features.html +++ b/examples/select-features.html @@ -43,6 +43,7 @@ + diff --git a/examples/semi-transparent-layer.html b/examples/semi-transparent-layer.html index 002c58fa82..1a877e35ab 100644 --- a/examples/semi-transparent-layer.html +++ b/examples/semi-transparent-layer.html @@ -42,6 +42,7 @@ + diff --git a/examples/side-by-side.html b/examples/side-by-side.html index d3ffb744f3..7df539fc64 100644 --- a/examples/side-by-side.html +++ b/examples/side-by-side.html @@ -54,6 +54,7 @@ + diff --git a/examples/simple.html b/examples/simple.html index c46005de82..860ac484ee 100644 --- a/examples/simple.html +++ b/examples/simple.html @@ -42,6 +42,7 @@ + diff --git a/examples/stamen.html b/examples/stamen.html index 0f146407f5..acf7cb1e8c 100644 --- a/examples/stamen.html +++ b/examples/stamen.html @@ -42,6 +42,7 @@ + diff --git a/examples/static-image.html b/examples/static-image.html index c7ca702969..29c8d08290 100644 --- a/examples/static-image.html +++ b/examples/static-image.html @@ -42,6 +42,7 @@ + diff --git a/examples/synthetic-lines.html b/examples/synthetic-lines.html index a129e66ce9..9065c02cfe 100644 --- a/examples/synthetic-lines.html +++ b/examples/synthetic-lines.html @@ -100,6 +100,7 @@ + diff --git a/examples/teleport.html b/examples/teleport.html index b26a4d7f1d..b67dda04b8 100644 --- a/examples/teleport.html +++ b/examples/teleport.html @@ -52,6 +52,7 @@ + diff --git a/examples/tilejson.html b/examples/tilejson.html index 58610c3751..d534c699ce 100644 --- a/examples/tilejson.html +++ b/examples/tilejson.html @@ -42,6 +42,7 @@ + diff --git a/examples/topojson.html b/examples/topojson.html index 0afee83db1..e8bcd3e597 100644 --- a/examples/topojson.html +++ b/examples/topojson.html @@ -44,6 +44,7 @@ + diff --git a/examples/wms-capabilities.html b/examples/wms-capabilities.html index 6aec2b9a03..acc12dad11 100644 --- a/examples/wms-capabilities.html +++ b/examples/wms-capabilities.html @@ -40,6 +40,7 @@ + diff --git a/examples/wms-custom-proj.html b/examples/wms-custom-proj.html index 3ddd07df23..6641ff0b51 100644 --- a/examples/wms-custom-proj.html +++ b/examples/wms-custom-proj.html @@ -42,6 +42,7 @@ + diff --git a/examples/wms-image-custom-proj.html b/examples/wms-image-custom-proj.html index e7478fb829..8d32132257 100644 --- a/examples/wms-image-custom-proj.html +++ b/examples/wms-image-custom-proj.html @@ -43,6 +43,7 @@ + diff --git a/examples/wms-image.html b/examples/wms-image.html index 72d6cca182..7707eb5768 100644 --- a/examples/wms-image.html +++ b/examples/wms-image.html @@ -42,6 +42,7 @@ + diff --git a/examples/wms-no-proj.html b/examples/wms-no-proj.html index ece1dfbf38..dc6e01b906 100644 --- a/examples/wms-no-proj.html +++ b/examples/wms-no-proj.html @@ -42,6 +42,7 @@ + diff --git a/examples/wms-tiled.html b/examples/wms-tiled.html index 8a0f52a068..1bc78e2527 100644 --- a/examples/wms-tiled.html +++ b/examples/wms-tiled.html @@ -42,6 +42,7 @@ + diff --git a/examples/wmts.html b/examples/wmts.html index cd093454de..1d03468dc1 100644 --- a/examples/wmts.html +++ b/examples/wmts.html @@ -42,6 +42,7 @@ + diff --git a/examples/xyz-esri.html b/examples/xyz-esri.html index 0846616cf6..0e096fd533 100644 --- a/examples/xyz-esri.html +++ b/examples/xyz-esri.html @@ -42,6 +42,7 @@ + diff --git a/examples/zoomify.html b/examples/zoomify.html index 940467aa1d..11aed4215f 100644 --- a/examples/zoomify.html +++ b/examples/zoomify.html @@ -42,6 +42,7 @@ + diff --git a/examples/zoomslider.html b/examples/zoomslider.html index 1b431caba6..dd270449de 100644 --- a/examples/zoomslider.html +++ b/examples/zoomslider.html @@ -106,6 +106,7 @@ + diff --git a/resources/example-behaviour.js b/resources/example-behaviour.js index 28b0785469..eb0e264a15 100644 --- a/resources/example-behaviour.js +++ b/resources/example-behaviour.js @@ -2,7 +2,7 @@ if (window.location.host === 'localhost:3000') { return; } - var container = document.querySelector('.navbar .navbar-inner .container'), + var container = $('.navbar .navbar-inner .container')[0], form = document.createElement('form'), select = document.createElement('select'), possibleModes = { @@ -54,7 +54,7 @@ } } - select.addEventListener('change', modeChangedMethod); + $(select).change(modeChangedMethod); select.className = 'input-medium'; form.className = 'navbar-form pull-right'; diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index 86ba8617c4..7fdbd6e09f 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -245,6 +245,8 @@ * @typedef {Object} olx.control.ZoomOptions * @property {number|undefined} duration Animation duration in milliseconds. Default is `250`. * @property {string|undefined} className CSS class name. Default is `ol-zoom`. + * @property {string|undefined} zoomInLabel Text label to use for the zoom-in button. Default is `+` + * @property {string|undefined} zoomOutLabel Text label to use for the zoom-out button. Default is `-` * @property {number|undefined} delta The zoom delta applied on each click. * @property {Element|undefined} target Target. * @todo stability experimental diff --git a/src/ol/browserfeature.js b/src/ol/browserfeature.js index e03792b08a..c5802a3e48 100644 --- a/src/ol/browserfeature.js +++ b/src/ol/browserfeature.js @@ -2,6 +2,7 @@ goog.provide('ol.BrowserFeature'); goog.require('goog.dom'); goog.require('goog.dom.TagName'); +goog.require('goog.userAgent'); goog.require('ol.webgl'); @@ -47,6 +48,21 @@ ol.ENABLE_VECTOR = true; ol.ENABLE_WEBGL = true; +/** + * @define {boolean} Whether to support legacy IE (7-8). + */ +ol.LEGACY_IE_SUPPORT = false; + + +/** + * Whether the current browser is legacy IE + * @const + * @type {boolean} + */ +ol.IS_LEGACY_IE = goog.userAgent.IE && + !goog.userAgent.isVersionOrHigher('9.0') && goog.userAgent.VERSION !== ''; + + /** * The ratio between physical pixels and device-independent pixels * (dips) on the device (`window.devicePixelRatio`). diff --git a/src/ol/control/zoomcontrol.js b/src/ol/control/zoomcontrol.js index 5c8fe4ca4a..1cce5fc6a8 100644 --- a/src/ol/control/zoomcontrol.js +++ b/src/ol/control/zoomcontrol.js @@ -32,10 +32,14 @@ ol.control.Zoom = function(opt_options) { var delta = goog.isDef(options.delta) ? options.delta : 1; + var zoomInLabel = goog.isDef(options.zoomInLabel) ? options.zoomInLabel : '+', + zoomOutLabel = + goog.isDef(options.zoomOutLabel) ? options.zoomOutLabel : '-'; + var inElement = goog.dom.createDom(goog.dom.TagName.A, { 'href': '#zoomIn', 'class': className + '-in' - }); + }, zoomInLabel); goog.events.listen(inElement, [ goog.events.EventType.TOUCHEND, goog.events.EventType.CLICK @@ -44,7 +48,7 @@ ol.control.Zoom = function(opt_options) { var outElement = goog.dom.createDom(goog.dom.TagName.A, { 'href': '#zoomOut', 'class': className + '-out' - }); + }, zoomOutLabel); goog.events.listen(outElement, [ goog.events.EventType.TOUCHEND, goog.events.EventType.CLICK diff --git a/src/ol/dom/dom.js b/src/ol/dom/dom.js index 44d86b8b43..9b9dea6990 100644 --- a/src/ol/dom/dom.js +++ b/src/ol/dom/dom.js @@ -4,15 +4,85 @@ goog.provide('ol.dom'); goog.provide('ol.dom.BrowserFeature'); goog.require('goog.asserts'); +goog.require('goog.dom'); +goog.require('goog.dom.TagName'); +goog.require('goog.style'); +goog.require('goog.userAgent'); goog.require('goog.vec.Mat4'); /** + * http://caniuse.com/#feat=transforms2d + * http://caniuse.com/#feat=transforms3d * @enum {boolean} */ ol.dom.BrowserFeature = { - CAN_USE_CSS_TRANSFORM: false, - CAN_USE_CSS_TRANSFORM3D: true + CAN_USE_CSS_TRANSFORM: ( + /** + * Detect 2d transform. + * Adapted from http://stackoverflow.com/q/5661671/130442 + * @return {boolean} + */ + function() { + if (!window.getComputedStyle) { + // this browser is ancient + return false; + } + var el = goog.dom.createElement(goog.dom.TagName.P), + has2d, + transforms = { + 'webkitTransform': '-webkit-transform', + 'OTransform': '-o-transform', + 'msTransform': '-ms-transform', + 'MozTransform': '-moz-transform', + 'transform': 'transform' + }; + goog.dom.appendChild(document.body, el); + for (var t in transforms) { + if (t in el.style) { + el.style[t] = 'translate(1px,1px)'; + has2d = window.getComputedStyle(el).getPropertyValue(transforms[t]); + } + } + goog.dom.removeNode(el); + + return (goog.isDefAndNotNull(has2d) && has2d.length > 0 && + has2d !== 'none'); + })(), + CAN_USE_CSS_TRANSFORM3D: ( + /** + * Detect 3d transform. + * Adapted from http://stackoverflow.com/q/5661671/130442 + * @return {boolean} + */ + function() { + if (!window.getComputedStyle) { + // this browser is ancient + return false; + } + var el = goog.dom.createElement(goog.dom.TagName.P), + has3d, + transforms = { + 'webkitTransform': '-webkit-transform', + 'OTransform': '-o-transform', + 'msTransform': '-ms-transform', + 'MozTransform': '-moz-transform', + 'transform': 'transform' + }; + goog.dom.appendChild(document.body, el); + for (var t in transforms) { + if (t in el.style) { + el.style[t] = 'translate3d(1px,1px,1px)'; + has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]); + } + } + goog.dom.removeNode(el); + + return (goog.isDefAndNotNull(has3d) && has3d.length > 0 && + has3d !== 'none'); + })(), + USE_MS_MATRIX_TRANSFORM: ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE, + USE_MS_ALPHA_FILTER: ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE }; @@ -25,21 +95,97 @@ ol.dom.setTransform = function(element, value) { style.WebkitTransform = value; style.MozTransform = value; style.OTransform = value; + style.msTransform = value; style.transform = value; + + // IE 9+ seems to assume transform-origin: 100% 100%; for some unknown reason + if (goog.userAgent.IE && !ol.IS_LEGACY_IE) { + element.style.transformOrigin = '0 0'; + } }; /** - * @param {Element} element Element. + * Sets the opacity of an element, in an IE-compatible way + * @param {!Element} element Element + * @param {number} value Opacity, [0..1] + */ +ol.dom.setOpacity = function(element, value) { + if (ol.dom.BrowserFeature.USE_MS_ALPHA_FILTER) { + /** @type {string} */ + var filter = element.currentStyle.filter; + + /** @type {RegExp} */ + var regex; + + /** @type {string} */ + var alpha; + + if (goog.userAgent.VERSION == '8.0') { + regex = /progid:DXImageTransform\.Microsoft\.Alpha\(.*?\)/i, + alpha = 'progid:DXImageTransform.Microsoft.Alpha(Opacity=' + + (value * 100) + ')'; + } else { + regex = /alpha\(.*?\)/i; + alpha = 'alpha(opacity=' + (value * 100) + ')'; + } + + var newFilter = filter.replace(regex, alpha); + if (newFilter === filter) { + // no replace was made? just append the new alpha filter instead + newFilter += ' ' + alpha; + } + + element.style.filter = newFilter; + + // Fix to apply filter to absolutely-positioned children element + if (element.currentStyle.zIndex === 'auto') { + element.style.zIndex = 0; + } + } else { + goog.style.setOpacity(element, value); + } +}; + + +/** + * Sets the IE matrix transform without replacing other filters + * @private + * @param {!Element} element Element + * @param {string} value The new progid string + */ +ol.dom.setIEMatrix_ = function(element, value) { + var filter = element.currentStyle.filter; + var newFilter = + filter.replace(/progid:DXImageTransform.Microsoft.Matrix\(.*?\)/i, value); + + if (newFilter === filter) { + newFilter = ' ' + value; + } + + element.style.filter = newFilter; + + // Fix to apply filter to absolutely-positioned children element + if (element.currentStyle.zIndex === 'auto') { + element.style.zIndex = 0; + } +}; + + +/** + * @param {!Element} element Element. * @param {goog.vec.Mat4.Number} transform Matrix. * @param {number=} opt_precision Precision. + * @param {Element=} opt_translationElement Required for IE7-8 */ -ol.dom.transformElement2D = function(element, transform, opt_precision) { +ol.dom.transformElement2D = + function(element, transform, opt_precision, opt_translationElement) { // using matrix() causes gaps in Chrome and Firefox on Mac OS X, so prefer // matrix3d() var i; if (ol.dom.BrowserFeature.CAN_USE_CSS_TRANSFORM3D) { var value3D; + if (goog.isDef(opt_precision)) { /** @type {Array.} */ var strings3D = new Array(16); @@ -73,10 +219,46 @@ ol.dom.transformElement2D = function(element, transform, opt_precision) { value2D = transform2D.join(','); } ol.dom.setTransform(element, 'matrix(' + value2D + ')'); + } else if (ol.dom.BrowserFeature.USE_MS_MATRIX_TRANSFORM) { + var m11 = goog.vec.Mat4.getElement(transform, 0, 0), + m12 = goog.vec.Mat4.getElement(transform, 0, 1), + m21 = goog.vec.Mat4.getElement(transform, 1, 0), + m22 = goog.vec.Mat4.getElement(transform, 1, 1), + dx = goog.vec.Mat4.getElement(transform, 0, 3), + dy = goog.vec.Mat4.getElement(transform, 1, 3); + + // See: http://msdn.microsoft.com/en-us/library/ms533014(v=vs.85).aspx + // and: http://extremelysatisfactorytotalitarianism.com/blog/?p=1002 + // @TODO: fix terrible IE bbox rotation issue. + var s = 'progid:DXImageTransform.Microsoft.Matrix('; + s += 'sizingMethod="auto expand"'; + s += ',M11=' + m11.toFixed(opt_precision || 20); + s += ',M12=' + m12.toFixed(opt_precision || 20); + s += ',M21=' + m21.toFixed(opt_precision || 20); + s += ',M22=' + m22.toFixed(opt_precision || 20); + s += ')'; + ol.dom.setIEMatrix_(element, s); + + // scale = m11 = m22 = target resolution [m/px] / current res [m/px] + // dx = (viewport width [px] / 2) * scale + // + (layer.x [m] - view.x [m]) / target resolution [m / px] + // except that we're positioning the child element relative to the + // viewport, not the map. + // dividing by the scale factor isn't the exact correction, but it's + // close enough that you can barely tell unless you're looking for it + dx /= m11; + dy /= m22; + + opt_translationElement.style.left = Math.round(dx) + 'px'; + opt_translationElement.style.top = Math.round(dy) + 'px'; } else { - // FIXME check this code! - var style = element.style; - style.left = Math.round(goog.vec.Mat4.getElement(transform, 0, 3)) + 'px'; - style.top = Math.round(goog.vec.Mat4.getElement(transform, 1, 3)) + 'px'; + element.style.left = + Math.round(goog.vec.Mat4.getElement(transform, 0, 3)) + 'px'; + element.style.top = + Math.round(goog.vec.Mat4.getElement(transform, 1, 3)) + 'px'; + + // TODO: Add scaling here. This isn't quite as simple as multiplying + // width/height, because that only changes the container size, not the + // content size. } }; diff --git a/src/ol/imagetile.js b/src/ol/imagetile.js index dd7098f00e..1fa5c9b866 100644 --- a/src/ol/imagetile.js +++ b/src/ol/imagetile.js @@ -115,6 +115,11 @@ ol.ImageTile.prototype.handleImageError_ = function() { * @private */ ol.ImageTile.prototype.handleImageLoad_ = function() { + if (!goog.isDef(this.image_.naturalWidth)) { + this.image_.naturalWidth = this.image_.width; + this.image_.naturalHeight = this.image_.height; + } + if (this.image_.naturalWidth && this.image_.naturalHeight) { this.state = ol.TileState.LOADED; } else { diff --git a/src/ol/interaction/drawinteraction.js b/src/ol/interaction/drawinteraction.js index 1ee25f8872..c2d19aded1 100644 --- a/src/ol/interaction/drawinteraction.js +++ b/src/ol/interaction/drawinteraction.js @@ -148,18 +148,15 @@ ol.interaction.Draw = function(options) { */ this.overlay_ = new ol.FeatureOverlay(); this.overlay_.setStyleFunction(goog.isDef(options.styleFunction) ? - options.styleFunction : ol.interaction.Draw.defaultStyleFunction - ); + options.styleFunction : ol.interaction.Draw.getDefaultStyleFunction()); }; goog.inherits(ol.interaction.Draw, ol.interaction.Interaction); /** - * @param {ol.Feature} feature Feature. - * @param {number} resolution Resolution. - * @return {Array.} Styles. + * @return {ol.feature.StyleFunction} Styles. */ -ol.interaction.Draw.defaultStyleFunction = (function() { +ol.interaction.Draw.getDefaultStyleFunction = function() { /** @type {Object.>} */ var styles = {}; styles[ol.geom.GeometryType.POLYGON] = [ @@ -210,7 +207,7 @@ ol.interaction.Draw.defaultStyleFunction = (function() { return function(feature, resolution) { return styles[feature.getGeometry().getType()]; }; -})(); +}; /** diff --git a/src/ol/mapbrowserevent.js b/src/ol/mapbrowserevent.js index bfd7088cd3..326505f967 100644 --- a/src/ol/mapbrowserevent.js +++ b/src/ol/mapbrowserevent.js @@ -8,6 +8,7 @@ goog.require('goog.events'); goog.require('goog.events.BrowserEvent'); goog.require('goog.events.EventTarget'); goog.require('goog.events.EventType'); +goog.require('goog.object'); goog.require('ol.Coordinate'); goog.require('ol.FrameState'); goog.require('ol.MapEvent'); @@ -132,6 +133,14 @@ ol.MapBrowserEventHandler = function(map) { */ this.touchstartListenerKey_ = null; + if (ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE) { + /** + * @type {goog.events.Key} + * @private + */ + this.ieDblclickListenerKey_ = null; + } + /** * @type {goog.events.BrowserEvent} * @private @@ -161,6 +170,10 @@ ol.MapBrowserEventHandler = function(map) { goog.events.EventType.TOUCHSTART, this.handleTouchStart_, false, this); + if (ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE) { + this.ieDblclickListenerKey_ = goog.events.listen(element, + goog.events.EventType.DBLCLICK, this.emulateClick_, false, this); + } }; goog.inherits(ol.MapBrowserEventHandler, goog.events.EventTarget); @@ -190,12 +203,28 @@ ol.MapBrowserEventHandler.prototype.emulateClick_ = function(browserEvent) { this.dispatchEvent(newEvent); } else { // click - this.clickTimeoutId_ = goog.global.setTimeout(goog.bind(function() { - this.clickTimeoutId_ = 0; - var newEvent = new ol.MapBrowserEvent( - ol.MapBrowserEvent.EventType.SINGLECLICK, this.map_, browserEvent); - this.dispatchEvent(newEvent); - }, this), 250); + + if (ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE) { + // In IE 7-8, referring to the original event object after the current + // call stack causes "member not found" exceptions, such as in the timeout + // we use here. + var ev = /** @type {Event} */ ( + goog.object.clone(browserEvent.getBrowserEvent())); + this.clickTimeoutId_ = goog.global.setTimeout(goog.bind(function() { + this.clickTimeoutId_ = 0; + var newEvent = new ol.MapBrowserEvent( + ol.MapBrowserEvent.EventType.SINGLECLICK, this.map_, + new goog.events.BrowserEvent(ev, browserEvent.currentTarget)); + this.dispatchEvent(newEvent); + }, this), 250); + } else { + this.clickTimeoutId_ = goog.global.setTimeout(goog.bind(function() { + this.clickTimeoutId_ = 0; + var newEvent = new ol.MapBrowserEvent( + ol.MapBrowserEvent.EventType.SINGLECLICK, this.map_, browserEvent); + this.dispatchEvent(newEvent); + }, this), 250); + } } }; @@ -446,6 +475,11 @@ ol.MapBrowserEventHandler.prototype.disposeInternal = function() { goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey); this.dragListenerKeys_ = null; } + if (ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE && + !goog.isNull(this.ieDblclickListenerKey_)) { + goog.events.unlistenByKey(this.ieDblclickListenerKey_); + this.ieDblclickListenerKey_ = null; + } goog.base(this, 'disposeInternal'); }; diff --git a/src/ol/renderer/dom/dommaprenderer.js b/src/ol/renderer/dom/dommaprenderer.js index e680a02fd2..0eaa8410bb 100644 --- a/src/ol/renderer/dom/dommaprenderer.js +++ b/src/ol/renderer/dom/dommaprenderer.js @@ -3,6 +3,7 @@ goog.provide('ol.renderer.dom.Map'); goog.require('goog.asserts'); goog.require('goog.dom'); goog.require('goog.dom.TagName'); +goog.require('goog.functions'); goog.require('goog.style'); goog.require('ol.css'); goog.require('ol.layer.Image'); @@ -36,6 +37,14 @@ ol.renderer.dom.Map = function(container, map) { style.width = '100%'; style.height = '100%'; + // in IE < 9, we need to return false from ondragstart to cancel the default + // behavior of dragging images, which is interfering with the custom handler + // in the Drag interaction subclasses + if (ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE) { + this.layersPane_.ondragstart = goog.functions.FALSE; + this.layersPane_.onselectstart = goog.functions.FALSE; + } + goog.dom.insertChildAt(container, this.layersPane_, 0); /** @@ -61,7 +70,6 @@ ol.renderer.dom.Map.prototype.createLayerRenderer = function(layer) { goog.asserts.fail(); return null; } - goog.dom.appendChild(this.layersPane_, layerRenderer.getTarget()); return layerRenderer; }; @@ -79,12 +87,45 @@ ol.renderer.dom.Map.prototype.renderFrame = function(frameState) { return; } + /** + * @this {ol.renderer.dom.Map} + * @param {Element} elem + * @param {number} i + */ + var addChild; + + // appendChild is actually more performant than insertBefore + // in IE 7 and 8. http://jsperf.com/reattaching-dom-nodes + if (ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE) { + addChild = + /** + * @this {ol.renderer.dom.Map} + * @param {Element} elem + */ ( + function(elem) { + goog.dom.appendChild(this.layersPane_, elem); + }); + } else { + addChild = + /** + * @this {ol.renderer.dom.Map} + * @param {Element} elem + * @param {number} i + */ ( + function(elem, i) { + goog.dom.insertChildAt(this.layersPane_, elem, i); + }); + } + var layerStates = frameState.layerStates; var layersArray = frameState.layersArray; var i, ii, layer, layerRenderer, layerState; for (i = 0, ii = layersArray.length; i < ii; ++i) { layer = layersArray[i]; - layerRenderer = this.getLayerRenderer(layer); + layerRenderer = /** @type {ol.renderer.dom.Layer} */ ( + this.getLayerRenderer(layer)); + goog.asserts.assertInstanceof(layerRenderer, ol.renderer.dom.Layer); + addChild.call(this, layerRenderer.getTarget(), i); layerState = frameState.layerStates[goog.getUid(layer)]; if (layerState.sourceState == ol.source.State.READY) { layerRenderer.prepareFrame(frameState, layerState); diff --git a/src/ol/renderer/dom/domtilelayerrenderer.js b/src/ol/renderer/dom/domtilelayerrenderer.js index a2b9974a16..a8d7b42b0a 100644 --- a/src/ol/renderer/dom/domtilelayerrenderer.js +++ b/src/ol/renderer/dom/domtilelayerrenderer.js @@ -17,6 +17,7 @@ goog.require('ol.TileRange'); goog.require('ol.TileState'); goog.require('ol.ViewHint'); goog.require('ol.dom'); +goog.require('ol.dom.BrowserFeature'); goog.require('ol.extent'); goog.require('ol.layer.Tile'); goog.require('ol.renderer.dom.Layer'); @@ -37,6 +38,12 @@ ol.renderer.dom.TileLayer = function(mapRenderer, tileLayer) { var target = goog.dom.createElement(goog.dom.TagName.DIV); target.style.position = 'absolute'; + // Needed for IE7-8 to render a transformed element correctly + if (ol.dom.BrowserFeature.USE_MS_MATRIX_TRANSFORM) { + target.style.width = '100%'; + target.style.height = '100%'; + } + goog.base(this, mapRenderer, tileLayer, target); /** @@ -229,7 +236,7 @@ ol.renderer.dom.TileLayer.prototype.prepareFrame = } if (layerState.opacity != this.renderedOpacity_) { - goog.style.setOpacity(this.target, layerState.opacity); + ol.dom.setOpacity(this.target, layerState.opacity); this.renderedOpacity_ = layerState.opacity; } @@ -261,6 +268,23 @@ ol.renderer.dom.TileLayerZ_ = function(tileGrid, tileCoordOrigin) { */ this.target = goog.dom.createElement(goog.dom.TagName.DIV); this.target.style.position = 'absolute'; + this.target.style.width = '100%'; + this.target.style.height = '100%'; + + if (ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE) { + /** + * Needed due to issues with IE7-8 clipping of transformed elements + * Solution is to translate separately from the scaled/rotated elements + * @private + * @type {!Element} + */ + this.translateTarget_ = goog.dom.createElement(goog.dom.TagName.DIV); + this.translateTarget_.style.position = 'absolute'; + this.translateTarget_.style.width = '100%'; + this.translateTarget_.style.height = '100%'; + + goog.dom.appendChild(this.target, this.translateTarget_); + } /** * @private @@ -364,7 +388,11 @@ ol.renderer.dom.TileLayerZ_.prototype.addTile = function(tile, tileGutter) { */ ol.renderer.dom.TileLayerZ_.prototype.finalizeAddTiles = function() { if (!goog.isNull(this.documentFragment_)) { - goog.dom.appendChild(this.target, this.documentFragment_); + if (ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE) { + goog.dom.appendChild(this.translateTarget_, this.documentFragment_); + } else { + goog.dom.appendChild(this.target, this.documentFragment_); + } this.documentFragment_ = null; } }; @@ -418,7 +446,12 @@ ol.renderer.dom.TileLayerZ_.prototype.removeTilesOutsideExtent = */ ol.renderer.dom.TileLayerZ_.prototype.setTransform = function(transform) { if (!ol.vec.Mat4.equals2D(transform, this.transform_)) { - ol.dom.transformElement2D(this.target, transform, 6); + if (ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE) { + ol.dom.transformElement2D(this.target, transform, 6, + this.translateTarget_); + } else { + ol.dom.transformElement2D(this.target, transform, 6); + } goog.vec.Mat4.setFromArray(this.transform_, transform); } };