diff --git a/src/component/axis/ParallelAxisView.js b/src/component/axis/ParallelAxisView.js index 964494d0c4e074479ea01458ec38c18bd94ccb24..90d65fb6d9d64eebefb2a23a43595dbe9cd08cca 100644 --- a/src/component/axis/ParallelAxisView.js +++ b/src/component/axis/ParallelAxisView.js @@ -82,8 +82,15 @@ define(function (require) { }); this._brushController - .mount(axisGroup) - .enableBrush({brushType: 'line', brushStyle: areaSelectStyle}) + .mount({container: axisGroup, localCoord: true}) + .setPanels([{ + panelId: 'pl', + rect: axisGroup.getBoundingRect() + }]) + .enableBrush({ + brushType: 'line', + brushStyle: areaSelectStyle + }) .updateCovers(coverInfoList); }, diff --git a/src/component/brush/BrushModel.js b/src/component/brush/BrushModel.js index 5d9ebc104e36c340aa165bba90b41c4422bc5d1a..f0b2ed48d10cd68d4c6b8818ad574fc1901d5990 100644 --- a/src/component/brush/BrushModel.js +++ b/src/component/brush/BrushModel.js @@ -91,7 +91,7 @@ define(function(require) { if (__DEV__) { zrUtil.assert(zrUtil.isArray(brushRanges)); zrUtil.each(brushRanges, function (brushRange) { - zrUtil.assert(brushRange.brushType && brushRange.range, 'Illegal brushRanges'); + zrUtil.assert(brushRange.brushType, 'Illegal brushRanges'); }); } diff --git a/src/component/brush/BrushView.js b/src/component/brush/BrushView.js index 88d789a7c1871caa55587ff7b7ca09e61a960920..3bd0205075fd6cc9680c0acb6eb1c2f87e7db87a 100644 --- a/src/component/brush/BrushView.js +++ b/src/component/brush/BrushView.js @@ -1,16 +1,15 @@ define(function (require) { var zrUtil = require('zrender/core/util'); - var graphic = require('../../util/graphic'); var BrushController = require('../helper/BrushController'); var echarts = require('../../echarts'); + var helper = require('./helper'); return echarts.extendComponentView({ type: 'brush', init: function (ecModel, api) { - var zr = api.getZr(); /** * @readOnly @@ -30,20 +29,13 @@ define(function (require) { */ this.model; - /** - * @private - * @type {module:zrender/container/Group} - */ - var controllerGroup = this._controllerGroup = new graphic.Group(); - zr.add(controllerGroup); - /** * @private * @type {module:echarts/component/helper/BrushController} */ - (this._brushController = new BrushController(zr)) + (this._brushController = new BrushController(api.getZr())) .on('brush', zrUtil.bind(this._onBrush, this)) - .mount(controllerGroup, false); + .mount(); }, /** @@ -51,30 +43,23 @@ define(function (require) { */ render: function (brushModel) { this.model = brushModel; - this._brushController - .enableBrush(brushModel.brushOption) - .updateCovers(brushModel.brushRanges); + return updateController.apply(this, arguments); }, /** * @override */ - updateView: function (brushModel, ecModel, api, payload) { - // Do not update controller when drawing. - payload.$from !== this.model.id && this._brushController - .enableBrush(brushModel.brushOption) - .updateCovers(brushModel.brushRanges); - }, + updateView: updateController, /** * @override */ - updateLayout: function (brushModel, ecModel) { - ecModel.eachComponent({mainType: 'geo'}, function (geoModel) { - var coord = geoModel.coordinateSystem; - console.log(coord.getBoundingRect()); - }); - }, + updateLayout: updateController, + + /** + * @override + */ + updateVisual: updateController, /** * @override @@ -89,9 +74,12 @@ define(function (require) { _onBrush: function (brushRanges, opt) { var modelId = this.model.id; + helper.setCoordRanges(brushRanges, this.ecModel); + // Action is not dispatched on drag end, because the drag end // emits the same params with the last drag move event, and - // may have some delay when using touch pad. + // may have some delay when using touch pad, which makes + // animation not smooth (when using debounce). (!opt.isEnd || opt.removeOnClick) && this.api.dispatchAction({ type: 'brush', brushId: modelId, @@ -102,4 +90,12 @@ define(function (require) { }); + function updateController(brushModel, ecModel, api, payload) { + // Do not update controller when drawing. + (!payload || payload.$from !== brushModel.id) && this._brushController + .setPanels(helper.makePanelOpts(brushModel, ecModel)) + .enableBrush(brushModel.brushOption) + .updateCovers(helper.setPanelId(brushModel.brushRanges)); + } + }); \ No newline at end of file diff --git a/src/component/brush/helper.js b/src/component/brush/helper.js new file mode 100644 index 0000000000000000000000000000000000000000..4b307a16fe39640236f8fccf2bac8020dd561002 --- /dev/null +++ b/src/component/brush/helper.js @@ -0,0 +1,125 @@ +define(function(require) { + + var zrUtil = require('zrender/core/util'); + var graphic = require('../../util/graphic'); + + var each = zrUtil.each; + + var COORD_NAMES = ['geo', 'grid']; + var PANEL_ID_SPLIT = '---'; + + var helper = {}; + + helper.convertCoordRanges = function (ecModel) { + ecModel.eachComponent({mainType: 'brush'}, function (brushModel) { + each(brushModel.brushRanges, function (brushRange) { + each(COORD_NAMES, function (coordName) { + var coordIndex = brushRange[coordName + 'Index']; + var coordRange = brushRange[coordName + 'Range']; + if (coordIndex >= 0 && coordRange) { + var coordModel = ecModel.getComponent(coordName, coordIndex); + brushRange.range = coordModel + ? coordConvert[brushRange.brushType]( + 'dataToPoint', coordModel.coordinateSystem, coordRange + ) + : []; + } + }); + }); + }); + }; + + helper.setCoordRanges = function (brushRanges, ecModel) { + each(brushRanges, function (brushRange) { + var panelId = brushRange.panelId; + if (panelId) { + panelId = brushRange.panelId.split(PANEL_ID_SPLIT); + var coordName = panelId[0]; + var coordIndex = +panelId[1]; + var coordModel = ecModel.getComponent(coordName, coordIndex); + brushRange[coordName + 'Index'] = coordIndex; + brushRange[coordName + 'Range'] = coordConvert[brushRange.brushType]( + 'pointToData', coordModel.coordinateSystem, brushRange.range + ); + } + }); + }; + + helper.setPanelId = function (brushRanges) { + each(brushRanges, function (brushRange) { + each(COORD_NAMES, function (coordName) { + var coordIndex = brushRange[coordName + 'Index']; + if (coordIndex != null) { + brushRange.panelId = coordName + PANEL_ID_SPLIT + coordIndex; + } + }); + }); + return brushRanges; + }; + + helper.makePanelOpts = function (brushModel, ecModel) { + var panelOpts = []; + + each(COORD_NAMES, function (coordName) { + var coordIndices = brushModel.option[coordName + 'Index']; + + if (coordIndices == null) { + return; + } + !zrUtil.isArray(coordIndices) && (coordIndices = [coordIndices]); + + zrUtil.each(coordIndices, function (coordIndex) { + var coordModel = ecModel.getComponent(coordName, coordIndex); + if (!coordModel) { + return; + } + var coordSys = coordModel.coordinateSystem; + // FIXME + // geo is getBoundingRect, grid is getRect. + var r = (coordSys.getRect || coordSys.getBoundingRect).call(coordSys); + var points = [ + [r.x, r.y], + [r.x, r.y + r.height], + [r.x + r.width, r.y + r.height], + [r.x + r.width, r.y] + ]; + + var coordTransform = graphic.getTransform(coordSys); + points = zrUtil.map(points, function (point) { + return graphic.applyTransform(point, coordTransform); + }); + + panelOpts.push({ + panelId: coordName + PANEL_ID_SPLIT + coordIndex, + points: points + }); + }); + }); + + return panelOpts; + }; + + + var coordConvert = { + + line: function (to, coordSys, coordRange) { + return [ + coordSys[to]([coordRange[0], 0]), + coordSys[to]([coordRange[1], 0]) + ]; + }, + + rect: function (to, coordSys, coordRange) { + var xminymin = coordSys[to]([coordRange[0][0], coordRange[1][0]]); + var xmaxymax = coordSys[to]([coordRange[0][1], coordRange[1][1]]); + return [[xminymin[0], xmaxymax[0]], [xminymin[1], xmaxymax[1]]]; + }, + + polygon: function (to, coordSys, coordRange) { + return zrUtil.map(coordRange, coordSys[to], coordSys); + } + }; + + return helper; + +}); \ No newline at end of file diff --git a/src/component/brush/visualEncoding.js b/src/component/brush/visualEncoding.js index 1a034dafb951edf8019276cc52a1f5be8324c68b..864094fb55c4fb05de7675910f85c7f037f6ea1f 100644 --- a/src/component/brush/visualEncoding.js +++ b/src/component/brush/visualEncoding.js @@ -1,5 +1,5 @@ /** - * @file Data range visual coding. + * @file Brush visual coding. */ define(function (require) { @@ -9,15 +9,24 @@ define(function (require) { var BoundingRect = require('zrender/core/BoundingRect'); var selector = require('./selector'); var throttle = require('../../util/throttle'); + var helper = require('./helper'); var STATE_LIST = ['inBrush', 'outOfBrush']; var DISPATCH_METHOD = '__ecBrushSelect'; var DISPATCH_FLAG = '__ecInBrushSelectEvent'; + var PRIORITY_BRUSH = echarts.PRIORITY.VISUAL.BRUSH; + + /** + * Layout for visual, the priority higher than other layout, and before brush visual. + */ + echarts.registerLayout(PRIORITY_BRUSH, function (ecModel, api, payload) { + helper.convertCoordRanges(ecModel); + }); /** * Register the visual encoding if this modules required. */ - echarts.registerVisual(echarts.PRIORITY.VISUAL.BRUSH, function (ecModel, api, payload) { + echarts.registerVisual(PRIORITY_BRUSH, function (ecModel, api, payload) { var brushSelected = []; var throttleType; @@ -48,7 +57,7 @@ define(function (require) { // Add boundingRect and selectors to range. var brushRanges = zrUtil.map(brushModel.brushRanges, function (brushRange) { return bindSelector( - zrUtil.extend( + zrUtil.defaults( {boundingRect: boundingRectBuilders[brushRange.brushType](brushRange)}, brushRange ) diff --git a/src/component/helper/BrushController.js b/src/component/helper/BrushController.js index 63f9f1d6ee0bfe4cd5d1b97040bcb42ecf6155be..0242657ae3be3373c045596d196e6abcbe2270f9 100644 --- a/src/component/helper/BrushController.js +++ b/src/component/helper/BrushController.js @@ -12,7 +12,7 @@ define(function (require) { var interactionMutex = require('./interactionMutex'); var DataDiffer = require('../../data/DataDiffer'); - var bind = zrUtil.bind; + var curry = zrUtil.curry; var each = zrUtil.each; var map = zrUtil.map; var mathMin = Math.min; @@ -58,7 +58,13 @@ define(function (require) { * @constructor * @mixin {module:zrender/mixin/Eventful} * @event module:echarts/component/helper/BrushController#brush - * brushRanges, opt {isEnd, removeOnClick} + * params: + * brushRanges: Array., coord relates to container group, + * If no container specified, to global. + * opt { + * isEnd: boolean, + * removeOnClick: boolean + * } * * @param {module:zrender/zrender~ZRender} zr */ @@ -98,9 +104,15 @@ define(function (require) { /** * @private - * @type {module:zrender/core/BoundingRect} + * @type {Object} */ - this._containerRect = null; + this._panels; + + /** + * @private + * @type {module:zrender/mixin/Transformable} + */ + this._container; /** * @private @@ -130,7 +142,9 @@ define(function (require) { * @private * @type {boolean} */ - this._mounted = false; + if (__DEV__) { + this._mounted; + } /** * @private @@ -144,7 +158,7 @@ define(function (require) { */ this._handlers = {}; each(mouseHandlers, function (handler, eventName) { - this._handlers[eventName] = bind(handler, this); + this._handlers[eventName] = zrUtil.bind(handler, this); }, this); } @@ -168,35 +182,89 @@ define(function (require) { * @param {string} [brushOption.brushStyle.fill] */ enableBrush: function (brushOption) { - if (!this._mounted) { - return; + if (__DEV__) { + zrUtil.assert(this._mounted); } - this._brushType && doDisableBrush.call(this); - brushOption.brushType && doEnableBrush.call(this, brushOption); + this._brushType && doDisableBrush(this); + brushOption.brushType && doEnableBrush(this, brushOption); + + return this; + }, + + /** + * @param {Array.} panelOpts If not pass, it is global brush. + * Each items: {panelId, points} + */ + setPanels: function (panelOpts) { + var oldPanels = this._panels || {}; + var newPanels = this._panels = panelOpts && panelOpts.length && {}; + var thisGroup = this.group; + + newPanels && each(panelOpts, function (panelOpt) { + var panelId = panelOpt.panelId; + var panel = oldPanels[panelId]; + if (!panel) { + panel = new graphic.Polygon({ + // FIXME + // 这样靠谱么? + // silent: true, + // invisible: true, + style: { + fill: 'rgba(0,0,0,0)' + }, + cursor: 'crosshair' + }); + // FIXME + // cursor + // boundingRect will change when dragging, so we have + // to keep initial boundingRect. + thisGroup.add(panel); + } + // FIXME + // only support rect panel now. + panel.attr('shape', {points: panelOpt.points}); + panel.__brushPanelId = panelId; + newPanels[panelId] = panel; + oldPanels[panelId] = null; + }); + + each(oldPanels, function (panel) { + panel && thisGroup.remove(panel); + }); return this; }, /** - * @param {module:zrender/mixin/Transformable} container - * @param {module:zrender/core/BoundingRect|boolean} [rect] If not specified, - * use container.getBoundingRect(). If false, do not use containerRect, - * which means global select. + * @param {Object} opt + * @param {module:zrender/mixin/Transformable} [opt.container] + * @param {boolean} [opt.localCoord=false] Whether input and output with global coord, + * ohterwise coord is according to panel. */ - mount: function (container, rect) { - this._mounted = true; // should be at first. + mount: function (opt) { + opt = opt || {}; - // Remove from old container. - removeGroup.call(this); + if (__DEV__) { + this._mounted = true; // should be at first. + } - // boundingRect will change when dragging, so we have - // to keep initial boundingRect. - this._containerRect = rect !== false - ? (rect || container.getBoundingRect()) : null; + var container = opt.container; + + // Reset container. + if (!this._container || container !== this._container) { + unmountContainer(this); + + if (!container) { + container = new graphic.Group(); + this._zr.add(container); + container.__createdByBrush = true; + } + this._container = container; - // Add to new container. - container.add(this.group); + // Add to new container. + container.add(this.group); + } return this; }, @@ -222,8 +290,8 @@ define(function (require) { * If brushOptionList is null/undefined, all covers removed. */ updateCovers: function (brushOptionList) { - if (!this._mounted) { - return; + if (__DEV__) { + zrUtil.assert(this._mounted); } brushOptionList = zrUtil.map(brushOptionList, function (brushOption) { @@ -235,54 +303,45 @@ define(function (require) { var newCovers = this._covers = []; var controller = this; - (new DataDiffer(oldCovers, brushOptionList, oldGetKey, newGetKey)) - .add(add) - .update(update) + (new DataDiffer(oldCovers, brushOptionList, oldGetKey, getKey)) + .add(addOrUpdate) + .update(addOrUpdate) .remove(remove) .execute(); return this; - function oldGetKey(cover, index) { - var brushOption = cover.__brushOption; - return brushOption.id != null ? brushOption.id : tmpIdPrefix + index; - } - - function newGetKey(brushOption, index) { - return brushOption.id != null ? brushOption.id : tmpIdPrefix + index; + function getKey(brushOption, index) { + return (brushOption.id != null ? brushOption.id : tmpIdPrefix + index) + + '-' + brushOption.brushType; } - function add(newIndex) { - newCovers[newIndex] = createCover.call(controller, brushOptionList[newIndex]); - endCreating.call(controller, newCovers[newIndex]); - updateCoverAfterCreation.call(controller, newCovers[newIndex]); + function oldGetKey(cover, index) { + return getKey(cover.__brushOption, index); } - function update(newIndex, oldIndex) { - var cover = newCovers[newIndex] = oldCovers[oldIndex]; + function addOrUpdate(newIndex, oldIndex) { var newBrushOption = brushOptionList[newIndex]; - - if (newBrushOption.brushType !== cover.__brushOption.brushType) { - controller.group.remove(cover); - cover = createCover.call(controller, newBrushOption); - endCreating.call(controller, cover); - } - - cover.__brushOption = newBrushOption; - updateCoverAfterCreation.call(controller, newCovers[newIndex]); + var cover = newCovers[newIndex] = oldIndex != null + ? (oldCovers[oldIndex].__brushOption = newBrushOption, oldCovers[oldIndex]) + : endCreating(controller, createCover(controller, newBrushOption)); + updateCoverAfterCreation(controller, cover); } function remove(oldIndex) { controller.group.remove(oldCovers[oldIndex]); } + }, unmount: function () { this.enableBrush(false); - removeGroup.call(this); - this._covers = []; - this._mounted = false; // should be at last. + unmountContainer(this); + + if (__DEV__) { + this._mounted = false; // should be at last. + } return this; }, @@ -296,56 +355,59 @@ define(function (require) { zrUtil.mixin(BrushController, Eventful); - function doEnableBrush(brushOption) { - var zr = this._zr; + function doEnableBrush(controller, brushOption) { + var zr = controller._zr; - if (isGlobalBrush(this)) { - // FIXME - // 多个 selectcontroller,区域不一样时,这是否合理? - var onRelease = zrUtil.bind(function (userOnRelease) { - this.enableBrush(false); - userOnRelease && userOnRelease(); - }, this, brushOption.onRelease); + var onRelease = zrUtil.bind(function (userOnRelease) { + controller.enableBrush(false); + userOnRelease && userOnRelease(); + }, controller, brushOption.onRelease); - interactionMutex.take(zr, MUTEX_RESOURCE_KEY, this._uid, onRelease); - zr.setDefaultCursorStyle('crosshair'); - } + // Consider roam, which takes globalPan too. + interactionMutex.take(zr, MUTEX_RESOURCE_KEY, controller._uid, onRelease); + zr.setDefaultCursorStyle('crosshair'); - each(this._handlers, function (handler, eventName) { + each(controller._handlers, function (handler, eventName) { zr.on(eventName, handler); }); - this._brushType = brushOption.brushType; - this._brushOption = zrUtil.merge(zrUtil.clone(DEFAULT_BRUSH_OPT), brushOption, true); + controller._brushType = brushOption.brushType; + controller._brushOption = zrUtil.merge(zrUtil.clone(DEFAULT_BRUSH_OPT), brushOption, true); } - function doDisableBrush() { - var zr = this._zr; + function doDisableBrush(controller) { + var zr = controller._zr; - interactionMutex.release(zr, MUTEX_RESOURCE_KEY, this._uid); + interactionMutex.release(zr, MUTEX_RESOURCE_KEY, controller._uid); zr.setDefaultCursorStyle('default'); - each(this._handlers, function (handler, eventName) { + each(controller._handlers, function (handler, eventName) { zr.off(eventName, handler); }); - this._brushType = this._brushOption = null; + controller._brushType = controller._brushOption = null; } - function createCover(brushOption) { - var cover = coverRenderers[brushOption.brushType].createCover.call(this, brushOption); + function createCover(controller, brushOption) { + var cover = coverRenderers[brushOption.brushType].createCover(controller, brushOption); updateZ(cover); cover.__brushOption = brushOption; - this.group.add(cover); + controller.group.add(cover); return cover; } - function endCreating(creatingCover) { - var coverRenderer = coverRenderers[creatingCover.__brushOption.brushType]; + function endCreating(controller, creatingCover) { + var coverRenderer = getCoverRenderer(creatingCover); if (coverRenderer.endCreating) { - coverRenderer.endCreating.call(this, creatingCover); + coverRenderer.endCreating(controller, creatingCover); updateZ(creatingCover); } + return creatingCover; + } + + function updateCoverShape(controller, cover) { + var brushOption = cover.__brushOption; + getCoverRenderer(cover).updateCoverShape(controller, cover, brushOption.range, brushOption); } function updateZ(group) { @@ -354,42 +416,53 @@ define(function (require) { }); } - function updateCoverAfterCreation(cover) { - var brushOption = cover.__brushOption; - var coverRenderer = coverRenderers[brushOption.brushType]; - coverRenderer.updateCoverShape.call(this, cover); - coverRenderer.updateCommon.call(this, cover); + function updateCoverAfterCreation(controller, cover) { + getCoverRenderer(cover).updateCommon(controller, cover); + updateCoverShape(controller, cover); } - function isInContainer(x, y) { - var localPos = this.group.transformCoordToLocal(x, y); - return !this._containerRect - || this._containerRect.contain(localPos[0], localPos[1]); + function getCoverRenderer(cover) { + return coverRenderers[cover.__brushOption.brushType]; } - function clearCovers() { - each(this._covers, function (cover) { - this.group.remove(cover); - }, this); - this._covers.length = 0; + function getPanelByPoint(controller, x, y) { + if (isGlobalBrush(controller)) { + return {}; + } + var panel; + each(controller._panels, function (pn) { + pn.contain(x, y) && (panel = pn); + }); + return panel; + } + + function clearCovers(controller) { + each(controller._covers, function (cover) { + controller.group.remove(cover); + }, controller); + controller._covers.length = 0; } - function trigger(opt) { - var brushRanges = map(this._covers, function (cover) { + function trigger(controller, opt) { + var brushRanges = map(controller._covers, function (cover) { var brushOption = cover.__brushOption; + var range = zrUtil.clone(brushOption.range); + return { brushType: brushOption.brushType, - range: zrUtil.clone(brushOption.range) + panelId: brushOption.panelId, + range: range }; }); - this.trigger('brush', brushRanges, { + + controller.trigger('brush', brushRanges, { isEnd: !!opt.isEnd, removeOnClick: !!opt.removeOnClick }); } - function shouldShowCover() { - var track = this._track; + function shouldShowCover(controller) { + var track = controller._track; if (!track.length) { return false; @@ -404,47 +477,47 @@ define(function (require) { return dist > UNSELECT_THRESHOLD; } - function removeGroup() { + function unmountContainer(controller) { // container may 'removeAll' outside. - var group = this.group; - var container = group.parent; + clearCovers(controller); + + var group = controller.group; + var container = controller._container; + if (container) { - container.remove(group); + group && container.remove(group); + if (container.__createdByBrush) { + controller._zr.remove(controller._container); + } + controller._container = null; } } function isGlobalBrush(controller) { - return !controller._containerRect; + return !controller._panels; } - function getLocalTrack() { - return map(this._track, function (point) { - return this.group.transformCoordToLocal(point[0], point[1]); - }, this); - } - - function getLocalTrackEnds() { - var localTrack = getLocalTrack.call(this); - var tail = localTrack.length - 1; + function getTrackEnds(track) { + var tail = track.length - 1; tail < 0 && (tail = 0); - return [localTrack[0], localTrack[tail]]; + return [track[0], track[tail]]; } - function createBaseRect(cover, brushOption) { + function createBaseRect(controller, cover, brushOption) { cover.add(new graphic.Rect({ name: 'rect', - style: brushOption.brushStyle, + style: makeStyle(brushOption), silent: true, draggable: true, cursor: 'move', - drift: bind(driftRect, this, cover, 'nswe'), - ondragend: bind(trigger, this, {isEnd: true}) + drift: curry(driftRect, controller, cover, 'nswe'), + ondragend: curry(trigger, controller, {isEnd: true}) })); } - function updateCommon(cover) { + function updateCommon(controller, cover) { var brushOption = cover.__brushOption; - cover.childAt(0).useStyle(brushOption.brushStyle); + cover.childAt(0).useStyle(makeStyle(brushOption)); var transformable = brushOption.transformable; cover.childAt(0).attr({ silent: !transformable, @@ -456,6 +529,10 @@ define(function (require) { cover.childOfName(name).setShape({x: x, y: y, width: w, height: h}); } + function makeStyle(brushOption) { + return zrUtil.defaults({strokeNoScale: true}, brushOption.brushStyle); + } + function formatRectRange(x, y, x2, y2) { var min = [mathMin(x, x2), mathMin(y, y2)]; var max = [mathMax(x, x2), mathMax(y, y2)]; @@ -466,7 +543,7 @@ define(function (require) { ]; } - function driftRect(cover, name, dx, dy) { + function driftRect(controller, cover, name, dx, dy) { var brushOption = cover.__brushOption; var rectRange = brushOption.range; var delta = [dx, dy]; @@ -480,11 +557,11 @@ define(function (require) { rectRange[0][0], rectRange[1][0], rectRange[0][1], rectRange[1][1] ); - updateCoverAfterCreation.call(this, cover); - trigger.call(this, {isEnd: false}); + updateCoverAfterCreation(controller, cover); + trigger(controller, {isEnd: false}); } - function driftPolygon(cover, dx, dy) { + function driftPolygon(controller, cover, dx, dy) { var range = cover.__brushOption.range; each(range, function (point) { @@ -492,8 +569,8 @@ define(function (require) { point[1] += dy; }); - updateCoverAfterCreation.call(this, cover); - trigger.call(this, {isEnd: false}); + updateCoverAfterCreation(controller, cover); + trigger(controller, {isEnd: false}); } function preventDefault(e) { @@ -501,38 +578,44 @@ define(function (require) { rawE.preventDefault && rawE.preventDefault(); } - function updateCoverByMouse(e, isEnd) { + function updateCoverByMouse(controller, e, isEnd) { var x = e.offsetX; var y = e.offsetY; - var creatingCover = this._creatingCover; - var thisBrushOption = this._brushOption; + var creatingCover = controller._creatingCover; + var thisBrushOption = controller._brushOption; + var panel = getPanelByPoint(controller, x, y); - if (isInContainer.call(this, x, y)) { - this._track.push([x, y]); + if (panel || isEnd) { // Outside panel but isEnd, cover creating ends. - if (shouldShowCover.call(this)) { + panel && controller._track.push([x, y]); - if (!creatingCover) { - thisBrushOption.brushMode === 'single' && clearCovers.call(this); - creatingCover = this._creatingCover = - createCover.call(this, zrUtil.clone(thisBrushOption)); - this._covers.push(creatingCover); + if (shouldShowCover(controller)) { + + if (!creatingCover && panel) { + thisBrushOption.brushMode === 'single' && clearCovers(controller); + var brushOption = zrUtil.clone(thisBrushOption); + brushOption.panelId = panel.__brushPanelId; + creatingCover = controller._creatingCover = createCover(controller, brushOption); + controller._covers.push(creatingCover); } - var coverRenderer = coverRenderers[this._brushType]; - var coverBrushOption = creatingCover.__brushOption; + if (creatingCover) { + var coverRenderer = coverRenderers[controller._brushType]; + var coverBrushOption = creatingCover.__brushOption; - coverBrushOption.range = - coverRenderer.getCreatingRange.call(this, isEnd); + coverBrushOption.range = coverRenderer.getCreatingRange( + zrUtil.clone(controller._track) + ); - if (isEnd) { - endCreating.call(this, creatingCover); - coverRenderer.updateCommon.call(this, creatingCover); - } + if (isEnd) { + endCreating(controller, creatingCover); + coverRenderer.updateCommon(controller, creatingCover); + } - coverRenderer.updateCoverShape.call(this, creatingCover); + updateCoverShape(controller, creatingCover); + } - trigger.call(this, {isEnd: isEnd}); + trigger(controller, {isEnd: isEnd}); } else if ( isEnd @@ -544,8 +627,8 @@ define(function (require) { // But a single click do not clear covers, because user may have casual // clicks (for example, click on other component and do not expect covers // disappear). - clearCovers.call(this); - trigger.call(this, {isEnd: isEnd, removeOnClick: true}); + clearCovers(controller); + trigger(controller, {isEnd: isEnd, removeOnClick: true}); } } @@ -563,7 +646,7 @@ define(function (require) { this._creatingCover = null; - if (isInContainer.call(this, x, y)) { + if (getPanelByPoint(this, x, y)) { this._dragging = true; this._track = [[x, y]]; } @@ -575,7 +658,7 @@ define(function (require) { preventDefault(e); - updateCoverByMouse.call(this, e, false); + updateCoverByMouse(this, e, false); } }, @@ -584,7 +667,7 @@ define(function (require) { preventDefault(e); - updateCoverByMouse.call(this, e, true); + updateCoverByMouse(this, e, true); this._dragging = false; this._track = []; @@ -599,28 +682,26 @@ define(function (require) { var coverRenderers = { line: { - createCover: function (brushOption) { + createCover: function (controller, brushOption) { var cover = new graphic.Group(); - createBaseRect.call(this, cover, brushOption); + createBaseRect(controller, cover, brushOption); return cover; }, - getCreatingRange: function () { - var ends = getLocalTrackEnds.call(this); + getCreatingRange: function (track) { + var ends = getTrackEnds(track); var min = mathMin(ends[0][0], ends[1][0]); var max = mathMax(ends[0][0], ends[1][0]); return [min, max]; }, - updateCoverShape: function (cover) { - var info = cover.__brushOption; - var range = info.range; - var width = info.brushStyle.width; + updateCoverShape: function (controller, cover, localRange, brushOption) { + var width = brushOption.brushStyle.width; cover.childOfName('rect').setShape({ - x: range[0], + x: localRange[0], y: -width / 2, - width: range[1] - range[0], + width: localRange[1] - localRange[0], height: width }); }, @@ -628,10 +709,10 @@ define(function (require) { }, rect: { - createCover: function (brushOption) { + createCover: function (controller, brushOption) { var cover = new graphic.Group(); - createBaseRect.call(this, cover, brushOption); + createBaseRect(controller, cover, brushOption); each( ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw'], @@ -641,30 +722,27 @@ define(function (require) { __cursor: CURSOR_MAP[name] + '-resize', style: {opacity: 0}, draggable: true, - drift: bind(driftRect, this, cover, name), - ondragend: bind(trigger, this, {isEnd: true}) + drift: curry(driftRect, controller, cover, name), + ondragend: curry(trigger, controller, {isEnd: true}) })); - }, - this + } ); return cover; }, - getCreatingRange: function () { - var ends = getLocalTrackEnds.call(this); + getCreatingRange: function (track) { + var ends = getTrackEnds(track); return formatRectRange(ends[1][0], ends[1][1], ends[0][0], ends[0][1]); }, - updateCoverShape: function (cover) { - var info = cover.__brushOption; - var range = info.range; - var lineWidth = info.brushStyle.lineWidth || 0; + updateCoverShape: function (controller, cover, localRange, brushOption) { + var lineWidth = brushOption.brushStyle.lineWidth || 0; var handleSize = mathMax(lineWidth, MIN_RESIZE_LINE_WIDTH); - var x = range[0][0]; - var y = range[1][0]; + var x = localRange[0][0]; + var y = localRange[1][0]; var xa = x - lineWidth / 2; var ya = y - lineWidth / 2; - var x2 = range[0][1]; - var y2 = range[1][1]; + var x2 = localRange[0][1]; + var y2 = localRange[1][1]; var x2a = x2 - handleSize + lineWidth / 2; var y2a = y2 - handleSize + lineWidth / 2; var width = x2 - x; @@ -674,7 +752,7 @@ define(function (require) { updateRectShape(cover, 'rect', x, y, width, height); - if (info.transformable) { + if (brushOption.transformable) { updateRectShape(cover, 'w', xa, ya, handleSize, heighta); updateRectShape(cover, 'e', x2a, ya, handleSize, heighta); updateRectShape(cover, 'n', xa, ya, widtha, handleSize); @@ -686,8 +764,8 @@ define(function (require) { updateRectShape(cover, 'se', x2a, y2a, handleSize, handleSize); } }, - updateCommon: function (cover) { - updateCommon.call(this, cover); + updateCommon: function (controller, cover) { + updateCommon(controller, cover); var transformable = cover.__brushOption.transformable; each( ['w', 'e', 'n', 's', 'se', 'sw', 'ne', 'nw'], @@ -697,39 +775,38 @@ define(function (require) { silent: !transformable, cursor: transformable ? el.__cursor : 'default' }); - }, - this + } ); } }, polygon: { - createCover: function (brushOption) { + createCover: function (controller, brushOption) { var cover = new graphic.Group(); // Do not use graphic.Polygon because graphic.Polyline do not close the // border of the shape when drawing, which is a better experience for user. cover.add(new graphic.Polyline({ - style: brushOption.brushStyle, + style: makeStyle(brushOption), silent: true })); return cover; }, - getCreatingRange: function (isEnd) { - return this._track.slice(); + getCreatingRange: function (track) { + return track; }, - endCreating: function (cover) { + endCreating: function (controller, cover) { cover.remove(cover.childAt(0)); // Use graphic.Polygon close the shape. cover.add(new graphic.Polygon({ draggable: true, - drift: bind(driftPolygon, this, cover), - ondragend: bind(trigger, this, {isEnd: true}) + drift: curry(driftPolygon, controller, cover), + ondragend: curry(trigger, controller, {isEnd: true}) })); }, - updateCoverShape: function (cover) { - cover.childAt(0).setShape({points: cover.__brushOption.range}); + updateCoverShape: function (controller, cover, localRange, brushOption) { + cover.childAt(0).setShape({points: localRange}); }, updateCommon: updateCommon } diff --git a/src/component/toolbox/feature/DataZoom.js b/src/component/toolbox/feature/DataZoom.js index f6065a1cc1fe681e26d9e06137b6b0339961cf6f..c8e1dc9b08d058ace75c5eb634d68b7600fd6358 100644 --- a/src/component/toolbox/feature/DataZoom.js +++ b/src/component/toolbox/feature/DataZoom.js @@ -5,7 +5,6 @@ define(function(require) { var numberUtil = require('../../../util/number'); var BrushController = require('../../helper/BrushController'); var BoundingRect = require('zrender/core/BoundingRect'); - var Group = require('zrender/container/Group'); var history = require('../../dataZoom/history'); var each = zrUtil.each; @@ -22,22 +21,14 @@ define(function(require) { this.model = model; this.ecModel = ecModel; this.api = api; - var zr = api.getZr(); - - /** - * @private - * @type {module:zrender/container/Group} - */ - var controllerGroup = this._controllerGroup = new Group(); - zr.add(controllerGroup); /** * @private * @type {module:echarts/component/helper/BrushController} */ - (this._brushController = new BrushController(zr)) + (this._brushController = new BrushController(api.getZr())) .on('brush', zrUtil.bind(this._onBrush, this)) - .mount(controllerGroup, false); + .mount(); /** * Is zoom active. @@ -75,9 +66,7 @@ define(function(require) { }; proto.dispose = function (ecModel, api) { - var zr = api.getZr(); this._brushController.dispose(); - this._controllerGroup && zr.remove(this._controllerGroup); }; /** diff --git a/test/brush.html b/test/brush.html index 090258db74219aff59543cafbd4f114f0302c028..08dede1792703c83e050581fea7f7c3f5544a63b 100644 --- a/test/brush.html +++ b/test/brush.html @@ -87,7 +87,7 @@
Scatter
-
+
    @@ -115,8 +115,8 @@
DIFF with previous selected: - Y - N + Y + N
animation: @@ -144,7 +144,7 @@
Stacked Bar (rect-polygon intersect)
-
+
  • CHECK: rect-polygon intersect.
  • @@ -510,7 +510,7 @@ var smSettings = { seperatedEChartsInstance: false, - diff: true, + diff: false, animation: true, animationDurationUpdate: 1000, throttleDelay: 300, @@ -575,15 +575,6 @@ } } }, - legend: { - orient: 'vertical', - top: 'bottom', - left: 'right', - data:['pm2.5'], - textStyle: { - color: '#fff' - } - }, brush: { outOfBrush: { color: '#abc' @@ -591,10 +582,19 @@ seriesIndex: [0, 1], throttleType: smSettings.throttleType, throttleDelay: smSettings.throttleDelay, + geoIndex: 0, brushRanges: [ + // { + // geoIndex: 0, + // brushType: 'polygon', + // range: [[482,130],[481,130],[470,123],[406,100],[387,94],[377,88],[374,83],[373,81],[366,76],[360,74],[355,73],[346,79],[337,83],[323,84],[301,84],[297,84],[281,88],[265,92],[265,93],[258,120],[265,144],[272,148],[297,168],[319,192],[324,200],[324,201],[325,205],[337,229],[342,240],[343,242],[343,243],[344,247],[345,250],[350,261],[354,268],[355,274],[355,281],[347,300],[342,319],[336,352],[333,388],[336,424],[351,442],[364,451],[375,455],[392,466],[401,474],[409,483],[419,493],[432,502],[453,502],[487,484],[521,436],[536,364],[539,322],[539,309],[537,305],[537,304],[536,295],[517,273],[511,264],[511,264]] + // } { + geoIndex: 0, brushType: 'polygon', - range: [[482,130],[481,130],[470,123],[406,100],[387,94],[377,88],[374,83],[373,81],[366,76],[360,74],[355,73],[346,79],[337,83],[323,84],[301,84],[297,84],[281,88],[265,92],[265,93],[258,120],[265,144],[272,148],[297,168],[319,192],[324,200],[324,201],[325,205],[337,229],[342,240],[343,242],[343,243],[344,247],[345,250],[350,261],[354,268],[355,274],[355,281],[347,300],[342,319],[336,352],[333,388],[336,424],[351,442],[364,451],[375,455],[392,466],[401,474],[409,483],[419,493],[432,502],[453,502],[487,484],[521,436],[536,364],[539,322],[539,309],[537,305],[537,304],[536,295],[517,273],[511,264],[511,264]] + // geoRange: [[121.15,31.89], [120.95,31.39], [112.91,27.87], [118.78,32.04]] + // geoRange: [[121.15, 31.89], [121.15, 31.89], [109.781327, 39.608266], [120.38, 37.35], [122.207216, 29.985295], [123.97, 47.33]] + geoRange: [[117.27,31.86], [114.31,30.52], [126.57,43.87]] } ] }, @@ -736,7 +736,8 @@ option.grid.width = '30%'; } - var oldSelectedItems = []; + var oldCategoryData = []; + var oldBarData = []; chart.on('brushSelected', renderBrushed); chart.setOption(option, true); @@ -758,8 +759,6 @@ var brushComponent = params.brushComponents[0]; var selectedItems = []; - var isDiff; - for (var sIdx = 0; sIdx < brushComponent.series.length; sIdx++) { var rawIndices = brushComponent.series[sIdx].rawIndices; var placesBySeries = []; @@ -781,18 +780,6 @@ brushed.push('[Series ' + sIdx + '] ' + placesBySeries.join(', ')); } - if (selectedItems.length !== oldSelectedItems.length) { - isDiff = true; - } - else { - for (var i = 0; i < selectedItems.length; i++) { - if (selectedItems[i].value !== oldSelectedItems[i].value - || selectedItems[i].name !== oldSelectedItems[i].name - ) { - isDiff = true; - } - } - } panel.innerHTML = [ '

    STATISTICS:

    ', @@ -817,6 +804,11 @@ barData.push(selectedItems[i].value[2]); } + var isDiff = checkDiff(categoryData, oldCategoryData) + || checkDiff(barData, oldBarData); + oldCategoryData = categoryData; + oldBarData = barData; + if (!smSettings.diff || isDiff) { var targetName = smSettings.seperatedEChartsInstance ? 'chart2' : 'mainChart'; smSettings.diff @@ -830,8 +822,21 @@ } - if (smSettings.diff && !isDiff) { - console.log('check diff and NO DIFF'); + // if (smSettings.diff && !isDiff) { + // console.log('check diff and NO DIFF'); + // } + } + + function checkDiff(list, oldList) { + if (list.length !== oldList.length) { + return true; + } + else { + for (var i = 0; i < list.length; i++) { + if (list[i] !== oldList[i]) { + return true; + } + } } } }