diff --git a/changelog/upgrade-notes.md b/changelog/upgrade-notes.md index e1c65292b1..6584dd9c61 100644 --- a/changelog/upgrade-notes.md +++ b/changelog/upgrade-notes.md @@ -1,5 +1,11 @@ ## Upgrade notes +### v3.5.0 + +* When manually loading an image for `ol.style.Icon`, the image size should now be set +with the `imgSize` option and not with `size`. `size` is supposed to be used for the +size of a sub-rectangle in an image sprite. + ### v3.4.0 ### v3.3.0 diff --git a/externs/olx.js b/externs/olx.js index 1789574ec3..99146c9010 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -6064,6 +6064,7 @@ olx.style.FillOptions.prototype.color; * rotateWithView: (boolean|undefined), * rotation: (number|undefined), * size: (ol.Size|undefined), + * imgSize: (ol.Size|undefined), * src: (string|undefined)}} * @api */ @@ -6122,7 +6123,7 @@ olx.style.IconOptions.prototype.crossOrigin; /** * Image object for the icon. If the `src` option is not provided then the * provided image must already be loaded. And in that case, it is required - * to provide the size of the image, with the `size` option. + * to provide the size of the image, with the `imgSize` option. * @type {Image|undefined} * @api */ @@ -6196,14 +6197,21 @@ olx.style.IconOptions.prototype.rotation; /** * Icon size in pixel. Can be used together with `offset` to define the - * sub-rectangle to use from the origin (sprite) icon image. Also, setting - * the `size` is required if `img` is set and `src` is not. + * sub-rectangle to use from the origin (sprite) icon image. * @type {ol.Size|undefined} * @api */ olx.style.IconOptions.prototype.size; +/** + * Image size in pixel. Only required if `img` is set and `src` is not. + * @type {ol.Size|undefined} + * @api + */ +olx.style.IconOptions.prototype.imgSize; + + /** * Image source URI. * @type {string} diff --git a/src/ol/style/iconstyle.js b/src/ol/style/iconstyle.js index 83b9207332..ab1aafd09c 100644 --- a/src/ol/style/iconstyle.js +++ b/src/ol/style/iconstyle.js @@ -95,16 +95,30 @@ ol.style.Icon = function(opt_options) { */ var image = goog.isDef(options.img) ? options.img : null; + /** + * @type {ol.Size} + */ + var imgSize = goog.isDef(options.imgSize) ? options.imgSize : null; + /** * @type {string|undefined} */ var src = options.src; + goog.asserts.assert(!(goog.isDef(src) && !goog.isNull(image)), + 'image and src can not provided at the same time'); + goog.asserts.assert( + !goog.isDef(src) || (goog.isDef(src) && goog.isNull(imgSize)), + 'imgSize should not be set when src is provided'); + goog.asserts.assert( + goog.isNull(image) || (!goog.isNull(image) && !goog.isNull(imgSize)), + 'imgSize must be set when image is provided'); + if ((!goog.isDef(src) || src.length === 0) && !goog.isNull(image)) { src = image.src; } goog.asserts.assert(goog.isDef(src) && src.length > 0, - 'must provide a defined and non-empty src'); + 'must provide a defined and non-empty src or image'); /** * @type {ol.style.ImageState} @@ -117,7 +131,7 @@ ol.style.Icon = function(opt_options) { * @type {ol.style.IconImage_} */ this.iconImage_ = ol.style.IconImage_.get( - image, src, crossOrigin, imageState); + image, src, imgSize, crossOrigin, imageState); /** * @private @@ -351,12 +365,13 @@ ol.style.Icon.prototype.unlistenImageChange = function(listener, thisArg) { * @constructor * @param {Image} image Image. * @param {string|undefined} src Src. + * @param {ol.Size} size Size. * @param {?string} crossOrigin Cross origin. * @param {ol.style.ImageState} imageState Image state. * @extends {goog.events.EventTarget} * @private */ -ol.style.IconImage_ = function(image, src, crossOrigin, imageState) { +ol.style.IconImage_ = function(image, src, size, crossOrigin, imageState) { goog.base(this); @@ -392,7 +407,7 @@ ol.style.IconImage_ = function(image, src, crossOrigin, imageState) { * @private * @type {ol.Size} */ - this.size_ = null; + this.size_ = size; /** * @private @@ -413,15 +428,17 @@ goog.inherits(ol.style.IconImage_, goog.events.EventTarget); /** * @param {Image} image Image. * @param {string} src Src. + * @param {ol.Size} size Size. * @param {?string} crossOrigin Cross origin. * @param {ol.style.ImageState} imageState Image state. * @return {ol.style.IconImage_} Icon image. */ -ol.style.IconImage_.get = function(image, src, crossOrigin, imageState) { +ol.style.IconImage_.get = function(image, src, size, crossOrigin, imageState) { var iconImageCache = ol.style.IconImageCache.getInstance(); var iconImage = iconImageCache.get(src, crossOrigin); if (goog.isNull(iconImage)) { - iconImage = new ol.style.IconImage_(image, src, crossOrigin, imageState); + iconImage = new ol.style.IconImage_( + image, src, size, crossOrigin, imageState); iconImageCache.set(src, crossOrigin, iconImage); } return iconImage; diff --git a/test/spec/ol/style/iconstyle.test.js b/test/spec/ol/style/iconstyle.test.js index e84d55aba1..2fa88d5981 100644 --- a/test/spec/ol/style/iconstyle.test.js +++ b/test/spec/ol/style/iconstyle.test.js @@ -109,6 +109,32 @@ describe('ol.style.Icon', function() { expect(iconStyle.getOrigin()).to.eql([92, 20]); }); }); + + describe('#getImageSize', function() { + var imgSize = [144, 192]; + + it('takes the real image size', function() { + // pretend that the image is already in the cache, + // this image will be used for the icon. + var cache = ol.style.IconImageCache.getInstance(); + var src = 'test.png'; + var iconImage = new ol.style.IconImage_(null, 'test.png', imgSize); + cache.set(src, null, iconImage); + + var iconStyle = new ol.style.Icon({ + src: 'test.png' + }); + expect(iconStyle.getImageSize()).to.eql(imgSize); + }); + + it('uses the given image size', function() { + var iconStyle = new ol.style.Icon({ + img: {src: 'test.png'}, + imgSize: imgSize + }); + expect(iconStyle.getImageSize()).to.eql(imgSize); + }); + }); }); describe('ol.style.IconImageCache', function() {