diff --git a/src/geo/Extent.js b/src/geo/Extent.js index 2f1044803..cf4e12c72 100644 --- a/src/geo/Extent.js +++ b/src/geo/Extent.js @@ -392,6 +392,7 @@ class Extent { this.ymin = ymin; this.xmax = xmax; this.ymax = ymax; + this._dirty = true; return this; } @@ -567,7 +568,7 @@ class Extent { } const e = out || new this.constructor(); if (out) { - e.xmin = e.ymin = e.xmax = e.ymax = 0; + e.set(null, null, null, null); } let coord; if (this._clazz === Coordinate) { @@ -589,6 +590,9 @@ class Extent { _project(ext) { if (!ext || !ext.isValid()) { + if (ext) { + ext.pxmin = ext.pxmax = ext.pymin = ext.pymax = null; + } return; } const proj = this.projection; diff --git a/src/renderer/geometry/Painter.js b/src/renderer/geometry/Painter.js index a7cb3833e..6018e3d97 100644 --- a/src/renderer/geometry/Painter.js +++ b/src/renderer/geometry/Painter.js @@ -528,26 +528,32 @@ class Painter extends Class { const map = this.getMap(); resources = resources || this.getLayer()._getRenderer().resources; const zoom = map.getZoom(); - if (!this._extent2D || this._extent2D._zoom !== zoom) { - delete this._extent2D; - delete this._fixedExtent; + const isDynamicSize = this._isDynamicSize(); + if (!this._extent2D || this._extent2D._zoom !== zoom || !this._fixedExtent) { + if (this._extent2D && this._extent2D._zoom !== zoom) { + delete this._extent2D; + } if (this.symbolizers) { - const extent = this._extent2D = new PointExtent(); - const fixedExt = this._fixedExtent = new PointExtent(); - for (let i = this.symbolizers.length - 1; i >= 0; i--) { - const symbolizer = this.symbolizers[i]; - extent._combine(symbolizer.get2DExtent()); - if (symbolizer.getFixedExtent) { - fixedExt._combine(symbolizer.getFixedExtent(resources)); - } + if (!this._extent2D) { + this._extent2D = this._computeExtent2D(new PointExtent()); + this._extent2D._zoom = zoom; + } + if (!this._fixedExtent) { + this._fixedExtent = this._computeFixedExtent(resources, new PointExtent()); } - extent._zoom = zoom; } } + if (!this._extent2D) { + if (isDynamicSize) { + delete this._fixedExtent; + } return null; } const { xmin, ymin, xmax, ymax } = this._fixedExtent; + if (isDynamicSize) { + delete this._fixedExtent; + } //2d 坐标系是opengl规则,y轴方向与containerPoint是反向的 TEMP_FIXED_EXTENT.set(xmin, -ymax, xmax, -ymin); if (out) { @@ -558,6 +564,34 @@ class Painter extends Class { return this._extent2D.add(TEMP_FIXED_EXTENT); } + _computeExtent2D(extent) { + for (let i = this.symbolizers.length - 1; i >= 0; i--) { + const symbolizer = this.symbolizers[i]; + extent._combine(symbolizer.get2DExtent()); + } + return extent; + } + + _computeFixedExtent(resources, extent) { + for (let i = this.symbolizers.length - 1; i >= 0; i--) { + const symbolizer = this.symbolizers[i]; + if (symbolizer.getFixedExtent) { + extent._combine(symbolizer.getFixedExtent(resources)); + } + } + return extent; + } + + _isDynamicSize() { + for (let i = this.symbolizers.length - 1; i >= 0; i--) { + const symbolizer = this.symbolizers[i]; + if (symbolizer.isDynamicSize()) { + return true; + } + } + return false; + } + getContainerExtent(out) { if (this._aboveCamera()) { return null; @@ -582,7 +616,7 @@ class Painter extends Class { extent._combine(groundExtent); } if (extent) { - extent._add(this._fixedExtent); + extent._add(this._fixedExtent || this._computeFixedExtent(null, new PointExtent())); } const smoothness = this.geometry.options['smoothness']; if (smoothness) { @@ -601,6 +635,9 @@ class Painter extends Class { getFixedExtent() { const map = this.getMap(); const zoom = map.getZoom(); + if (this._isDynamicSize()) { + return this._computeFixedExtent(null, new PointExtent()); + } if (!this._extent2D || this._extent2D._zoom !== zoom) { this.get2DExtent(null, TEMP_FIXED_EXTENT); } diff --git a/src/renderer/geometry/symbolizers/PointSymbolizer.js b/src/renderer/geometry/symbolizers/PointSymbolizer.js index 37a85ced8..301bcd54f 100644 --- a/src/renderer/geometry/symbolizers/PointSymbolizer.js +++ b/src/renderer/geometry/symbolizers/PointSymbolizer.js @@ -2,6 +2,7 @@ import { computeDegree } from '../../../core/util'; import PointExtent from '../../../geo/PointExtent'; import Point from '../../../geo/Point'; import CanvasSymbolizer from './CanvasSymbolizer'; +import { isFunctionDefinition } from '../../../core/mapbox'; const TEMP_POINT0 = new Point(0, 0); const TEMP_POINT1 = new Point(0, 0); @@ -38,6 +39,12 @@ class PointSymbolizer extends CanvasSymbolizer { return extent; } + isDynamicSize() { + const symbol = this.symbol; + return isFunctionDefinition(symbol['markerWidth']) || isFunctionDefinition(symbol['markerHeight']) || + isFunctionDefinition(symbol['textSize']); + } + _rotateExtent(fixedExtent, angle) { return fixedExtent.convertTo(p => p._rotate(angle)); } diff --git a/src/renderer/geometry/symbolizers/Symbolizer.js b/src/renderer/geometry/symbolizers/Symbolizer.js index fa2ec23eb..322f6d77b 100644 --- a/src/renderer/geometry/symbolizers/Symbolizer.js +++ b/src/renderer/geometry/symbolizers/Symbolizer.js @@ -18,6 +18,10 @@ class Symbolizer { return this.painter; } + isDynamicSize() { + return false; + } + /** * Test if the property is a property related with coloring * @param {String} prop - property name to test diff --git a/src/renderer/geometry/symbolizers/VectorMarkerSymbolizer.js b/src/renderer/geometry/symbolizers/VectorMarkerSymbolizer.js index 4d51f0997..9cd83576a 100644 --- a/src/renderer/geometry/symbolizers/VectorMarkerSymbolizer.js +++ b/src/renderer/geometry/symbolizers/VectorMarkerSymbolizer.js @@ -1,7 +1,7 @@ import { isNil, isNumber, isArrayHasData, getValueOrDefault, sign } from '../../../core/util'; import { isGradient, getGradientStamp } from '../../../core/util/style'; import { getAlignPoint } from '../../../core/util/strings'; -import { hasFunctionDefinition } from '../../../core/mapbox'; +import { hasFunctionDefinition, isFunctionDefinition } from '../../../core/mapbox'; import Size from '../../../geo/Size'; import Point from '../../../geo/Point'; import PointExtent from '../../../geo/PointExtent'; @@ -109,6 +109,9 @@ export default class VectorMarkerSymbolizer extends PointSymbolizer { shadow = 2 * (this.symbol['shadowBlur'] || 0), // add some tolerance for shadowOffsetX/Y w = Math.round(this.style['markerWidth'] + lineWidth + 2 * shadow + this.padding * 2), h = Math.round(this.style['markerHeight'] + lineWidth + 2 * shadow + this.padding * 2); + if (isFunctionDefinition(this.symbol['markerWidth']) || isFunctionDefinition(this.symbol['markerHeight'])) { + return [w, h]; + } this._size = [w, h]; } return this._size; diff --git a/test/geometry/event/GeometryEventSpec.js b/test/geometry/event/GeometryEventSpec.js index c70b06a4f..f0eb4f4bf 100644 --- a/test/geometry/event/GeometryEventSpec.js +++ b/test/geometry/event/GeometryEventSpec.js @@ -1,5 +1,4 @@ describe('Geometry.Events', function () { - var container; var map; var center = new maptalks.Coordinate(118.846825, 32.046534); @@ -227,4 +226,46 @@ describe('Geometry.Events', function () { }); expect(spy.called).not.to.be.ok(); }); + + it('#1029, event for invisible dynamic size marker', function () { + var circle = new maptalks.Marker(map.getCenter(), { + 'symbol': { + 'markerType': 'circle', + 'markerWidth': {stops: [[18, 0], [20, 30]]}, + 'markerHeight': {stops: [[18, 0], [20, 30]]}, + } + }); + circle.addTo(layer); + var domPosition = GET_PAGE_POSITION(container); + var point = map.coordinateToContainerPoint(center).add(domPosition); + var spy = sinon.spy(); + circle.on('click', spy); + + happen.click(eventContainer, { + 'clientX':point.x + 1, + 'clientY':point.y + }); + expect(spy.called).not.to.be.ok(); + }); + + it('#1029, event for visible dynamic size marker', function () { + var circle = new maptalks.Marker(map.getCenter(), { + 'symbol': { + 'markerType': 'circle', + 'markerWidth': {stops: [[10, 0], [20, 30]]}, + 'markerHeight': {stops: [[10, 0], [20, 30]]}, + } + }); + circle.addTo(layer); + var domPosition = GET_PAGE_POSITION(container); + var point = map.coordinateToContainerPoint(center).add(domPosition); + var spy = sinon.spy(); + circle.on('click', spy); + + happen.click(eventContainer, { + 'clientX':point.x + 1, + 'clientY':point.y + }); + expect(spy.called).to.be.ok(); + }); });