From f5786a4a6c36fb98e602b75d568047b69bf5207b Mon Sep 17 00:00:00 2001 From: Ovilia Date: Tue, 4 Jun 2019 12:54:43 +0800 Subject: [PATCH 001/127] ci: configure file for stale robot --- .github/stale.yml | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000000..29c704e1ce --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,59 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 730 # two years + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 7 + +# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) +onlyLabels: [] + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - "maybe-later" + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: true + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Set to true to ignore issues with an assignee (defaults to false) +exemptAssignees: false + +# Label to use when marking as stale +staleLabel: stale + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. + +# Comment to post when closing a stale Issue or Pull Request. +# closeComment: > +# Your comment here. + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +# only: issues + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +# pulls: +# daysUntilStale: 30 +# markComment: > +# This pull request has been automatically marked as stale because it has not had +# recent activity. It will be closed if no further activity occurs. Thank you +# for your contributions. + +# issues: +# exemptLabels: +# - confirmed From 5fb263fb772ef9ea9ad8b4f9fe816124aa14f943 Mon Sep 17 00:00:00 2001 From: deqingli Date: Thu, 20 Jun 2019 19:10:37 +0800 Subject: [PATCH 002/127] feat(legend): add selector in plain legend --- src/component/legend/LegendModel.js | 103 +++++++++++++++++ src/component/legend/LegendView.js | 160 +++++++++++++++++++++++++-- src/component/legend/legendAction.js | 25 ++++- src/echarts.js | 2 +- src/model/Global.js | 4 +- src/util/graphic.js | 17 ++- 6 files changed, 292 insertions(+), 19 deletions(-) diff --git a/src/component/legend/LegendModel.js b/src/component/legend/LegendModel.js index c4329590fb..255c7f6fbd 100644 --- a/src/component/legend/LegendModel.js +++ b/src/component/legend/LegendModel.js @@ -44,10 +44,38 @@ var LegendModel = echarts.extendComponentModel({ this.mergeDefaultAndTheme(option, ecModel); option.selected = option.selected || {}; + this._updateSelector(option); }, mergeOption: function (option) { LegendModel.superCall(this, 'mergeOption', option); + this._updateSelector(option); + }, + + _updateSelector: function (option) { + var selector = option.selector; + var defaultAllIcon = 'M421.65 752.94h-60.24v60.24c0 18.07 12.05 30.12 30.12 30.12h421.65c18.07 0 30.12-12.05 30.12-30.12V391.53c0-18.07-12.05-30.12-30.12-30.12h-60.24v361.42c0 18.07-12.05 30.12-30.12 30.12H421.65z m271.06-572.23H210.82c-18.07 0-30.12 12.05-30.12 30.12v481.88c0 18.07 12.05 30.12 30.12 30.12h481.89c18.07 0 30.12-12.05 30.12-30.12V210.82c-0.01-18.07-12.05-30.11-30.12-30.11zM30.12 421.65c18.07 0 30.12-12.05 30.12-30.12V60.24h331.29c18.07 0 30.12-12.05 30.12-30.12S409.6 0 391.53 0H30.12C12.05 0 0 12.05 0 30.12v361.41c0 18.07 12.05 30.12 30.12 30.12z m361.41 542.11H60.24V632.47c0-18.07-12.05-30.12-30.12-30.12S0 614.4 0 632.47v361.41c0 18.07 12.05 30.12 30.12 30.12h361.41c18.07 0 30.12-12.05 30.12-30.12s-12.05-30.12-30.12-30.12z m602.35-361.41c-18.07 0-30.12 12.05-30.12 30.12v331.29H632.47c-18.07 0-30.12 12.05-30.12 30.12S614.4 1024 632.47 1024h361.41c18.07 0 30.12-12.05 30.12-30.12V632.47c0-18.07-12.05-30.12-30.12-30.12z m0-602.35H512c-18.07 0-30.12 12.05-30.12 30.12S493.93 60.24 512 60.24h451.76v331.29c0 18.07 12.05 30.12 30.12 30.12S1024 409.6 1024 391.53V30.12C1024 12.05 1011.95 0 993.88 0z'; + var defaultInverseIcon = 'M843.29 331.28v481.9c0 16.65-13.47 30.12-30.12 30.12H331.3c-16.65 0-30.12-13.47-30.12-30.12v-60.23h421.63c16.65 0 30.12-13.47 30.12-30.12V301.17h60.23c16.65 0 30.13 13.47 30.13 30.11zM722.82 692.72v-481.9c0-16.65-13.47-30.12-30.12-30.12H210.83c-16.65 0-30.12 13.47-30.12 30.12v481.9c0 16.65 13.47 30.12 30.12 30.12H692.7c16.65-0.01 30.12-13.48 30.12-30.12zM240.95 240.93h421.63V662.6H240.95V240.93zM60.25 391.52V60.23h331.28c16.65 0 30.12-13.47 30.12-30.12S408.18 0 391.53 0H30.13C13.48 0 0.01 13.47 0.01 30.12v361.4c0 16.65 13.47 30.12 30.12 30.12s30.12-13.48 30.12-30.12z m361.4 602.36c0-16.65-13.47-30.12-30.12-30.12H60.25V632.48c0-16.65-13.47-30.12-30.12-30.12S0.01 615.84 0.01 632.48v361.4c0 16.65 13.47 30.12 30.12 30.12h361.4c16.65 0 30.12-13.47 30.12-30.12z m602.34 0v-361.4c0-16.65-13.47-30.12-30.12-30.12s-30.12 13.47-30.12 30.12v331.28H632.47c-16.65 0-30.12 13.47-30.12 30.12s13.47 30.12 30.12 30.12h361.4c16.65 0 30.12-13.47 30.12-30.12z m0-602.36V30.12c0-16.65-13.47-30.12-30.12-30.12h-361.4c-16.65 0-30.12 13.47-30.12 30.12s13.47 30.12 30.12 30.12h331.28v331.28c0 16.65 13.47 30.12 30.12 30.12 16.65-0.01 30.12-13.48 30.12-30.12z'; + + if (selector === true) { + option.selector = [{ + type: 'all', + title: '全选', + icon: defaultAllIcon + }, { + type: 'inverse', + title: '反选', + icon: defaultInverseIcon + }]; + } + else if (zrUtil.isArray(selector)) { + zrUtil.each(selector, function (item) { + var type = item.type; + item.icon = item.icon + || (type === 'all' ? defaultAllIcon : defaultInverseIcon); + item.title = item.title || (type === 'all' ? '全选' : '反选'); + }); + } }, optionUpdated: function () { @@ -176,6 +204,27 @@ var LegendModel = echarts.extendComponentModel({ this[selected[name] ? 'unSelect' : 'select'](name); }, + allSelect: function () { + var data = this._data; + var selected = this.option.selected; + zrUtil.each(data, function (dataItem) { + selected[dataItem.get('name', true)] = true; + }); + }, + + inverseSelect: function () { + var data = this._data; + var selected = this.option.selected; + zrUtil.each(data, function (dataItem) { + var name = dataItem.get('name', true); + // Initially, default value is true + if (!selected.hasOwnProperty(name)) { + selected[name] = true; + } + selected[name] = !selected[name]; + }); + }, + /** * @param {string} name */ @@ -185,6 +234,12 @@ var LegendModel = echarts.extendComponentModel({ && zrUtil.indexOf(this._availableNames, name) >= 0; }, + getOrient: function () { + return this.get('orient') === 'vertical' + ? {index: 1, name: 'vertical'} + : {index: 0, name: 'horizontal'}; + }, + defaultOption: { // 一级层叠 zlevel: 0, @@ -239,6 +294,54 @@ var LegendModel = echarts.extendComponentModel({ // 图例内容(详见legend.data,数组中每一项代表一个item // data: [], + // Usage: + // selector: [{type: 'all or inverse', icon: 'xxx', title: xxx}] + // selector: true + selector: false, + + selectorIconStyle: { + color: null, + borderColor: '#666666', + borderWidth: 1, + shadowBlur: null, + shadowColor: null, + shadowOffsetX: 0, + shadowOffsetY: 0, + opacity: 1 + }, + + selectorIconSize: 14, + + selectorTextStyle: { + show: false, + position: 'auto', + color: '#666666' + }, + + emphasis: { + selectorIconStyle: { + borderColor: '#4EADDE', + color: '#4EADDE' + }, + selectorTextStyle: { + backgroundColor: 'rgba(50,50,50,0.7)', + + padding: 3, + show: true, + position: 'auto', + color: '#fff' + } + }, + + // Value can be 'start' or 'end' + selectorPosition: 'auto', + + selectorItemGap: 7, + + selectorLegendGap: 10, + + selectorBoundaryGap: 1, + // Tooltip 相关配置 tooltip: { show: false diff --git a/src/component/legend/LegendView.js b/src/component/legend/LegendView.js index 0cf78d0840..193b6502a7 100644 --- a/src/component/legend/LegendView.js +++ b/src/component/legend/LegendView.js @@ -28,6 +28,8 @@ import * as layoutUtil from '../../util/layout'; var curry = zrUtil.curry; var each = zrUtil.each; var Group = graphic.Group; +var isArray = zrUtil.isArray; +var retrieve2 = zrUtil.retrieve2; export default echarts.extendComponentView({ @@ -52,6 +54,12 @@ export default echarts.extendComponentView({ */ this._backgroundEl; + /** + * @private + * @type {module:zrender/container/Group} + */ + this._selectorGroup; + /** * If first rendering, `contentGroup.position` is [0, 0], which * does not make sense and may cause unexepcted animation if adopted. @@ -68,6 +76,13 @@ export default echarts.extendComponentView({ return this._contentGroup; }, + /** + * @protected + */ + getSelectorGroup: function () { + return this._selectorGroup; + }, + /** * @override */ @@ -82,14 +97,23 @@ export default echarts.extendComponentView({ } var itemAlign = legendModel.get('align'); + var orient = legendModel.get('orient'); if (!itemAlign || itemAlign === 'auto') { itemAlign = ( legendModel.get('left') === 'right' - && legendModel.get('orient') === 'vertical' + && orient === 'vertical' ) ? 'right' : 'left'; } - this.renderInner(itemAlign, legendModel, ecModel, api); + var selector = legendModel.get('selector', true); + if (selector) { + var selectorPosition = legendModel.get('selectorPosition', true); + if (!selectorPosition || selectorPosition === 'auto') { + selectorPosition = orient === 'horizontal' ? 'end' : 'start'; + } + } + + this.renderInner(itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition); // Perform layout. var positionInfo = legendModel.getBoxLayoutParams(); @@ -98,7 +122,7 @@ export default echarts.extendComponentView({ var maxSize = layoutUtil.getLayoutRect(positionInfo, viewportSize, padding); - var mainRect = this.layoutInner(legendModel, itemAlign, maxSize, isFirstRender); + var mainRect = this.layoutInner(legendModel, itemAlign, maxSize, isFirstRender, selectorPosition); // Place mainGroup, based on the calculated `mainRect`. var layoutRect = layoutUtil.getLayoutRect( @@ -120,12 +144,13 @@ export default echarts.extendComponentView({ resetInner: function () { this.getContentGroup().removeAll(); this._backgroundEl && this.group.remove(this._backgroundEl); + this._selectorGroup && this._selectorGroup.removeAll(); }, /** * @protected */ - renderInner: function (itemAlign, legendModel, ecModel, api) { + renderInner: function (itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition, viewportSize) { var contentGroup = this.getContentGroup(); var legendDrawnMap = zrUtil.createHashMap(); var selectMode = legendModel.get('selectedMode'); @@ -229,6 +254,71 @@ export default echarts.extendComponentView({ } } }, this); + + if (selector) { + this._createSelector(selector, legendModel, api, orient, selectorPosition, viewportSize); + } + }, + + _createSelector: function (selector, legendModel, api, orient, selectorPosition, viewportSize) { + this.group.add(this._selectorGroup = new Group()); + var selectorGroup = this._selectorGroup; + + var iconSize = legendModel.get('selectorIconSize', true); + if (!isArray(iconSize)) { + iconSize = [iconSize, iconSize]; + } + + each(selector, function (selectorItem) { + createSelectorButton(selectorItem); + }); + + function createSelectorButton(selectorItem) { + var type = selectorItem.type; + var icon = graphic.createIcon( + selectorItem.icon, + { + onclick: type === 'all' + ? curry(dispatchAllSelectorAction, api) + : curry(dispatchInverseSelectorAction, api) + }, + { + x: -iconSize[0] / 2, + y: -iconSize[1] / 2, + width: iconSize[0], + height: iconSize[1] + } + ); + selectorGroup.add(icon); + icon.name = type; + + var normalStyle = legendModel.getModel('selectorIconStyle').getItemStyle(); + icon.setStyle(normalStyle); + var hoverStyle = icon.hoverStyle = legendModel.getModel('emphasis.selectorIconStyle').getItemStyle(); + + var normalTextStyleModel = legendModel.getModel('selectorTextStyle'); + var emphasisTextStyleModel = legendModel.getModel('emphasis.selectorTextStyle'); + graphic.setLabelStyle( + icon.style, hoverStyle, normalTextStyleModel, emphasisTextStyleModel, + { + defaultText: selectorItem.title, + isRectText: true, + getTextPosition: function (textStyleModel) { + var textPosition = textStyleModel.getShallow('position'); + if (textPosition == null || textPosition === 'auto') { + if (orient === 'horizontal') { + textPosition = selectorPosition === 'end' ? 'left' : 'right'; + } + else if (orient === 'vertical') { + textPosition = selectorPosition === 'start' ? 'bottom' : 'top'; + } + } + return textPosition; + } + } + ); + graphic.setHoverStyle(icon, hoverStyle); + } }, _createItem: function ( @@ -348,8 +438,9 @@ export default echarts.extendComponentView({ /** * @protected */ - layoutInner: function (legendModel, itemAlign, maxSize) { + layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender, selectorPosition) { var contentGroup = this.getContentGroup(); + var selectorGroup = this._selectorGroup; // Place items in contentGroup. layoutUtil.box( @@ -361,9 +452,52 @@ export default echarts.extendComponentView({ ); var contentRect = contentGroup.getBoundingRect(); - contentGroup.attr('position', [-contentRect.x, -contentRect.y]); + var contentPos = [-contentRect.x, -contentRect.y]; + + if (selectorGroup) { + // Place buttons in selectorGroup + selectorGroup && layoutUtil.box( + // Buttons in selectorGroup always layout horizontally + 'horizontal', + selectorGroup, + legendModel.get('selectorItemGap', true) + ); + + var selectorRect = selectorGroup.getBoundingRect(); + var selectorPos = [-selectorRect.x, -selectorRect.y]; + + var selectorLegendGap = retrieve2( + legendModel.get('selectorLegendGap', true), legendModel.get('itemGap', true) + ); + + var orientIdx = legendModel.getOrient().index; + var WH = orientIdx === 0 ? 'width' : 'height'; + var HW = orientIdx === 0 ? 'height' : 'width'; + var YX = orientIdx === 0 ? 'y' : 'x'; + var selectorBoundaryGap = legendModel.get('selectorBoundaryGap', true); + + if (selectorPosition === 'end') { + selectorPos[orientIdx] += contentRect[WH] + selectorLegendGap; + } + else { + contentPos[orientIdx] += selectorRect[WH] + selectorLegendGap; + } + + //Always align selector to content as 'middle' + selectorPos[1 - orientIdx] += contentRect[HW] / 2 - selectorRect[HW] / 2; + selectorGroup.attr('position', selectorPos); + contentGroup.attr('position', contentPos); - return this.group.getBoundingRect(); + var mainRect = {x: 0, y: 0}; + mainRect[WH] = contentRect[WH] + selectorLegendGap + selectorRect[WH] + selectorBoundaryGap; + mainRect[HW] = Math.max(contentRect[HW], selectorRect[HW]); + mainRect[YX] = Math.min(0, selectorRect[YX] + selectorPos[1 - orientIdx]); + return mainRect; + } + else { + contentGroup.attr('position', contentPos); + return this.group.getBoundingRect(); + } }, /** @@ -376,6 +510,18 @@ export default echarts.extendComponentView({ }); +function dispatchAllSelectorAction(api) { + api.dispatchAction({ + type: 'legendAllSelect' + }); +} + +function dispatchInverseSelectorAction(api) { + api.dispatchAction({ + type: 'legendInverseSelect' + }); +} + function dispatchSelectAction(name, api) { api.dispatchAction({ type: 'legendToggleSelect', diff --git a/src/component/legend/legendAction.js b/src/component/legend/legendAction.js index 05c3d33421..d95156f62c 100644 --- a/src/component/legend/legendAction.js +++ b/src/component/legend/legendAction.js @@ -33,6 +33,9 @@ function legendSelectActionHandler(methodName, payload, ecModel) { // doesn't has the item, they will assume it is selected. legendModel[isSelected ? 'select' : 'unSelect'](payload.name); } + else if (methodName === 'allSelect' || methodName === 'inverseSelect') { + legendModel[methodName](); + } else { legendModel[methodName](payload.name); isSelected = legendModel.isSelected(payload.name); @@ -55,10 +58,14 @@ function legendSelectActionHandler(methodName, payload, ecModel) { }); }); // Return the event explicitly - return { - name: payload.name, - selected: selectedMap - }; + return (methodName === 'allSelect' || methodName === 'inverseSelect') + ? { + selected: selectedMap + } + : { + name: payload.name, + selected: selectedMap + }; } /** * @event legendToggleSelect @@ -72,6 +79,16 @@ echarts.registerAction( zrUtil.curry(legendSelectActionHandler, 'toggleSelected') ); +echarts.registerAction( + 'legendAllSelect', 'legendselectall', + zrUtil.curry(legendSelectActionHandler, 'allSelect') +); + +echarts.registerAction( + 'legendInverseSelect', 'legendinverseselect', + zrUtil.curry(legendSelectActionHandler, 'inverseSelect') +); + /** * @event legendSelect * @type {Object} diff --git a/src/echarts.js b/src/echarts.js index 6edca4af36..acc3496c32 100644 --- a/src/echarts.js +++ b/src/echarts.js @@ -1145,7 +1145,7 @@ echartsProto.makeActionFromEvent = function (eventObj) { * @param {boolean} [opt.flush=undefined] * true: Flush immediately, and then pixel in canvas can be fetched * immediately. Caution: it might affect performance. - * false: Not not flush. + * false: Not flush. * undefined: Auto decide whether perform flush. */ echartsProto.dispatchAction = function (payload, opt) { diff --git a/src/model/Global.js b/src/model/Global.js index a8900e4e63..d33fc8522e 100644 --- a/src/model/Global.js +++ b/src/model/Global.js @@ -373,8 +373,8 @@ var GlobalModel = Model.extend({ * {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}} * ); * var result = findComponents( - * {mainType: 'series'}, - * function (model, index) {...} + * {mainType: 'series', + * filter: function (model, index) {...}} * ); * // result like [component0, componnet1, ...] * diff --git a/src/util/graphic.js b/src/util/graphic.js index 8795440adb..110288a857 100644 --- a/src/util/graphic.js +++ b/src/util/graphic.js @@ -760,11 +760,18 @@ function setTextStyleCommon(textStyle, textStyleModel, opt, isEmphasis) { opt = opt || EMPTY_OBJ; if (opt.isRectText) { - var textPosition = textStyleModel.getShallow('position') - || (isEmphasis ? null : 'inside'); - // 'outside' is not a valid zr textPostion value, but used - // in bar series, and magric type should be considered. - textPosition === 'outside' && (textPosition = 'top'); + var textPosition; + if (opt.getTextPosition) { + textPosition = opt.getTextPosition(textStyleModel, isEmphasis); + } + else { + textPosition = textStyleModel.getShallow('position') + || (isEmphasis ? null : 'inside'); + // 'outside' is not a valid zr textPostion value, but used + // in bar series, and magric type should be considered. + textPosition === 'outside' && (textPosition = 'top'); + } + textStyle.textPosition = textPosition; textStyle.textOffset = textStyleModel.getShallow('offset'); var labelRotate = textStyleModel.getShallow('rotate'); From e4af3ab39d82049886570b99b9644e03d0e4f4c6 Mon Sep 17 00:00:00 2001 From: deqingli Date: Thu, 20 Jun 2019 19:35:16 +0800 Subject: [PATCH 003/127] feat(legend): add selector in scroll legend --- src/component/legend/ScrollableLegendModel.js | 6 -- src/component/legend/ScrollableLegendView.js | 87 ++++++++++++++++--- 2 files changed, 73 insertions(+), 20 deletions(-) diff --git a/src/component/legend/ScrollableLegendModel.js b/src/component/legend/ScrollableLegendModel.js index c2aeae90ba..bf8e713f60 100644 --- a/src/component/legend/ScrollableLegendModel.js +++ b/src/component/legend/ScrollableLegendModel.js @@ -72,12 +72,6 @@ var ScrollableLegendModel = LegendModel.extend({ ScrollableLegendModel.superCall(this, 'mergeOption', option, extraOpt); mergeAndNormalizeLayoutParams(this, this.option, option); - }, - - getOrient: function () { - return this.get('orient') === 'vertical' - ? {index: 1, name: 'vertical'} - : {index: 0, name: 'horizontal'}; } }); diff --git a/src/component/legend/ScrollableLegendView.js b/src/component/legend/ScrollableLegendView.js index a5e7cb0e43..77e1ae2e11 100644 --- a/src/component/legend/ScrollableLegendView.js +++ b/src/component/legend/ScrollableLegendView.js @@ -81,11 +81,12 @@ var ScrollableLegendView = LegendView.extend({ /** * @override */ - renderInner: function (itemAlign, legendModel, ecModel, api) { + renderInner: function (itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition) { var me = this; // Render content items. - ScrollableLegendView.superCall(this, 'renderInner', itemAlign, legendModel, ecModel, api); + ScrollableLegendView.superCall(this, 'renderInner', itemAlign, + legendModel, ecModel, api, selector, orient, selectorPosition); var controllerGroup = this._controllerGroup; @@ -138,10 +139,11 @@ var ScrollableLegendView = LegendView.extend({ /** * @override */ - layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender) { + layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender, selectorPosition) { var contentGroup = this.getContentGroup(); var containerGroup = this._containerGroup; var controllerGroup = this._controllerGroup; + var selectorGroup = this.getSelectorGroup(); var orientIdx = legendModel.getOrient().index; var wh = WH[orientIdx]; @@ -157,6 +159,22 @@ var ScrollableLegendView = LegendView.extend({ orientIdx ? null : maxSize.height ); + if (selectorGroup) { + layoutUtil.box( + // Buttons in selectorGroup always layout horizontally + 'horizontal', + selectorGroup, + legendModel.get('selectorItemGap', true) + ); + } + + var selectorLegendGap = selectorGroup ? zrUtil.retrieve2( + legendModel.get('selectorLegendGap', true), legendModel.get('itemGap', true)) : 0; + + var selectorBoundaryGap = selectorGroup ? legendModel.get('selectorBoundaryGap', true) : 0; + var selectorRect = selectorGroup ? selectorGroup.getBoundingRect() : {x: 0, y: 0, width: 0, height: 0}; + var selectorPos = [-selectorRect.x, -selectorRect.y]; + layoutUtil.box( // Buttons in controller are layout always horizontally. 'horizontal', @@ -188,17 +206,55 @@ var ScrollableLegendView = LegendView.extend({ var pageButtonPosition = legendModel.get('pageButtonPosition', true); // controller is on the right / bottom. if (pageButtonPosition === 'end') { - controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh]; + if (selectorGroup) { + if (selectorPosition === 'end') { + selectorPos[orientIdx] += maxSize[wh] - selectorRect[wh]; + controllerPos[orientIdx] += maxSize[wh] - selectorRect[wh] + - selectorLegendGap - controllerRect[wh]; + } + else { + controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh]; + containerPos[orientIdx] += selectorRect[wh] + selectorLegendGap; + } + } + else { + controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh]; + } } // controller is on the left / top. else { - containerPos[orientIdx] += controllerRect[wh] + pageButtonGap; + if (selectorGroup) { + if (selectorPosition === 'start') { + controllerPos[orientIdx] += selectorRect[wh] + selectorLegendGap; + containerPos[orientIdx] += selectorRect[wh] + selectorLegendGap + + controllerRect[wh] + pageButtonGap; + } + else { + selectorPos[orientIdx] += maxSize[wh] - selectorRect[wh]; + containerPos[orientIdx] += controllerRect[wh] + pageButtonGap; + } + } + else { + containerPos[orientIdx] += controllerRect[wh] + pageButtonGap; + } + } + } + else if (selectorGroup) { + if (selectorPosition === 'end') { + selectorPos[orientIdx] += contentRect[wh] + selectorLegendGap; + } + else { + containerPos[orientIdx] += selectorRect[wh] + selectorLegendGap; } } // Always align controller to content as 'middle'. controllerPos[1 - orientIdx] += contentRect[hw] / 2 - controllerRect[hw] / 2; + if (selectorGroup) { + selectorPos[1 - orientIdx] += contentRect[hw] / 2 - selectorRect[hw] / 2; + selectorGroup.attr('position', selectorPos); + } contentGroup.attr('position', contentPos); containerGroup.attr('position', containerPos); controllerGroup.attr('position', controllerPos); @@ -206,18 +262,21 @@ var ScrollableLegendView = LegendView.extend({ // Calculate `mainRect` and set `clipPath`. // mainRect should not be calculated by `this.group.getBoundingRect()` // for sake of the overflow. - var mainRect = this.group.getBoundingRect(); var mainRect = {x: 0, y: 0}; // Consider content may be overflow (should be clipped). - mainRect[wh] = showController ? maxSize[wh] : contentRect[wh]; - mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw]); + mainRect[wh] = showController ? maxSize[wh] + : contentRect[wh] + selectorLegendGap + selectorRect[wh] + selectorBoundaryGap; + + mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw], selectorRect[hw]); // `containerRect[yx] + containerPos[1 - orientIdx]` is 0. - mainRect[yx] = Math.min(0, controllerRect[yx] + controllerPos[1 - orientIdx]); + mainRect[yx] = Math.min(0, controllerRect[yx] + controllerPos[1 - orientIdx], + selectorRect[yx] + selectorPos[1 - orientIdx]); containerGroup.__rectSize = maxSize[wh]; if (showController) { var clipShape = {x: 0, y: 0}; - clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap, 0); + clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap + - selectorRect[wh] - selectorLegendGap - selectorBoundaryGap, 0); clipShape[hw] = mainRect[hw]; containerGroup.setClipPath(new graphic.Rect({shape: clipShape})); // Consider content may be larger than container, container rect @@ -225,7 +284,7 @@ var ScrollableLegendView = LegendView.extend({ containerGroup.__rectSize = clipShape[wh]; } else { - // Do not remove or ignore controller. Keep them set as place holders. + // Do not remove or ignore controller. Keep them set as placeholders. controllerGroup.eachChild(function (child) { child.attr({invisible: true, silent: true}); }); @@ -237,7 +296,7 @@ var ScrollableLegendView = LegendView.extend({ contentGroup, {position: pageInfo.contentPosition}, // When switch from "show controller" to "not show controller", view should be - // updated immediately without animation, otherwise causes weird efffect. + // updated immediately without animation, otherwise causes weird effect. showController ? legendModel : false ); @@ -293,8 +352,8 @@ var ScrollableLegendView = LegendView.extend({ * contentPosition: Array., null when data item not found. * pageIndex: number, null when data item not found. * pageCount: number, always be a number, can be 0. - * pagePrevDataIndex: number, null when no next page. - * pageNextDataIndex: number, null when no previous page. + * pagePrevDataIndex: number, null when no previous page. + * pageNextDataIndex: number, null when no next page. * } */ _getPageInfo: function (legendModel) { From 93c3e623698cd54d26a3f3b80e548edfcd2b8c7d Mon Sep 17 00:00:00 2001 From: deqingli Date: Thu, 20 Jun 2019 19:37:56 +0800 Subject: [PATCH 004/127] test(selector): add legend selector example --- test/legend.html | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test/legend.html b/test/legend.html index 6462feb613..cae8a8943c 100644 --- a/test/legend.html +++ b/test/legend.html @@ -152,6 +152,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( var option = { legend: { + selector: true, data: seriesInfo.legendData, backgroundColor: 'rgba(0,100,50,0.2)' }, @@ -218,6 +219,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( legend: { right: 10, width: 300, + selector: true, data: seriesInfo.legendData, backgroundColor: 'rgba(0,100,50,0.2)' }, @@ -293,6 +295,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( var option = { legend: { bottom: 20, + selector: true, data: seriesInfo.legendData, backgroundColor: 'rgba(0,100,50,0.2)' }, @@ -359,6 +362,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( legend: { orient: 'vertical', right: 20, + selector: true, data: seriesInfo.legendData, backgroundColor: 'rgba(0,100,50,0.2)' }, @@ -426,6 +430,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( orient: 'vertical', left: 20, top: 'center', + selector: true, height: 150, data: seriesInfo.legendData, backgroundColor: 'rgba(0,100,50,0.2)' @@ -491,11 +496,13 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( var option = { legend: [{ type: 'scroll', + selector: true, data: seriesInfo.legendData, backgroundColor: 'rgba(0,100,50,0.2)' }, { type: 'scroll', bottom: 0, + selector: true, data: seriesInfo.legendData, backgroundColor: 'rgba(0,100,50,0.2)', pageButtonPosition: 'start' @@ -564,6 +571,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( type: 'scroll', width: '80%', right: 30, + selector: true, data: seriesInfo.legendData, pageIconSize: 50, pageIconColor: 'red', @@ -642,6 +650,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( right: 30, left: 30, data: seriesInfo.legendData, + selector: true, pageIconSize: 5, pageIconColor: 'red', pageIconInactiveColor: 'green', @@ -720,6 +729,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( legend: { type: 'scroll', orient: 'vertical', + selector: true, bottom: 0, right: 30, data: seriesInfo.legendData @@ -785,6 +795,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( legend: { type: 'scroll', orient: 'vertical', + selector: true, top: 'middle', left: 10, height: '50%', @@ -900,7 +911,8 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( tooltip: { }, legend: { - data: ['a', 'b', 'c'] + data: ['a', 'b', 'c'], + selector: true }, series: [ { @@ -965,6 +977,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( }, legend: { type: 'scroll', + selector: true, top: 10, left: 0, data: echarts.util.map(data, function (item) { @@ -1071,6 +1084,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( var option = { legend: [{ type: 'scroll', + selector: true, itemGap: 30, backgroundColor: 'rgba(0,100,50,0.2)' }], @@ -1116,6 +1130,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( var option = { legend: [{ type: 'scroll', + selector: true, data: seriesInfo.legendData }], tooltip: { From bbef91a295bf086aa43c5ccb2d636464a0031f34 Mon Sep 17 00:00:00 2001 From: deqingli Date: Mon, 24 Jun 2019 17:24:47 +0800 Subject: [PATCH 005/127] fix(legendSelector): fix legend Selector with CR comment --- build/rollup-plugin-ec-lang.js | 2 +- src/component/legend/LegendModel.js | 56 +++++++++++--------- src/component/legend/LegendView.js | 29 +++++----- src/component/legend/ScrollableLegendView.js | 36 ++++++------- src/lang.js | 6 +++ src/langEN.js | 6 +++ 6 files changed, 74 insertions(+), 61 deletions(-) diff --git a/build/rollup-plugin-ec-lang.js b/build/rollup-plugin-ec-lang.js index 837ccbea39..2ec8c6dde5 100644 --- a/build/rollup-plugin-ec-lang.js +++ b/build/rollup-plugin-ec-lang.js @@ -65,7 +65,7 @@ let getLangFileInfo = getPlugin.getLangFileInfo = function (lang) { if (lang) { if (/^[a-zA-Z]{2}$/.test(lang)) { - absolutePath = resolve(__dirname, '../', 'src/lang' + lang.toUpperCase() + '.js') + absolutePath = resolve(__dirname, '../', 'src/lang' + lang.toUpperCase() + '.js'); } else { isOuter = true; diff --git a/src/component/legend/LegendModel.js b/src/component/legend/LegendModel.js index 255c7f6fbd..f64d81db42 100644 --- a/src/component/legend/LegendModel.js +++ b/src/component/legend/LegendModel.js @@ -21,6 +21,9 @@ import * as echarts from '../../echarts'; import * as zrUtil from 'zrender/src/core/util'; import Model from '../../model/Model'; import {isNameSpecified} from '../../util/model'; +import lang from '../../lang'; + +var langTitle = lang.legendSelector.title; var LegendModel = echarts.extendComponentModel({ @@ -54,26 +57,26 @@ var LegendModel = echarts.extendComponentModel({ _updateSelector: function (option) { var selector = option.selector; - var defaultAllIcon = 'M421.65 752.94h-60.24v60.24c0 18.07 12.05 30.12 30.12 30.12h421.65c18.07 0 30.12-12.05 30.12-30.12V391.53c0-18.07-12.05-30.12-30.12-30.12h-60.24v361.42c0 18.07-12.05 30.12-30.12 30.12H421.65z m271.06-572.23H210.82c-18.07 0-30.12 12.05-30.12 30.12v481.88c0 18.07 12.05 30.12 30.12 30.12h481.89c18.07 0 30.12-12.05 30.12-30.12V210.82c-0.01-18.07-12.05-30.11-30.12-30.11zM30.12 421.65c18.07 0 30.12-12.05 30.12-30.12V60.24h331.29c18.07 0 30.12-12.05 30.12-30.12S409.6 0 391.53 0H30.12C12.05 0 0 12.05 0 30.12v361.41c0 18.07 12.05 30.12 30.12 30.12z m361.41 542.11H60.24V632.47c0-18.07-12.05-30.12-30.12-30.12S0 614.4 0 632.47v361.41c0 18.07 12.05 30.12 30.12 30.12h361.41c18.07 0 30.12-12.05 30.12-30.12s-12.05-30.12-30.12-30.12z m602.35-361.41c-18.07 0-30.12 12.05-30.12 30.12v331.29H632.47c-18.07 0-30.12 12.05-30.12 30.12S614.4 1024 632.47 1024h361.41c18.07 0 30.12-12.05 30.12-30.12V632.47c0-18.07-12.05-30.12-30.12-30.12z m0-602.35H512c-18.07 0-30.12 12.05-30.12 30.12S493.93 60.24 512 60.24h451.76v331.29c0 18.07 12.05 30.12 30.12 30.12S1024 409.6 1024 391.53V30.12C1024 12.05 1011.95 0 993.88 0z'; - var defaultInverseIcon = 'M843.29 331.28v481.9c0 16.65-13.47 30.12-30.12 30.12H331.3c-16.65 0-30.12-13.47-30.12-30.12v-60.23h421.63c16.65 0 30.12-13.47 30.12-30.12V301.17h60.23c16.65 0 30.13 13.47 30.13 30.11zM722.82 692.72v-481.9c0-16.65-13.47-30.12-30.12-30.12H210.83c-16.65 0-30.12 13.47-30.12 30.12v481.9c0 16.65 13.47 30.12 30.12 30.12H692.7c16.65-0.01 30.12-13.48 30.12-30.12zM240.95 240.93h421.63V662.6H240.95V240.93zM60.25 391.52V60.23h331.28c16.65 0 30.12-13.47 30.12-30.12S408.18 0 391.53 0H30.13C13.48 0 0.01 13.47 0.01 30.12v361.4c0 16.65 13.47 30.12 30.12 30.12s30.12-13.48 30.12-30.12z m361.4 602.36c0-16.65-13.47-30.12-30.12-30.12H60.25V632.48c0-16.65-13.47-30.12-30.12-30.12S0.01 615.84 0.01 632.48v361.4c0 16.65 13.47 30.12 30.12 30.12h361.4c16.65 0 30.12-13.47 30.12-30.12z m602.34 0v-361.4c0-16.65-13.47-30.12-30.12-30.12s-30.12 13.47-30.12 30.12v331.28H632.47c-16.65 0-30.12 13.47-30.12 30.12s13.47 30.12 30.12 30.12h361.4c16.65 0 30.12-13.47 30.12-30.12z m0-602.36V30.12c0-16.65-13.47-30.12-30.12-30.12h-361.4c-16.65 0-30.12 13.47-30.12 30.12s13.47 30.12 30.12 30.12h331.28v331.28c0 16.65 13.47 30.12 30.12 30.12 16.65-0.01 30.12-13.48 30.12-30.12z'; - - if (selector === true) { - option.selector = [{ + var defaultSelectorOption = { + all: { type: 'all', - title: '全选', - icon: defaultAllIcon - }, { + icon: 'M421.65 752.94h-60.24v60.24c0 18.07 12.05 30.12 30.12 30.12h421.65c18.07 0 30.12-12.05 30.12-30.12V391.53c0-18.07-12.05-30.12-30.12-30.12h-60.24v361.42c0 18.07-12.05 30.12-30.12 30.12H421.65z m271.06-572.23H210.82c-18.07 0-30.12 12.05-30.12 30.12v481.88c0 18.07 12.05 30.12 30.12 30.12h481.89c18.07 0 30.12-12.05 30.12-30.12V210.82c-0.01-18.07-12.05-30.11-30.12-30.11zM30.12 421.65c18.07 0 30.12-12.05 30.12-30.12V60.24h331.29c18.07 0 30.12-12.05 30.12-30.12S409.6 0 391.53 0H30.12C12.05 0 0 12.05 0 30.12v361.41c0 18.07 12.05 30.12 30.12 30.12z m361.41 542.11H60.24V632.47c0-18.07-12.05-30.12-30.12-30.12S0 614.4 0 632.47v361.41c0 18.07 12.05 30.12 30.12 30.12h361.41c18.07 0 30.12-12.05 30.12-30.12s-12.05-30.12-30.12-30.12z m602.35-361.41c-18.07 0-30.12 12.05-30.12 30.12v331.29H632.47c-18.07 0-30.12 12.05-30.12 30.12S614.4 1024 632.47 1024h361.41c18.07 0 30.12-12.05 30.12-30.12V632.47c0-18.07-12.05-30.12-30.12-30.12z m0-602.35H512c-18.07 0-30.12 12.05-30.12 30.12S493.93 60.24 512 60.24h451.76v331.29c0 18.07 12.05 30.12 30.12 30.12S1024 409.6 1024 391.53V30.12C1024 12.05 1011.95 0 993.88 0z', + title: zrUtil.clone(langTitle.all) + }, + inverse: { type: 'inverse', - title: '反选', - icon: defaultInverseIcon - }]; + icon: 'M843.29 331.28v481.9c0 16.65-13.47 30.12-30.12 30.12H331.3c-16.65 0-30.12-13.47-30.12-30.12v-60.23h421.63c16.65 0 30.12-13.47 30.12-30.12V301.17h60.23c16.65 0 30.13 13.47 30.13 30.11zM722.82 692.72v-481.9c0-16.65-13.47-30.12-30.12-30.12H210.83c-16.65 0-30.12 13.47-30.12 30.12v481.9c0 16.65 13.47 30.12 30.12 30.12H692.7c16.65-0.01 30.12-13.48 30.12-30.12zM240.95 240.93h421.63V662.6H240.95V240.93zM60.25 391.52V60.23h331.28c16.65 0 30.12-13.47 30.12-30.12S408.18 0 391.53 0H30.13C13.48 0 0.01 13.47 0.01 30.12v361.4c0 16.65 13.47 30.12 30.12 30.12s30.12-13.48 30.12-30.12z m361.4 602.36c0-16.65-13.47-30.12-30.12-30.12H60.25V632.48c0-16.65-13.47-30.12-30.12-30.12S0.01 615.84 0.01 632.48v361.4c0 16.65 13.47 30.12 30.12 30.12h361.4c16.65 0 30.12-13.47 30.12-30.12z m602.34 0v-361.4c0-16.65-13.47-30.12-30.12-30.12s-30.12 13.47-30.12 30.12v331.28H632.47c-16.65 0-30.12 13.47-30.12 30.12s13.47 30.12 30.12 30.12h361.4c16.65 0 30.12-13.47 30.12-30.12z m0-602.36V30.12c0-16.65-13.47-30.12-30.12-30.12h-361.4c-16.65 0-30.12 13.47-30.12 30.12s13.47 30.12 30.12 30.12h331.28v331.28c0 16.65 13.47 30.12 30.12 30.12 16.65-0.01 30.12-13.48 30.12-30.12z', + title: zrUtil.clone(langTitle.inverse) + } + }; + + if (selector === true) { + selector = option.selector = ['all', 'inverse']; } - else if (zrUtil.isArray(selector)) { - zrUtil.each(selector, function (item) { - var type = item.type; - item.icon = item.icon - || (type === 'all' ? defaultAllIcon : defaultInverseIcon); - item.title = item.title || (type === 'all' ? '全选' : '反选'); + if (zrUtil.isArray(selector)) { + zrUtil.each(selector, function (item, index) { + zrUtil.isString(item) && (item = {type: item}); + selector[index] = zrUtil.merge(item, defaultSelectorOption[item.type]); }); } }, @@ -296,18 +299,21 @@ var LegendModel = echarts.extendComponentModel({ // Usage: // selector: [{type: 'all or inverse', icon: 'xxx', title: xxx}] + // or // selector: true + // or + // selector: ['all', 'inverse'] selector: false, selectorIconStyle: { color: null, borderColor: '#666666', - borderWidth: 1, - shadowBlur: null, - shadowColor: null, - shadowOffsetX: 0, - shadowOffsetY: 0, - opacity: 1 + borderWidth: 1 + // shadowBlur: null, + // shadowColor: null, + // shadowOffsetX: 0, + // shadowOffsetY: 0, + // opacity: 1 }, selectorIconSize: 14, @@ -338,9 +344,9 @@ var LegendModel = echarts.extendComponentModel({ selectorItemGap: 7, - selectorLegendGap: 10, + selectorLegendContentGap: 10, - selectorBoundaryGap: 1, + selectorBorderGap: 1, // Tooltip 相关配置 tooltip: { diff --git a/src/component/legend/LegendView.js b/src/component/legend/LegendView.js index 193b6502a7..55fdfeae81 100644 --- a/src/component/legend/LegendView.js +++ b/src/component/legend/LegendView.js @@ -29,7 +29,6 @@ var curry = zrUtil.curry; var each = zrUtil.each; var Group = graphic.Group; var isArray = zrUtil.isArray; -var retrieve2 = zrUtil.retrieve2; export default echarts.extendComponentView({ @@ -122,7 +121,7 @@ export default echarts.extendComponentView({ var maxSize = layoutUtil.getLayoutRect(positionInfo, viewportSize, padding); - var mainRect = this.layoutInner(legendModel, itemAlign, maxSize, isFirstRender, selectorPosition); + var mainRect = this.layoutInner(legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition); // Place mainGroup, based on the calculated `mainRect`. var layoutRect = layoutUtil.getLayoutRect( @@ -150,7 +149,7 @@ export default echarts.extendComponentView({ /** * @protected */ - renderInner: function (itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition, viewportSize) { + renderInner: function (itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition) { var contentGroup = this.getContentGroup(); var legendDrawnMap = zrUtil.createHashMap(); var selectMode = legendModel.get('selectedMode'); @@ -256,19 +255,18 @@ export default echarts.extendComponentView({ }, this); if (selector) { - this._createSelector(selector, legendModel, api, orient, selectorPosition, viewportSize); + this._createSelector(selector, legendModel, api, orient, selectorPosition); } }, - _createSelector: function (selector, legendModel, api, orient, selectorPosition, viewportSize) { - this.group.add(this._selectorGroup = new Group()); + _createSelector: function (selector, legendModel, api, orient, selectorPosition) { + !this._selectorGroup && this.group.add(this._selectorGroup = new Group()); var selectorGroup = this._selectorGroup; var iconSize = legendModel.get('selectorIconSize', true); if (!isArray(iconSize)) { iconSize = [iconSize, iconSize]; } - each(selector, function (selectorItem) { createSelectorButton(selectorItem); }); @@ -438,7 +436,7 @@ export default echarts.extendComponentView({ /** * @protected */ - layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender, selectorPosition) { + layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition) { var contentGroup = this.getContentGroup(); var selectorGroup = this._selectorGroup; @@ -454,7 +452,7 @@ export default echarts.extendComponentView({ var contentRect = contentGroup.getBoundingRect(); var contentPos = [-contentRect.x, -contentRect.y]; - if (selectorGroup) { + if (selector && selectorGroup) { // Place buttons in selectorGroup selectorGroup && layoutUtil.box( // Buttons in selectorGroup always layout horizontally @@ -465,22 +463,19 @@ export default echarts.extendComponentView({ var selectorRect = selectorGroup.getBoundingRect(); var selectorPos = [-selectorRect.x, -selectorRect.y]; - - var selectorLegendGap = retrieve2( - legendModel.get('selectorLegendGap', true), legendModel.get('itemGap', true) - ); + var selectorLegendContentGap = legendModel.get('selectorLegendContentGap', true); var orientIdx = legendModel.getOrient().index; var WH = orientIdx === 0 ? 'width' : 'height'; var HW = orientIdx === 0 ? 'height' : 'width'; var YX = orientIdx === 0 ? 'y' : 'x'; - var selectorBoundaryGap = legendModel.get('selectorBoundaryGap', true); + var selectorBorderGap = legendModel.get('selectorBorderGap', true); if (selectorPosition === 'end') { - selectorPos[orientIdx] += contentRect[WH] + selectorLegendGap; + selectorPos[orientIdx] += contentRect[WH] + selectorLegendContentGap; } else { - contentPos[orientIdx] += selectorRect[WH] + selectorLegendGap; + contentPos[orientIdx] += selectorRect[WH] + selectorLegendContentGap; } //Always align selector to content as 'middle' @@ -489,7 +484,7 @@ export default echarts.extendComponentView({ contentGroup.attr('position', contentPos); var mainRect = {x: 0, y: 0}; - mainRect[WH] = contentRect[WH] + selectorLegendGap + selectorRect[WH] + selectorBoundaryGap; + mainRect[WH] = contentRect[WH] + selectorLegendContentGap + selectorRect[WH] + selectorBorderGap; mainRect[HW] = Math.max(contentRect[HW], selectorRect[HW]); mainRect[YX] = Math.min(0, selectorRect[YX] + selectorPos[1 - orientIdx]); return mainRect; diff --git a/src/component/legend/ScrollableLegendView.js b/src/component/legend/ScrollableLegendView.js index 77e1ae2e11..832a4f1fc8 100644 --- a/src/component/legend/ScrollableLegendView.js +++ b/src/component/legend/ScrollableLegendView.js @@ -139,11 +139,12 @@ var ScrollableLegendView = LegendView.extend({ /** * @override */ - layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender, selectorPosition) { + layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition) { var contentGroup = this.getContentGroup(); var containerGroup = this._containerGroup; var controllerGroup = this._controllerGroup; var selectorGroup = this.getSelectorGroup(); + var isSelector = selector && selectorGroup; var orientIdx = legendModel.getOrient().index; var wh = WH[orientIdx]; @@ -159,7 +160,7 @@ var ScrollableLegendView = LegendView.extend({ orientIdx ? null : maxSize.height ); - if (selectorGroup) { + if (isSelector) { layoutUtil.box( // Buttons in selectorGroup always layout horizontally 'horizontal', @@ -168,11 +169,10 @@ var ScrollableLegendView = LegendView.extend({ ); } - var selectorLegendGap = selectorGroup ? zrUtil.retrieve2( - legendModel.get('selectorLegendGap', true), legendModel.get('itemGap', true)) : 0; + var selectorLegendContentGap = isSelector ? legendModel.get('selectorLegendContentGap', true) : 0; - var selectorBoundaryGap = selectorGroup ? legendModel.get('selectorBoundaryGap', true) : 0; - var selectorRect = selectorGroup ? selectorGroup.getBoundingRect() : {x: 0, y: 0, width: 0, height: 0}; + var selectorBorderGap = isSelector ? legendModel.get('selectorBorderGap', true) : 0; + var selectorRect = isSelector ? selectorGroup.getBoundingRect() : {x: 0, y: 0, width: 0, height: 0}; var selectorPos = [-selectorRect.x, -selectorRect.y]; layoutUtil.box( @@ -206,15 +206,15 @@ var ScrollableLegendView = LegendView.extend({ var pageButtonPosition = legendModel.get('pageButtonPosition', true); // controller is on the right / bottom. if (pageButtonPosition === 'end') { - if (selectorGroup) { + if (isSelector) { if (selectorPosition === 'end') { selectorPos[orientIdx] += maxSize[wh] - selectorRect[wh]; controllerPos[orientIdx] += maxSize[wh] - selectorRect[wh] - - selectorLegendGap - controllerRect[wh]; + - selectorLegendContentGap - controllerRect[wh]; } else { controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh]; - containerPos[orientIdx] += selectorRect[wh] + selectorLegendGap; + containerPos[orientIdx] += selectorRect[wh] + selectorLegendContentGap; } } else { @@ -223,10 +223,10 @@ var ScrollableLegendView = LegendView.extend({ } // controller is on the left / top. else { - if (selectorGroup) { + if (isSelector) { if (selectorPosition === 'start') { - controllerPos[orientIdx] += selectorRect[wh] + selectorLegendGap; - containerPos[orientIdx] += selectorRect[wh] + selectorLegendGap + controllerPos[orientIdx] += selectorRect[wh] + selectorLegendContentGap; + containerPos[orientIdx] += selectorRect[wh] + selectorLegendContentGap + controllerRect[wh] + pageButtonGap; } else { @@ -239,19 +239,19 @@ var ScrollableLegendView = LegendView.extend({ } } } - else if (selectorGroup) { + else if (isSelector) { if (selectorPosition === 'end') { - selectorPos[orientIdx] += contentRect[wh] + selectorLegendGap; + selectorPos[orientIdx] += contentRect[wh] + selectorLegendContentGap; } else { - containerPos[orientIdx] += selectorRect[wh] + selectorLegendGap; + containerPos[orientIdx] += selectorRect[wh] + selectorLegendContentGap; } } // Always align controller to content as 'middle'. controllerPos[1 - orientIdx] += contentRect[hw] / 2 - controllerRect[hw] / 2; - if (selectorGroup) { + if (isSelector) { selectorPos[1 - orientIdx] += contentRect[hw] / 2 - selectorRect[hw] / 2; selectorGroup.attr('position', selectorPos); } @@ -265,7 +265,7 @@ var ScrollableLegendView = LegendView.extend({ var mainRect = {x: 0, y: 0}; // Consider content may be overflow (should be clipped). mainRect[wh] = showController ? maxSize[wh] - : contentRect[wh] + selectorLegendGap + selectorRect[wh] + selectorBoundaryGap; + : contentRect[wh] + selectorLegendContentGap + selectorRect[wh] + selectorBorderGap; mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw], selectorRect[hw]); // `containerRect[yx] + containerPos[1 - orientIdx]` is 0. @@ -276,7 +276,7 @@ var ScrollableLegendView = LegendView.extend({ if (showController) { var clipShape = {x: 0, y: 0}; clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap - - selectorRect[wh] - selectorLegendGap - selectorBoundaryGap, 0); + - selectorRect[wh] - selectorLegendContentGap - selectorBorderGap, 0); clipShape[hw] = mainRect[hw]; containerGroup.setClipPath(new graphic.Rect({shape: clipShape})); // Consider content may be larger than container, container rect diff --git a/src/lang.js b/src/lang.js index 7115dfc630..778f93d119 100644 --- a/src/lang.js +++ b/src/lang.js @@ -19,6 +19,12 @@ export default { + legendSelector: { + title: { + all: '全选', + inverse: '反选' + } + }, toolbox: { brush: { title: { diff --git a/src/langEN.js b/src/langEN.js index f55cf7a298..c904a1165e 100644 --- a/src/langEN.js +++ b/src/langEN.js @@ -19,6 +19,12 @@ export default { + legendSelector: { + title: { + all: 'All', + inverse: 'Inv' + } + }, toolbox: { brush: { title: { From 8e83c4842edaf98c6779afe18a2fd701efb347de Mon Sep 17 00:00:00 2001 From: deqingli Date: Tue, 25 Jun 2019 09:32:49 +0800 Subject: [PATCH 006/127] Move the defaultSelectorOption into global namespace rather than in the function --- src/component/legend/LegendModel.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/component/legend/LegendModel.js b/src/component/legend/LegendModel.js index f64d81db42..688e475654 100644 --- a/src/component/legend/LegendModel.js +++ b/src/component/legend/LegendModel.js @@ -25,6 +25,19 @@ import lang from '../../lang'; var langTitle = lang.legendSelector.title; +var defaultSelectorOption = { + all: { + type: 'all', + icon: 'M421.65 752.94h-60.24v60.24c0 18.07 12.05 30.12 30.12 30.12h421.65c18.07 0 30.12-12.05 30.12-30.12V391.53c0-18.07-12.05-30.12-30.12-30.12h-60.24v361.42c0 18.07-12.05 30.12-30.12 30.12H421.65z m271.06-572.23H210.82c-18.07 0-30.12 12.05-30.12 30.12v481.88c0 18.07 12.05 30.12 30.12 30.12h481.89c18.07 0 30.12-12.05 30.12-30.12V210.82c-0.01-18.07-12.05-30.11-30.12-30.11zM30.12 421.65c18.07 0 30.12-12.05 30.12-30.12V60.24h331.29c18.07 0 30.12-12.05 30.12-30.12S409.6 0 391.53 0H30.12C12.05 0 0 12.05 0 30.12v361.41c0 18.07 12.05 30.12 30.12 30.12z m361.41 542.11H60.24V632.47c0-18.07-12.05-30.12-30.12-30.12S0 614.4 0 632.47v361.41c0 18.07 12.05 30.12 30.12 30.12h361.41c18.07 0 30.12-12.05 30.12-30.12s-12.05-30.12-30.12-30.12z m602.35-361.41c-18.07 0-30.12 12.05-30.12 30.12v331.29H632.47c-18.07 0-30.12 12.05-30.12 30.12S614.4 1024 632.47 1024h361.41c18.07 0 30.12-12.05 30.12-30.12V632.47c0-18.07-12.05-30.12-30.12-30.12z m0-602.35H512c-18.07 0-30.12 12.05-30.12 30.12S493.93 60.24 512 60.24h451.76v331.29c0 18.07 12.05 30.12 30.12 30.12S1024 409.6 1024 391.53V30.12C1024 12.05 1011.95 0 993.88 0z', + title: zrUtil.clone(langTitle.all) + }, + inverse: { + type: 'inverse', + icon: 'M843.29 331.28v481.9c0 16.65-13.47 30.12-30.12 30.12H331.3c-16.65 0-30.12-13.47-30.12-30.12v-60.23h421.63c16.65 0 30.12-13.47 30.12-30.12V301.17h60.23c16.65 0 30.13 13.47 30.13 30.11zM722.82 692.72v-481.9c0-16.65-13.47-30.12-30.12-30.12H210.83c-16.65 0-30.12 13.47-30.12 30.12v481.9c0 16.65 13.47 30.12 30.12 30.12H692.7c16.65-0.01 30.12-13.48 30.12-30.12zM240.95 240.93h421.63V662.6H240.95V240.93zM60.25 391.52V60.23h331.28c16.65 0 30.12-13.47 30.12-30.12S408.18 0 391.53 0H30.13C13.48 0 0.01 13.47 0.01 30.12v361.4c0 16.65 13.47 30.12 30.12 30.12s30.12-13.48 30.12-30.12z m361.4 602.36c0-16.65-13.47-30.12-30.12-30.12H60.25V632.48c0-16.65-13.47-30.12-30.12-30.12S0.01 615.84 0.01 632.48v361.4c0 16.65 13.47 30.12 30.12 30.12h361.4c16.65 0 30.12-13.47 30.12-30.12z m602.34 0v-361.4c0-16.65-13.47-30.12-30.12-30.12s-30.12 13.47-30.12 30.12v331.28H632.47c-16.65 0-30.12 13.47-30.12 30.12s13.47 30.12 30.12 30.12h361.4c16.65 0 30.12-13.47 30.12-30.12z m0-602.36V30.12c0-16.65-13.47-30.12-30.12-30.12h-361.4c-16.65 0-30.12 13.47-30.12 30.12s13.47 30.12 30.12 30.12h331.28v331.28c0 16.65 13.47 30.12 30.12 30.12 16.65-0.01 30.12-13.48 30.12-30.12z', + title: zrUtil.clone(langTitle.inverse) + } +}; + var LegendModel = echarts.extendComponentModel({ type: 'legend.plain', @@ -57,19 +70,6 @@ var LegendModel = echarts.extendComponentModel({ _updateSelector: function (option) { var selector = option.selector; - var defaultSelectorOption = { - all: { - type: 'all', - icon: 'M421.65 752.94h-60.24v60.24c0 18.07 12.05 30.12 30.12 30.12h421.65c18.07 0 30.12-12.05 30.12-30.12V391.53c0-18.07-12.05-30.12-30.12-30.12h-60.24v361.42c0 18.07-12.05 30.12-30.12 30.12H421.65z m271.06-572.23H210.82c-18.07 0-30.12 12.05-30.12 30.12v481.88c0 18.07 12.05 30.12 30.12 30.12h481.89c18.07 0 30.12-12.05 30.12-30.12V210.82c-0.01-18.07-12.05-30.11-30.12-30.11zM30.12 421.65c18.07 0 30.12-12.05 30.12-30.12V60.24h331.29c18.07 0 30.12-12.05 30.12-30.12S409.6 0 391.53 0H30.12C12.05 0 0 12.05 0 30.12v361.41c0 18.07 12.05 30.12 30.12 30.12z m361.41 542.11H60.24V632.47c0-18.07-12.05-30.12-30.12-30.12S0 614.4 0 632.47v361.41c0 18.07 12.05 30.12 30.12 30.12h361.41c18.07 0 30.12-12.05 30.12-30.12s-12.05-30.12-30.12-30.12z m602.35-361.41c-18.07 0-30.12 12.05-30.12 30.12v331.29H632.47c-18.07 0-30.12 12.05-30.12 30.12S614.4 1024 632.47 1024h361.41c18.07 0 30.12-12.05 30.12-30.12V632.47c0-18.07-12.05-30.12-30.12-30.12z m0-602.35H512c-18.07 0-30.12 12.05-30.12 30.12S493.93 60.24 512 60.24h451.76v331.29c0 18.07 12.05 30.12 30.12 30.12S1024 409.6 1024 391.53V30.12C1024 12.05 1011.95 0 993.88 0z', - title: zrUtil.clone(langTitle.all) - }, - inverse: { - type: 'inverse', - icon: 'M843.29 331.28v481.9c0 16.65-13.47 30.12-30.12 30.12H331.3c-16.65 0-30.12-13.47-30.12-30.12v-60.23h421.63c16.65 0 30.12-13.47 30.12-30.12V301.17h60.23c16.65 0 30.13 13.47 30.13 30.11zM722.82 692.72v-481.9c0-16.65-13.47-30.12-30.12-30.12H210.83c-16.65 0-30.12 13.47-30.12 30.12v481.9c0 16.65 13.47 30.12 30.12 30.12H692.7c16.65-0.01 30.12-13.48 30.12-30.12zM240.95 240.93h421.63V662.6H240.95V240.93zM60.25 391.52V60.23h331.28c16.65 0 30.12-13.47 30.12-30.12S408.18 0 391.53 0H30.13C13.48 0 0.01 13.47 0.01 30.12v361.4c0 16.65 13.47 30.12 30.12 30.12s30.12-13.48 30.12-30.12z m361.4 602.36c0-16.65-13.47-30.12-30.12-30.12H60.25V632.48c0-16.65-13.47-30.12-30.12-30.12S0.01 615.84 0.01 632.48v361.4c0 16.65 13.47 30.12 30.12 30.12h361.4c16.65 0 30.12-13.47 30.12-30.12z m602.34 0v-361.4c0-16.65-13.47-30.12-30.12-30.12s-30.12 13.47-30.12 30.12v331.28H632.47c-16.65 0-30.12 13.47-30.12 30.12s13.47 30.12 30.12 30.12h361.4c16.65 0 30.12-13.47 30.12-30.12z m0-602.36V30.12c0-16.65-13.47-30.12-30.12-30.12h-361.4c-16.65 0-30.12 13.47-30.12 30.12s13.47 30.12 30.12 30.12h331.28v331.28c0 16.65 13.47 30.12 30.12 30.12 16.65-0.01 30.12-13.48 30.12-30.12z', - title: zrUtil.clone(langTitle.inverse) - } - }; - if (selector === true) { selector = option.selector = ['all', 'inverse']; } From 434e2b1add4d325fda821c09d46a45234efec4fc Mon Sep 17 00:00:00 2001 From: deqingli Date: Tue, 25 Jun 2019 14:30:39 +0800 Subject: [PATCH 007/127] fix(selector): modify the parameter in legend default option and the time selectorgroup be created --- src/component/legend/LegendModel.js | 4 +- src/component/legend/LegendView.js | 34 +++++++-------- src/component/legend/ScrollableLegendView.js | 44 +++++++++----------- 3 files changed, 37 insertions(+), 45 deletions(-) diff --git a/src/component/legend/LegendModel.js b/src/component/legend/LegendModel.js index 688e475654..adcfb6eac1 100644 --- a/src/component/legend/LegendModel.js +++ b/src/component/legend/LegendModel.js @@ -344,9 +344,7 @@ var LegendModel = echarts.extendComponentModel({ selectorItemGap: 7, - selectorLegendContentGap: 10, - - selectorBorderGap: 1, + selectorButtonGap: 10, // Tooltip 相关配置 tooltip: { diff --git a/src/component/legend/LegendView.js b/src/component/legend/LegendView.js index 55fdfeae81..7855df7c2c 100644 --- a/src/component/legend/LegendView.js +++ b/src/component/legend/LegendView.js @@ -57,7 +57,7 @@ export default echarts.extendComponentView({ * @private * @type {module:zrender/container/Group} */ - this._selectorGroup; + this.group.add(this._selectorGroup = new Group()); /** * If first rendering, `contentGroup.position` is [0, 0], which @@ -143,7 +143,7 @@ export default echarts.extendComponentView({ resetInner: function () { this.getContentGroup().removeAll(); this._backgroundEl && this.group.remove(this._backgroundEl); - this._selectorGroup && this._selectorGroup.removeAll(); + this.getSelectorGroup().removeAll(); }, /** @@ -260,8 +260,7 @@ export default echarts.extendComponentView({ }, _createSelector: function (selector, legendModel, api, orient, selectorPosition) { - !this._selectorGroup && this.group.add(this._selectorGroup = new Group()); - var selectorGroup = this._selectorGroup; + var selectorGroup = this.getSelectorGroup(); var iconSize = legendModel.get('selectorIconSize', true); if (!isArray(iconSize)) { @@ -438,7 +437,7 @@ export default echarts.extendComponentView({ */ layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition) { var contentGroup = this.getContentGroup(); - var selectorGroup = this._selectorGroup; + var selectorGroup = this.getSelectorGroup(); // Place items in contentGroup. layoutUtil.box( @@ -452,9 +451,9 @@ export default echarts.extendComponentView({ var contentRect = contentGroup.getBoundingRect(); var contentPos = [-contentRect.x, -contentRect.y]; - if (selector && selectorGroup) { + if (selector) { // Place buttons in selectorGroup - selectorGroup && layoutUtil.box( + layoutUtil.box( // Buttons in selectorGroup always layout horizontally 'horizontal', selectorGroup, @@ -463,30 +462,29 @@ export default echarts.extendComponentView({ var selectorRect = selectorGroup.getBoundingRect(); var selectorPos = [-selectorRect.x, -selectorRect.y]; - var selectorLegendContentGap = legendModel.get('selectorLegendContentGap', true); + var selectorButtonGap = legendModel.get('selectorButtonGap', true); var orientIdx = legendModel.getOrient().index; - var WH = orientIdx === 0 ? 'width' : 'height'; - var HW = orientIdx === 0 ? 'height' : 'width'; - var YX = orientIdx === 0 ? 'y' : 'x'; - var selectorBorderGap = legendModel.get('selectorBorderGap', true); + var wh = orientIdx === 0 ? 'width' : 'height'; + var hw = orientIdx === 0 ? 'height' : 'width'; + var yx = orientIdx === 0 ? 'y' : 'x'; if (selectorPosition === 'end') { - selectorPos[orientIdx] += contentRect[WH] + selectorLegendContentGap; + selectorPos[orientIdx] += contentRect[wh] + selectorButtonGap; } else { - contentPos[orientIdx] += selectorRect[WH] + selectorLegendContentGap; + contentPos[orientIdx] += selectorRect[wh] + selectorButtonGap; } //Always align selector to content as 'middle' - selectorPos[1 - orientIdx] += contentRect[HW] / 2 - selectorRect[HW] / 2; + selectorPos[1 - orientIdx] += contentRect[hw] / 2 - selectorRect[hw] / 2; selectorGroup.attr('position', selectorPos); contentGroup.attr('position', contentPos); var mainRect = {x: 0, y: 0}; - mainRect[WH] = contentRect[WH] + selectorLegendContentGap + selectorRect[WH] + selectorBorderGap; - mainRect[HW] = Math.max(contentRect[HW], selectorRect[HW]); - mainRect[YX] = Math.min(0, selectorRect[YX] + selectorPos[1 - orientIdx]); + mainRect[wh] = contentRect[wh] + selectorButtonGap + selectorRect[wh]; + mainRect[hw] = Math.max(contentRect[hw], selectorRect[hw]); + mainRect[yx] = Math.min(0, selectorRect[yx] + selectorPos[1 - orientIdx]); return mainRect; } else { diff --git a/src/component/legend/ScrollableLegendView.js b/src/component/legend/ScrollableLegendView.js index 832a4f1fc8..c1ff0bdac5 100644 --- a/src/component/legend/ScrollableLegendView.js +++ b/src/component/legend/ScrollableLegendView.js @@ -144,7 +144,6 @@ var ScrollableLegendView = LegendView.extend({ var containerGroup = this._containerGroup; var controllerGroup = this._controllerGroup; var selectorGroup = this.getSelectorGroup(); - var isSelector = selector && selectorGroup; var orientIdx = legendModel.getOrient().index; var wh = WH[orientIdx]; @@ -160,19 +159,16 @@ var ScrollableLegendView = LegendView.extend({ orientIdx ? null : maxSize.height ); - if (isSelector) { - layoutUtil.box( - // Buttons in selectorGroup always layout horizontally - 'horizontal', - selectorGroup, - legendModel.get('selectorItemGap', true) - ); - } + selector && layoutUtil.box( + // Buttons in selectorGroup always layout horizontally + 'horizontal', + selectorGroup, + legendModel.get('selectorItemGap', true) + ); - var selectorLegendContentGap = isSelector ? legendModel.get('selectorLegendContentGap', true) : 0; + var selectorButtonGap = selector ? legendModel.get('selectorButtonGap', true) : 0; - var selectorBorderGap = isSelector ? legendModel.get('selectorBorderGap', true) : 0; - var selectorRect = isSelector ? selectorGroup.getBoundingRect() : {x: 0, y: 0, width: 0, height: 0}; + var selectorRect = selector ? selectorGroup.getBoundingRect() : {x: 0, y: 0, width: 0, height: 0}; var selectorPos = [-selectorRect.x, -selectorRect.y]; layoutUtil.box( @@ -206,15 +202,15 @@ var ScrollableLegendView = LegendView.extend({ var pageButtonPosition = legendModel.get('pageButtonPosition', true); // controller is on the right / bottom. if (pageButtonPosition === 'end') { - if (isSelector) { + if (selector) { if (selectorPosition === 'end') { selectorPos[orientIdx] += maxSize[wh] - selectorRect[wh]; controllerPos[orientIdx] += maxSize[wh] - selectorRect[wh] - - selectorLegendContentGap - controllerRect[wh]; + - selectorButtonGap - controllerRect[wh]; } else { controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh]; - containerPos[orientIdx] += selectorRect[wh] + selectorLegendContentGap; + containerPos[orientIdx] += selectorRect[wh] + selectorButtonGap; } } else { @@ -223,10 +219,10 @@ var ScrollableLegendView = LegendView.extend({ } // controller is on the left / top. else { - if (isSelector) { + if (selector) { if (selectorPosition === 'start') { - controllerPos[orientIdx] += selectorRect[wh] + selectorLegendContentGap; - containerPos[orientIdx] += selectorRect[wh] + selectorLegendContentGap + controllerPos[orientIdx] += selectorRect[wh] + selectorButtonGap; + containerPos[orientIdx] += selectorRect[wh] + selectorButtonGap + controllerRect[wh] + pageButtonGap; } else { @@ -239,19 +235,19 @@ var ScrollableLegendView = LegendView.extend({ } } } - else if (isSelector) { + else if (selector) { if (selectorPosition === 'end') { - selectorPos[orientIdx] += contentRect[wh] + selectorLegendContentGap; + selectorPos[orientIdx] += contentRect[wh] + selectorButtonGap; } else { - containerPos[orientIdx] += selectorRect[wh] + selectorLegendContentGap; + containerPos[orientIdx] += selectorRect[wh] + selectorButtonGap; } } // Always align controller to content as 'middle'. controllerPos[1 - orientIdx] += contentRect[hw] / 2 - controllerRect[hw] / 2; - if (isSelector) { + if (selector) { selectorPos[1 - orientIdx] += contentRect[hw] / 2 - selectorRect[hw] / 2; selectorGroup.attr('position', selectorPos); } @@ -265,7 +261,7 @@ var ScrollableLegendView = LegendView.extend({ var mainRect = {x: 0, y: 0}; // Consider content may be overflow (should be clipped). mainRect[wh] = showController ? maxSize[wh] - : contentRect[wh] + selectorLegendContentGap + selectorRect[wh] + selectorBorderGap; + : contentRect[wh] + selectorButtonGap + selectorRect[wh]; mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw], selectorRect[hw]); // `containerRect[yx] + containerPos[1 - orientIdx]` is 0. @@ -276,7 +272,7 @@ var ScrollableLegendView = LegendView.extend({ if (showController) { var clipShape = {x: 0, y: 0}; clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap - - selectorRect[wh] - selectorLegendContentGap - selectorBorderGap, 0); + - selectorRect[wh] - selectorButtonGap, 0); clipShape[hw] = mainRect[hw]; containerGroup.setClipPath(new graphic.Rect({shape: clipShape})); // Consider content may be larger than container, container rect From 3954da04098e8f17e3414548d7a1fc1284bf7837 Mon Sep 17 00:00:00 2001 From: deqingli Date: Wed, 26 Jun 2019 16:43:46 +0800 Subject: [PATCH 008/127] fix(selector): modify selector position computation in scrollable legend --- src/chart/gauge/GaugeView.js | 2 +- src/component/legend/LegendView.js | 8 +- src/component/legend/ScrollableLegendView.js | 114 +++++++++---------- 3 files changed, 56 insertions(+), 68 deletions(-) diff --git a/src/chart/gauge/GaugeView.js b/src/chart/gauge/GaugeView.js index 567f72ec43..0ccd6dd706 100644 --- a/src/chart/gauge/GaugeView.js +++ b/src/chart/gauge/GaugeView.js @@ -86,7 +86,7 @@ var GaugeView = ChartView.extend({ var prevEndAngle = startAngle; var axisLineWidth = lineStyleModel.get('width'); var showAxis = axisLineModel.get('show'); - + for (var i = 0; showAxis && i < colorList.length; i++) { // Clamp var percent = Math.min(Math.max(colorList[i][0], 0), 1); diff --git a/src/component/legend/LegendView.js b/src/component/legend/LegendView.js index 7855df7c2c..b9e8e7cd54 100644 --- a/src/component/legend/LegendView.js +++ b/src/component/legend/LegendView.js @@ -105,11 +105,9 @@ export default echarts.extendComponentView({ } var selector = legendModel.get('selector', true); - if (selector) { - var selectorPosition = legendModel.get('selectorPosition', true); - if (!selectorPosition || selectorPosition === 'auto') { - selectorPosition = orient === 'horizontal' ? 'end' : 'start'; - } + var selectorPosition = legendModel.get('selectorPosition', true); + if (selector && (!selectorPosition || selectorPosition === 'auto')) { + selectorPosition = orient === 'horizontal' ? 'end' : 'start'; } this.renderInner(itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition); diff --git a/src/component/legend/ScrollableLegendView.js b/src/component/legend/ScrollableLegendView.js index c1ff0bdac5..0c68a12f6e 100644 --- a/src/component/legend/ScrollableLegendView.js +++ b/src/component/legend/ScrollableLegendView.js @@ -140,25 +140,14 @@ var ScrollableLegendView = LegendView.extend({ * @override */ layoutInner: function (legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition) { - var contentGroup = this.getContentGroup(); - var containerGroup = this._containerGroup; - var controllerGroup = this._controllerGroup; var selectorGroup = this.getSelectorGroup(); var orientIdx = legendModel.getOrient().index; var wh = WH[orientIdx]; + var xy = XY[orientIdx]; var hw = WH[1 - orientIdx]; var yx = XY[1 - orientIdx]; - // Place items in contentGroup. - layoutUtil.box( - legendModel.get('orient'), - contentGroup, - legendModel.get('itemGap'), - !orientIdx ? null : maxSize.width, - orientIdx ? null : maxSize.height - ); - selector && layoutUtil.box( // Buttons in selectorGroup always layout horizontally 'horizontal', @@ -166,11 +155,52 @@ var ScrollableLegendView = LegendView.extend({ legendModel.get('selectorItemGap', true) ); - var selectorButtonGap = selector ? legendModel.get('selectorButtonGap', true) : 0; - - var selectorRect = selector ? selectorGroup.getBoundingRect() : {x: 0, y: 0, width: 0, height: 0}; + var selectorButtonGap = legendModel.get('selectorButtonGap', true); + var selectorRect = selectorGroup.getBoundingRect(); var selectorPos = [-selectorRect.x, -selectorRect.y]; + var processMaxSize = zrUtil.clone(maxSize); + selector && (processMaxSize[wh] = maxSize[wh] - selectorRect[wh] - selectorButtonGap); + + var mainRect = this._layoutContentAndController(legendModel, isFirstRender, + processMaxSize, orientIdx, wh, hw, yx + ); + + if (selector) { + if (selectorPosition === 'end') { + selectorPos[orientIdx] += mainRect[wh] + selectorButtonGap; + } + else { + var offset = selectorRect[wh] + selectorButtonGap; + selectorPos[orientIdx] -= offset; + mainRect[xy] -= offset; + } + mainRect[wh] += selectorRect[wh] + selectorButtonGap; + + selectorPos[1 - orientIdx] += mainRect[yx] + mainRect[hw] / 2 - selectorRect[hw] / 2; + mainRect[hw] = Math.max(mainRect[hw], selectorRect[hw]); + mainRect[yx] = Math.min(mainRect[yx], selectorRect[yx] + selectorPos[1 - orientIdx]); + + selectorGroup.attr('position', selectorPos); + } + + return mainRect; + }, + + _layoutContentAndController: function (legendModel, isFirstRender, maxSize, orientIdx, wh, hw, yx) { + var contentGroup = this.getContentGroup(); + var containerGroup = this._containerGroup; + var controllerGroup = this._controllerGroup; + + // Place items in contentGroup. + layoutUtil.box( + legendModel.get('orient'), + contentGroup, + legendModel.get('itemGap'), + !orientIdx ? null : maxSize.width, + orientIdx ? null : maxSize.height + ); + layoutUtil.box( // Buttons in controller are layout always horizontally. 'horizontal', @@ -202,55 +232,17 @@ var ScrollableLegendView = LegendView.extend({ var pageButtonPosition = legendModel.get('pageButtonPosition', true); // controller is on the right / bottom. if (pageButtonPosition === 'end') { - if (selector) { - if (selectorPosition === 'end') { - selectorPos[orientIdx] += maxSize[wh] - selectorRect[wh]; - controllerPos[orientIdx] += maxSize[wh] - selectorRect[wh] - - selectorButtonGap - controllerRect[wh]; - } - else { - controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh]; - containerPos[orientIdx] += selectorRect[wh] + selectorButtonGap; - } - } - else { - controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh]; - } + controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh]; } // controller is on the left / top. else { - if (selector) { - if (selectorPosition === 'start') { - controllerPos[orientIdx] += selectorRect[wh] + selectorButtonGap; - containerPos[orientIdx] += selectorRect[wh] + selectorButtonGap - + controllerRect[wh] + pageButtonGap; - } - else { - selectorPos[orientIdx] += maxSize[wh] - selectorRect[wh]; - containerPos[orientIdx] += controllerRect[wh] + pageButtonGap; - } - } - else { - containerPos[orientIdx] += controllerRect[wh] + pageButtonGap; - } - } - } - else if (selector) { - if (selectorPosition === 'end') { - selectorPos[orientIdx] += contentRect[wh] + selectorButtonGap; - } - else { - containerPos[orientIdx] += selectorRect[wh] + selectorButtonGap; + containerPos[orientIdx] += controllerRect[wh] + pageButtonGap; } } // Always align controller to content as 'middle'. controllerPos[1 - orientIdx] += contentRect[hw] / 2 - controllerRect[hw] / 2; - if (selector) { - selectorPos[1 - orientIdx] += contentRect[hw] / 2 - selectorRect[hw] / 2; - selectorGroup.attr('position', selectorPos); - } contentGroup.attr('position', contentPos); containerGroup.attr('position', containerPos); controllerGroup.attr('position', controllerPos); @@ -259,20 +251,18 @@ var ScrollableLegendView = LegendView.extend({ // mainRect should not be calculated by `this.group.getBoundingRect()` // for sake of the overflow. var mainRect = {x: 0, y: 0}; + // Consider content may be overflow (should be clipped). - mainRect[wh] = showController ? maxSize[wh] - : contentRect[wh] + selectorButtonGap + selectorRect[wh]; + mainRect[wh] = showController ? maxSize[wh] : contentRect[wh]; + mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw]); - mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw], selectorRect[hw]); // `containerRect[yx] + containerPos[1 - orientIdx]` is 0. - mainRect[yx] = Math.min(0, controllerRect[yx] + controllerPos[1 - orientIdx], - selectorRect[yx] + selectorPos[1 - orientIdx]); + mainRect[yx] = Math.min(0, controllerRect[yx] + controllerPos[1 - orientIdx]); containerGroup.__rectSize = maxSize[wh]; if (showController) { var clipShape = {x: 0, y: 0}; - clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap - - selectorRect[wh] - selectorButtonGap, 0); + clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap, 0); clipShape[hw] = mainRect[hw]; containerGroup.setClipPath(new graphic.Rect({shape: clipShape})); // Consider content may be larger than container, container rect From b7553885542b964daf030184262225e1a134c957 Mon Sep 17 00:00:00 2001 From: Ovilia Date: Wed, 26 Jun 2019 16:53:22 +0800 Subject: [PATCH 009/127] fix: graphic group position --- src/component/graphic.js | 41 +++++++++++------- test/graphicOption.html | 93 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 15 deletions(-) diff --git a/src/component/graphic.js b/src/component/graphic.js index 631dc6d3ef..82d06789ec 100644 --- a/src/component/graphic.js +++ b/src/component/graphic.js @@ -24,6 +24,7 @@ import * as zrUtil from 'zrender/src/core/util'; import * as modelUtil from '../util/model'; import * as graphicUtil from '../util/graphic'; import * as layoutUtil from '../util/layout'; +import {parsePercent} from '../util/number'; // ------------- // Preprocessor @@ -266,7 +267,7 @@ echarts.extendComponentView({ } this._lastGraphicModel = graphicModel; - this._updateElements(graphicModel); + this._updateElements(graphicModel, api); this._relocate(graphicModel, api); }, @@ -276,7 +277,7 @@ echarts.extendComponentView({ * @private * @param {Object} graphicModel graphic model */ - _updateElements: function (graphicModel) { + _updateElements: function (graphicModel, api) { var elOptionsToUpdate = graphicModel.useElOptionsToUpdate(); if (!elOptionsToUpdate) { @@ -293,6 +294,7 @@ echarts.extendComponentView({ var existEl = elMap.get(id); var parentId = elOption.parentId; var targetElParent = parentId != null ? elMap.get(parentId) : rootGroup; + console.log('tagetParent', targetElParent); var elOptionStyle = elOption.style; if (elOption.type === 'text' && elOptionStyle) { @@ -338,8 +340,24 @@ echarts.extendComponentView({ var el = elMap.get(id); if (el) { - el.__ecGraphicWidth = elOption.width; - el.__ecGraphicHeight = elOption.height; + var isParentRoot = targetElParent === rootGroup; + var parentWidth = isParentRoot + ? api.getWidth() + // Like 'position:absolute' in css, default 0. + : (targetElParent.__ecGraphicWidth || 0); + var parentHeight = isParentRoot + ? api.getHeight() + : (targetElParent.__ecGraphicHeight || 0); + + var isGroup = el.type === 'group'; + el.__ecGraphicWidth = isGroup + ? parsePercent(elOption.width, parentWidth) + : parentWidth; + el.__ecGraphicHeight = isGroup + ? parsePercent(elOption.height, parentHeight) + : parentHeight; + + console.log(el.type, el.__ecGraphicWidth, el.__ecGraphicHeight); setEventData(el, graphicModel, elOption); } }); @@ -354,7 +372,6 @@ echarts.extendComponentView({ */ _relocate: function (graphicModel, api) { var elOptions = graphicModel.option.elements; - var rootGroup = this.group; var elMap = this._elMap; // Bottom-up tranvese all elements (consider ec resize) to locate elements. @@ -366,16 +383,10 @@ echarts.extendComponentView({ continue; } - var parentEl = el.parent; - var containerInfo = parentEl === rootGroup - ? { - width: api.getWidth(), - height: api.getHeight() - } - : { // Like 'position:absolut' in css, default 0. - width: parentEl.__ecGraphicWidth || 0, - height: parentEl.__ecGraphicHeight || 0 - }; + var containerInfo = { + width: el.__ecGraphicWidth, + height: el.__ecGraphicHeight + }; layoutUtil.positionElement( el, elOption, containerInfo, null, diff --git a/test/graphicOption.html b/test/graphicOption.html index a8413a34f5..450e98cc91 100644 --- a/test/graphicOption.html +++ b/test/graphicOption.html @@ -204,6 +204,99 @@

Test resize.

}, z: 100 }] + }, { + type: 'group', + id: 'bl', + width: '100%', + height: '100%', + children: [{ + type: 'rect', + right: 0, + bottom: 0, + shape: { + width: 200, + height: 100 + }, + style: { + stroke: 'blue', + fill: 'blue', + lineWidth: 2 + } + }, { + type: 'rect', + position: [10, 20], + shape: { + width: 50, + height: 150 + }, + style: { + stroke: 'blue', + fill: 'blue', + lineWidth: 2 + } + }, { + type: 'group', + width: '50%', + height: '50%', + children: [{ + type: 'rect', + shape: { + width: 100, + height: 100 + }, + style: { + stroke: 'blue', + fill: 'blue', + lineWidth: 2 + }, + right: 0, + bottom: 0 + }] + }] + }, { + type: 'rect', + right: 0, + bottom: 0, + shape: { + width: 200, + height: 100 + }, + style: { + stroke: 'orange', + fill: 'transparent', + lineWidth: 2 + } + }, { + type: 'rect', + position: [10, 20], + shape: { + width: 50, + height: 150 + }, + style: { + stroke: 'orange', + fill: 'transparent', + lineWidth: 2 + } + }, { + type: 'rect', + shape: { + width: 100, + height: 100 + }, + style: { + stroke: 'orange', + fill: 'transparent', + lineWidth: 2 + }, + right: '50%', + bottom: '50%' + }, { + type: 'text', + position: [220, 20], + style: { + text: '蓝色矩形应与橙色矩形同一位置' + } }] } From f83c355fdfc47da1e00cf8f0c878ab5e738d7fac Mon Sep 17 00:00:00 2001 From: sushuang Date: Wed, 26 Jun 2019 21:27:39 +0800 Subject: [PATCH 010/127] remove console.log --- src/component/graphic.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/component/graphic.js b/src/component/graphic.js index 82d06789ec..0ba2570319 100644 --- a/src/component/graphic.js +++ b/src/component/graphic.js @@ -294,7 +294,6 @@ echarts.extendComponentView({ var existEl = elMap.get(id); var parentId = elOption.parentId; var targetElParent = parentId != null ? elMap.get(parentId) : rootGroup; - console.log('tagetParent', targetElParent); var elOptionStyle = elOption.style; if (elOption.type === 'text' && elOptionStyle) { @@ -357,7 +356,6 @@ echarts.extendComponentView({ ? parsePercent(elOption.height, parentHeight) : parentHeight; - console.log(el.type, el.__ecGraphicWidth, el.__ecGraphicHeight); setEventData(el, graphicModel, elOption); } }); @@ -559,4 +557,4 @@ function setEventData(el, graphicModel, elOption) { if (eventData) { eventData.info = el.info; } -} \ No newline at end of file +} From 9f983344df8d73044ed2669f1a6cf4b87b2d9761 Mon Sep 17 00:00:00 2001 From: deqingli Date: Wed, 26 Jun 2019 22:24:22 +0800 Subject: [PATCH 011/127] fix(selector): modify the style of the selector button --- src/component/legend/LegendModel.js | 39 +++++----------- src/component/legend/LegendView.js | 69 ++++++++--------------------- test/legend.html | 4 +- 3 files changed, 33 insertions(+), 79 deletions(-) diff --git a/src/component/legend/LegendModel.js b/src/component/legend/LegendModel.js index adcfb6eac1..187cfb4acb 100644 --- a/src/component/legend/LegendModel.js +++ b/src/component/legend/LegendModel.js @@ -28,12 +28,10 @@ var langTitle = lang.legendSelector.title; var defaultSelectorOption = { all: { type: 'all', - icon: 'M421.65 752.94h-60.24v60.24c0 18.07 12.05 30.12 30.12 30.12h421.65c18.07 0 30.12-12.05 30.12-30.12V391.53c0-18.07-12.05-30.12-30.12-30.12h-60.24v361.42c0 18.07-12.05 30.12-30.12 30.12H421.65z m271.06-572.23H210.82c-18.07 0-30.12 12.05-30.12 30.12v481.88c0 18.07 12.05 30.12 30.12 30.12h481.89c18.07 0 30.12-12.05 30.12-30.12V210.82c-0.01-18.07-12.05-30.11-30.12-30.11zM30.12 421.65c18.07 0 30.12-12.05 30.12-30.12V60.24h331.29c18.07 0 30.12-12.05 30.12-30.12S409.6 0 391.53 0H30.12C12.05 0 0 12.05 0 30.12v361.41c0 18.07 12.05 30.12 30.12 30.12z m361.41 542.11H60.24V632.47c0-18.07-12.05-30.12-30.12-30.12S0 614.4 0 632.47v361.41c0 18.07 12.05 30.12 30.12 30.12h361.41c18.07 0 30.12-12.05 30.12-30.12s-12.05-30.12-30.12-30.12z m602.35-361.41c-18.07 0-30.12 12.05-30.12 30.12v331.29H632.47c-18.07 0-30.12 12.05-30.12 30.12S614.4 1024 632.47 1024h361.41c18.07 0 30.12-12.05 30.12-30.12V632.47c0-18.07-12.05-30.12-30.12-30.12z m0-602.35H512c-18.07 0-30.12 12.05-30.12 30.12S493.93 60.24 512 60.24h451.76v331.29c0 18.07 12.05 30.12 30.12 30.12S1024 409.6 1024 391.53V30.12C1024 12.05 1011.95 0 993.88 0z', title: zrUtil.clone(langTitle.all) }, inverse: { type: 'inverse', - icon: 'M843.29 331.28v481.9c0 16.65-13.47 30.12-30.12 30.12H331.3c-16.65 0-30.12-13.47-30.12-30.12v-60.23h421.63c16.65 0 30.12-13.47 30.12-30.12V301.17h60.23c16.65 0 30.13 13.47 30.13 30.11zM722.82 692.72v-481.9c0-16.65-13.47-30.12-30.12-30.12H210.83c-16.65 0-30.12 13.47-30.12 30.12v481.9c0 16.65 13.47 30.12 30.12 30.12H692.7c16.65-0.01 30.12-13.48 30.12-30.12zM240.95 240.93h421.63V662.6H240.95V240.93zM60.25 391.52V60.23h331.28c16.65 0 30.12-13.47 30.12-30.12S408.18 0 391.53 0H30.13C13.48 0 0.01 13.47 0.01 30.12v361.4c0 16.65 13.47 30.12 30.12 30.12s30.12-13.48 30.12-30.12z m361.4 602.36c0-16.65-13.47-30.12-30.12-30.12H60.25V632.48c0-16.65-13.47-30.12-30.12-30.12S0.01 615.84 0.01 632.48v361.4c0 16.65 13.47 30.12 30.12 30.12h361.4c16.65 0 30.12-13.47 30.12-30.12z m602.34 0v-361.4c0-16.65-13.47-30.12-30.12-30.12s-30.12 13.47-30.12 30.12v331.28H632.47c-16.65 0-30.12 13.47-30.12 30.12s13.47 30.12 30.12 30.12h361.4c16.65 0 30.12-13.47 30.12-30.12z m0-602.36V30.12c0-16.65-13.47-30.12-30.12-30.12h-361.4c-16.65 0-30.12 13.47-30.12 30.12s13.47 30.12 30.12 30.12h331.28v331.28c0 16.65 13.47 30.12 30.12 30.12 16.65-0.01 30.12-13.48 30.12-30.12z', title: zrUtil.clone(langTitle.inverse) } }; @@ -305,37 +303,24 @@ var LegendModel = echarts.extendComponentModel({ // selector: ['all', 'inverse'] selector: false, - selectorIconStyle: { - color: null, - borderColor: '#666666', - borderWidth: 1 - // shadowBlur: null, - // shadowColor: null, - // shadowOffsetX: 0, - // shadowOffsetY: 0, - // opacity: 1 - }, - selectorIconSize: 14, - selectorTextStyle: { - show: false, - position: 'auto', - color: '#666666' + selectorLabel: { + show: true, + borderRadius: 10, + padding: [3, 5, 3, 5], + fontSize: 12, + fontFamily: ' sans-serif', + color: '#666', + borderWidth: 1, + borderColor: '#666' }, emphasis: { - selectorIconStyle: { - borderColor: '#4EADDE', - color: '#4EADDE' - }, - selectorTextStyle: { - backgroundColor: 'rgba(50,50,50,0.7)', - - padding: 3, + selectorLabel: { show: true, - position: 'auto', - color: '#fff' + color: '#eee', + backgroundColor: '#666' } }, diff --git a/src/component/legend/LegendView.js b/src/component/legend/LegendView.js index b9e8e7cd54..24e529d798 100644 --- a/src/component/legend/LegendView.js +++ b/src/component/legend/LegendView.js @@ -260,59 +260,40 @@ export default echarts.extendComponentView({ _createSelector: function (selector, legendModel, api, orient, selectorPosition) { var selectorGroup = this.getSelectorGroup(); - var iconSize = legendModel.get('selectorIconSize', true); - if (!isArray(iconSize)) { - iconSize = [iconSize, iconSize]; - } each(selector, function (selectorItem) { createSelectorButton(selectorItem); }); function createSelectorButton(selectorItem) { var type = selectorItem.type; - var icon = graphic.createIcon( - selectorItem.icon, - { - onclick: type === 'all' - ? curry(dispatchAllSelectorAction, api) - : curry(dispatchInverseSelectorAction, api) + + var labelText = new graphic.Text({ + style: { + x: 0, + y: 0, + align: 'center', + verticalAlign: 'middle' }, - { - x: -iconSize[0] / 2, - y: -iconSize[1] / 2, - width: iconSize[0], - height: iconSize[1] + onclick: function () { + api.dispatchAction({ + type: type === 'all' ? 'legendAllSelect' : 'legendInverseSelect' + }); } - ); - selectorGroup.add(icon); - icon.name = type; + }); + + selectorGroup.add(labelText); - var normalStyle = legendModel.getModel('selectorIconStyle').getItemStyle(); - icon.setStyle(normalStyle); - var hoverStyle = icon.hoverStyle = legendModel.getModel('emphasis.selectorIconStyle').getItemStyle(); + var labelModel = legendModel.getModel('selectorLabel'); + var emphasisLabelModel = legendModel.getModel('emphasis.selectorLabel'); - var normalTextStyleModel = legendModel.getModel('selectorTextStyle'); - var emphasisTextStyleModel = legendModel.getModel('emphasis.selectorTextStyle'); graphic.setLabelStyle( - icon.style, hoverStyle, normalTextStyleModel, emphasisTextStyleModel, + labelText.style, labelText.hoverStyle = {}, labelModel, emphasisLabelModel, { defaultText: selectorItem.title, - isRectText: true, - getTextPosition: function (textStyleModel) { - var textPosition = textStyleModel.getShallow('position'); - if (textPosition == null || textPosition === 'auto') { - if (orient === 'horizontal') { - textPosition = selectorPosition === 'end' ? 'left' : 'right'; - } - else if (orient === 'vertical') { - textPosition = selectorPosition === 'start' ? 'bottom' : 'top'; - } - } - return textPosition; - } + isRectText: false } ); - graphic.setHoverStyle(icon, hoverStyle); + graphic.setHoverStyle(labelText); } }, @@ -501,18 +482,6 @@ export default echarts.extendComponentView({ }); -function dispatchAllSelectorAction(api) { - api.dispatchAction({ - type: 'legendAllSelect' - }); -} - -function dispatchInverseSelectorAction(api) { - api.dispatchAction({ - type: 'legendInverseSelect' - }); -} - function dispatchSelectAction(name, api) { api.dispatchAction({ type: 'legendToggleSelect', diff --git a/test/legend.html b/test/legend.html index cae8a8943c..0f74621608 100644 --- a/test/legend.html +++ b/test/legend.html @@ -154,7 +154,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( legend: { selector: true, data: seriesInfo.legendData, - backgroundColor: 'rgba(0,100,50,0.2)' + // backgroundColor: 'rgba(0,100,50,0.2)' }, tooltip: { }, @@ -497,6 +497,7 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( legend: [{ type: 'scroll', selector: true, + selectorIconSize: 50, data: seriesInfo.legendData, backgroundColor: 'rgba(0,100,50,0.2)' }, { @@ -1155,6 +1156,5 @@

Scroll vertically, left: 10, top: 'center', position: 'start', height: 50% ( - \ No newline at end of file From 33a2e4b887157e97574c3930052754ecca4cfb28 Mon Sep 17 00:00:00 2001 From: sushuang Date: Thu, 27 Jun 2019 03:23:21 +0800 Subject: [PATCH 012/127] Fix group layout --- src/component/graphic.js | 61 +++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/src/component/graphic.js b/src/component/graphic.js index 0ba2570319..6a88f2135a 100644 --- a/src/component/graphic.js +++ b/src/component/graphic.js @@ -267,7 +267,7 @@ echarts.extendComponentView({ } this._lastGraphicModel = graphicModel; - this._updateElements(graphicModel, api); + this._updateElements(graphicModel); this._relocate(graphicModel, api); }, @@ -277,7 +277,7 @@ echarts.extendComponentView({ * @private * @param {Object} graphicModel graphic model */ - _updateElements: function (graphicModel, api) { + _updateElements: function (graphicModel) { var elOptionsToUpdate = graphicModel.useElOptionsToUpdate(); if (!elOptionsToUpdate) { @@ -339,23 +339,8 @@ echarts.extendComponentView({ var el = elMap.get(id); if (el) { - var isParentRoot = targetElParent === rootGroup; - var parentWidth = isParentRoot - ? api.getWidth() - // Like 'position:absolute' in css, default 0. - : (targetElParent.__ecGraphicWidth || 0); - var parentHeight = isParentRoot - ? api.getHeight() - : (targetElParent.__ecGraphicHeight || 0); - - var isGroup = el.type === 'group'; - el.__ecGraphicWidth = isGroup - ? parsePercent(elOption.width, parentWidth) - : parentWidth; - el.__ecGraphicHeight = isGroup - ? parsePercent(elOption.height, parentHeight) - : parentHeight; - + el.__ecGraphicWidthOption = elOption.width; + el.__ecGraphicHeightOption = elOption.height; setEventData(el, graphicModel, elOption); } }); @@ -370,7 +355,31 @@ echarts.extendComponentView({ */ _relocate: function (graphicModel, api) { var elOptions = graphicModel.option.elements; + var rootGroup = this.group; var elMap = this._elMap; + var apiWidth = api.getWidth(); + var apiHeight = api.getHeight(); + + // Top-down to calculate percentage width/height of group + for (var i = 0; i < elOptions.length; i++) { + var elOption = elOptions[i]; + var el = elMap.get(elOption.id); + + if (!el || !el.isGroup) { + continue; + } + var parentEl = el.parent; + var isParentRoot = parentEl === rootGroup; + // Like 'position:absolut' in css, default 0. + el.__ecGraphicWidth = parsePercent( + el.__ecGraphicWidthOption, + isParentRoot ? apiWidth : parentEl.__ecGraphicWidth + ) || 0; + el.__ecGraphicHeight = parsePercent( + el.__ecGraphicHeightOption, + isParentRoot ? apiHeight : parentEl.__ecGraphicHeight + ) || 0; + } // Bottom-up tranvese all elements (consider ec resize) to locate elements. for (var i = elOptions.length - 1; i >= 0; i--) { @@ -381,10 +390,16 @@ echarts.extendComponentView({ continue; } - var containerInfo = { - width: el.__ecGraphicWidth, - height: el.__ecGraphicHeight - }; + var parentEl = el.parent; + var containerInfo = parentEl === rootGroup + ? { + width: apiWidth, + height: apiHeight + } + : { + width: parentEl.__ecGraphicWidth, + height: parentEl.__ecGraphicHeight + }; layoutUtil.positionElement( el, elOption, containerInfo, null, From 3a72ce5f24272ba0a20dd8fbe1a5eb992e8bc79c Mon Sep 17 00:00:00 2001 From: deqingli Date: Thu, 27 Jun 2019 11:50:16 +0800 Subject: [PATCH 013/127] fix(legendView): remove function isArray(), which is not used --- src/component/legend/LegendView.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/component/legend/LegendView.js b/src/component/legend/LegendView.js index 24e529d798..fc0d15660e 100644 --- a/src/component/legend/LegendView.js +++ b/src/component/legend/LegendView.js @@ -28,7 +28,6 @@ import * as layoutUtil from '../../util/layout'; var curry = zrUtil.curry; var each = zrUtil.each; var Group = graphic.Group; -var isArray = zrUtil.isArray; export default echarts.extendComponentView({ From 9bfcfbd47c41d42aa3691b58252e899ef4af8a16 Mon Sep 17 00:00:00 2001 From: sushuang Date: Fri, 28 Jun 2019 17:27:39 +0800 Subject: [PATCH 014/127] Fix that inappropriate adding parameters of mergeOption method. --- src/component/marker/MarkerModel.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/component/marker/MarkerModel.js b/src/component/marker/MarkerModel.js index 5cb44a113d..8c3a3140c4 100644 --- a/src/component/marker/MarkerModel.js +++ b/src/component/marker/MarkerModel.js @@ -40,7 +40,7 @@ var MarkerModel = echarts.extendComponentModel({ /** * @overrite */ - init: function (option, parentModel, ecModel, extraOpt) { + init: function (option, parentModel, ecModel) { if (__DEV__) { if (this.type === 'marker') { @@ -48,7 +48,7 @@ var MarkerModel = echarts.extendComponentModel({ } } this.mergeDefaultAndTheme(option, ecModel); - this.mergeOption(option, ecModel, extraOpt.createdBySelf, true); + this._mergeOption(option, ecModel, false, true); }, /** @@ -63,7 +63,14 @@ var MarkerModel = echarts.extendComponentModel({ return this.getShallow('animation') && hostSeries && hostSeries.isAnimationEnabled(); }, - mergeOption: function (newOpt, ecModel, createdBySelf, isInit) { + /** + * @overrite + */ + mergeOption: function (newOpt, ecModel) { + this._mergeOption(newOpt, ecModel, false, false); + }, + + _mergeOption: function (newOpt, ecModel, createdBySelf, isInit) { var MarkerModel = this.constructor; var modelPropName = this.mainType + 'Model'; if (!createdBySelf) { @@ -107,7 +114,7 @@ var MarkerModel = echarts.extendComponentModel({ markerModel.__hostSeries = seriesModel; } else { - markerModel.mergeOption(markerOpt, ecModel, true); + markerModel._mergeOption(markerOpt, ecModel, true); } seriesModel[modelPropName] = markerModel; }, this); From 40ca973eb8c7fda617a568488b7c20e26de38aa4 Mon Sep 17 00:00:00 2001 From: sushuang Date: Fri, 28 Jun 2019 17:37:50 +0800 Subject: [PATCH 015/127] Add comment for a pending issue. --- src/component/graphic.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/component/graphic.js b/src/component/graphic.js index 6a88f2135a..457cc4c4f5 100644 --- a/src/component/graphic.js +++ b/src/component/graphic.js @@ -401,6 +401,10 @@ echarts.extendComponentView({ height: parentEl.__ecGraphicHeight }; + // PENDING + // Currently, when `bounding: 'all'`, the union bounding rect of the group + // does not include the rect of [0, 0, group.width, group.height], which + // is probably weird for users. Should we make a break change for it? layoutUtil.positionElement( el, elOption, containerInfo, null, {hv: elOption.hv, boundingMode: elOption.bounding} From e547c558065b5ebd81a9ddcad368525c5159a8ae Mon Sep 17 00:00:00 2001 From: deqingli Date: Tue, 9 Jul 2019 16:39:36 +0800 Subject: [PATCH 016/127] fix(readme): fix syntax error in readme about the paper --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 039e5805af..77c61b5040 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,6 @@ Please refer to [Apache Code of Conduct](https://www.apache.org/foundation/polic ## Reference Paper Deqing Li, Honghui Mei, Yi Shen, Shuang Su, Wenli Zhang, Junting Wang, Ming Zu, Wei Chen. -[ECharts: A Declarative Framework for Rapid Construction of Wed-based Visualization](https://www.sciencedirect.com/science/article/pii/S2468502X18300068). +[ECharts: A Declarative Framework for Rapid Construction of Web-based Visualization](https://www.sciencedirect.com/science/article/pii/S2468502X18300068). Visual Informatics, 2018. From c10773fa0eccb5c11c57bd7d7f813d83c2d55cb6 Mon Sep 17 00:00:00 2001 From: chengjie Date: Thu, 11 Jul 2019 18:21:19 +0800 Subject: [PATCH 017/127] Feature - support version 3.0 (bmap) Expanding echart to support version 3.0 (bmap) of Baidu Map API. --- extension-src/bmap/BMapModel.js | 2 ++ extension-src/bmap/BMapView.js | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/extension-src/bmap/BMapModel.js b/extension-src/bmap/BMapModel.js index 8fb263d5de..ca5cb6525a 100644 --- a/extension-src/bmap/BMapModel.js +++ b/extension-src/bmap/BMapModel.js @@ -49,6 +49,8 @@ export default echarts.extendComponentModel({ mapStyle: {}, + mapStyleV2: {}, + roam: false } }); \ No newline at end of file diff --git a/extension-src/bmap/BMapView.js b/extension-src/bmap/BMapView.js index dfd6e722ce..b6ee812d1e 100644 --- a/extension-src/bmap/BMapView.js +++ b/extension-src/bmap/BMapView.js @@ -87,6 +87,7 @@ export default echarts.extendComponentView({ bmap.disablePinchToZoom(); } + /* map 2.0 */ var originalStyle = bMapModel.__mapStyle; var newMapStyle = bMapModel.get('mapStyle') || {}; @@ -100,6 +101,20 @@ export default echarts.extendComponentView({ bMapModel.__mapStyle = JSON.parse(mapStyleStr); } + /* map 3.0 */ + var originalStyle2 = bMapModel.__mapStyle2; + + var newMapStyle2 = bMapModel.get('mapStyleV2') || {}; + // FIXME, Not use JSON methods + var mapStyleStr2 = JSON.stringify(newMapStyle2); + if (JSON.stringify(originalStyle2) !== mapStyleStr2) { + // FIXME May have blank tile when dragging if setMapStyle + if (Object.keys(newMapStyle2).length) { + bmap.setMapStyleV2(newMapStyle2); + } + bMapModel.__mapStyle2 = JSON.parse(mapStyleStr2); + } + rendering = false; } }); \ No newline at end of file From 3bbcf2f3beacd992862457ec476650ea741f265f Mon Sep 17 00:00:00 2001 From: susiwen Date: Fri, 12 Jul 2019 13:33:35 +0800 Subject: [PATCH 018/127] Fix #10853 update custom build site --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 77c61b5040..364d09edea 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ ECharts-GL is an extension pack of ECharts, which provides 3D plots, globe visua ## Build -Check this tutorial [Create Custom Build of ECharts](https://ecomfe.github.io/echarts-doc/public/en/tutorial.html#Create%20Custom%20Build%20of%20ECharts) +Check this tutorial [Create Custom Build of ECharts](https://echarts.apache.org/en/builder.html) please. ## License From bb79bf0b33b12eb1f7f1b5d34da70a18fbb76502 Mon Sep 17 00:00:00 2001 From: Ovilia Date: Mon, 15 Jul 2019 11:56:25 +0800 Subject: [PATCH 019/127] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 364d09edea..0b3abbb3b8 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ ECharts-GL is an extension pack of ECharts, which provides 3D plots, globe visua ## Build -Check this tutorial [Create Custom Build of ECharts](https://echarts.apache.org/en/builder.html) +Check this tutorial [Create Custom Build of ECharts](https://echarts.apache.org/en/tutorial.html#Create%20Custom%20Build%20of%20ECharts) please. ## License From c6d660981acf6079904b9840330909937cdc1069 Mon Sep 17 00:00:00 2001 From: ende93 Date: Mon, 18 Feb 2019 21:06:59 +0800 Subject: [PATCH 020/127] [effectScatter] add rippleEffect.color --- src/chart/helper/EffectSymbol.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/chart/helper/EffectSymbol.js b/src/chart/helper/EffectSymbol.js index 80d94dade8..29eb6813ff 100644 --- a/src/chart/helper/EffectSymbol.js +++ b/src/chart/helper/EffectSymbol.js @@ -38,13 +38,14 @@ function normalizeSymbolSize(symbolSize) { } function updateRipplePath(rippleGroup, effectCfg) { + const color = effectCfg.rippleEffectColor || effectCfg.color rippleGroup.eachChild(function (ripplePath) { ripplePath.attr({ z: effectCfg.z, zlevel: effectCfg.zlevel, style: { - stroke: effectCfg.brushType === 'stroke' ? effectCfg.color : null, - fill: effectCfg.brushType === 'fill' ? effectCfg.color : null + stroke: effectCfg.brushType === 'stroke' ? color : null, + fill: effectCfg.brushType === 'fill' ? color : null } }); }); @@ -81,9 +82,6 @@ effectSymbolProto.startEffectAnimation = function (effectCfg) { var rippleGroup = this.childAt(1); for (var i = 0; i < EFFECT_RIPPLE_NUMBER; i++) { - // var ripplePath = createSymbol( - // symbolType, -0.5, -0.5, 1, 1, color - // ); // If width/height are set too small (e.g., set to 1) on ios10 // and macOS Sierra, a circle stroke become a rect, no matter what // the scale is set. So we set width/height as 2. See #4136. @@ -198,6 +196,7 @@ effectSymbolProto.updateData = function (data, idx) { effectCfg.zlevel = itemModel.getShallow('zlevel') || 0; effectCfg.symbolType = symbolType; effectCfg.color = color; + effectCfg.rippleEffectColor = itemModel.get('rippleEffect.color') this.off('mouseover').off('mouseout').off('emphasis').off('normal'); From c47d6c80146ef282b0537db3691a89dc91d038f6 Mon Sep 17 00:00:00 2001 From: ende93 Date: Mon, 29 Jul 2019 19:40:40 +0800 Subject: [PATCH 021/127] fix: add comma --- src/chart/helper/EffectSymbol.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chart/helper/EffectSymbol.js b/src/chart/helper/EffectSymbol.js index 29eb6813ff..c515c7fa5a 100644 --- a/src/chart/helper/EffectSymbol.js +++ b/src/chart/helper/EffectSymbol.js @@ -38,7 +38,7 @@ function normalizeSymbolSize(symbolSize) { } function updateRipplePath(rippleGroup, effectCfg) { - const color = effectCfg.rippleEffectColor || effectCfg.color + const color = effectCfg.rippleEffectColor || effectCfg.color; rippleGroup.eachChild(function (ripplePath) { ripplePath.attr({ z: effectCfg.z, @@ -196,7 +196,7 @@ effectSymbolProto.updateData = function (data, idx) { effectCfg.zlevel = itemModel.getShallow('zlevel') || 0; effectCfg.symbolType = symbolType; effectCfg.color = color; - effectCfg.rippleEffectColor = itemModel.get('rippleEffect.color') + effectCfg.rippleEffectColor = itemModel.get('rippleEffect.color'); this.off('mouseover').off('mouseout').off('emphasis').off('normal'); From 4da347c9e820f2007ffcd6bd1904e1108f7b07d0 Mon Sep 17 00:00:00 2001 From: Ovilia Date: Fri, 2 Aug 2019 11:18:04 +0800 Subject: [PATCH 022/127] fix: dispose checking for chart instance --- src/echarts.js | 87 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 13 deletions(-) diff --git a/src/echarts.js b/src/echarts.js index acc3496c32..fc9621c4f9 100644 --- a/src/echarts.js +++ b/src/echarts.js @@ -98,7 +98,12 @@ var OPTION_UPDATED = '__optionUpdated'; var ACTION_REG = /^[a-zA-Z0-9_]+$/; -function createRegisterEventWithLowercaseName(method) { +function createRegisterEventWithLowercaseName(method, ignoreDisposed) { + if (!ignoreDisposed && this._disposed) { + disposedWarning(this.id); + return; + } + return function (eventName, handler, context) { // Event name is all lowercase eventName = eventName && eventName.toLowerCase(); @@ -112,9 +117,9 @@ function createRegisterEventWithLowercaseName(method) { function MessageCenter() { Eventful.call(this); } -MessageCenter.prototype.on = createRegisterEventWithLowercaseName('on'); -MessageCenter.prototype.off = createRegisterEventWithLowercaseName('off'); -MessageCenter.prototype.one = createRegisterEventWithLowercaseName('one'); +MessageCenter.prototype.on = createRegisterEventWithLowercaseName('on', true); +MessageCenter.prototype.off = createRegisterEventWithLowercaseName('off', true); +MessageCenter.prototype.one = createRegisterEventWithLowercaseName('one', true); zrUtil.mixin(MessageCenter, Eventful); /** @@ -350,6 +355,10 @@ echartsProto.setOption = function (option, notMerge, lazyUpdate) { if (__DEV__) { assert(!this[IN_MAIN_PROCESS], '`setOption` should not be called during main process.'); } + if (this._disposed) { + disposedWarning(this.id); + return; + } var silent; if (isObject(notMerge)) { @@ -485,6 +494,11 @@ echartsProto.getSvgDataUrl = function () { * @param {string} [opts.excludeComponents] */ echartsProto.getDataURL = function (opts) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + opts = opts || {}; var excludeComponents = opts.excludeComponents; var ecModel = this._model; @@ -525,6 +539,11 @@ echartsProto.getDataURL = function (opts) { * @param {string} [opts.backgroundColor] */ echartsProto.getConnectedDataURL = function (opts) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + if (!env.canvasSupported) { return; } @@ -644,6 +663,11 @@ echartsProto.convertToPixel = zrUtil.curry(doConvertPixel, 'convertToPixel'); echartsProto.convertFromPixel = zrUtil.curry(doConvertPixel, 'convertFromPixel'); function doConvertPixel(methodName, finder, value) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + var ecModel = this._model; var coordSysList = this._coordSysMgr.getCoordinateSystems(); var result; @@ -684,6 +708,11 @@ function doConvertPixel(methodName, finder, value) { * @return {boolean} result */ echartsProto.containPixel = function (finder, value) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + var ecModel = this._model; var result; @@ -1056,6 +1085,10 @@ echartsProto.resize = function (opts) { if (__DEV__) { assert(!this[IN_MAIN_PROCESS], '`resize` should not be called during main process.'); } + if (this._disposed) { + disposedWarning(this.id); + return; + } this._zr.resize(opts); @@ -1098,6 +1131,11 @@ function updateStreamModes(ecIns, ecModel) { * @param {Object} [cfg] */ echartsProto.showLoading = function (name, cfg) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + if (isObject(name)) { cfg = name; name = ''; @@ -1122,6 +1160,11 @@ echartsProto.showLoading = function (name, cfg) { * Hide loading effect */ echartsProto.hideLoading = function () { + if (this._disposed) { + disposedWarning(this.id); + return; + } + this._loadingFX && this._zr.remove(this._loadingFX); this._loadingFX = null; }; @@ -1149,6 +1192,11 @@ echartsProto.makeActionFromEvent = function (eventObj) { * undefined: Auto decide whether perform flush. */ echartsProto.dispatchAction = function (payload, opt) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + if (!isObject(opt)) { opt = {silent: !!opt}; } @@ -1317,6 +1365,11 @@ function bindRenderedEvent(zr, ecIns) { * @param {Array|TypedArray} params.data */ echartsProto.appendData = function (params) { + if (this._disposed) { + disposedWarning(this.id); + return; + } + var seriesIndex = params.seriesIndex; var ecModel = this.getModel(); var seriesModel = ecModel.getSeriesByIndex(seriesIndex); @@ -1342,9 +1395,9 @@ echartsProto.appendData = function (params) { * Register event * @method */ -echartsProto.on = createRegisterEventWithLowercaseName('on'); -echartsProto.off = createRegisterEventWithLowercaseName('off'); -echartsProto.one = createRegisterEventWithLowercaseName('one'); +echartsProto.on = createRegisterEventWithLowercaseName('on', false); +echartsProto.off = createRegisterEventWithLowercaseName('off', false); +echartsProto.one = createRegisterEventWithLowercaseName('one', false); /** * Prepare view instances of charts and components @@ -1622,6 +1675,10 @@ echartsProto.isDisposed = function () { * Clear */ echartsProto.clear = function () { + if (this._disposed) { + disposedWarning(this.id); + return; + } this.setOption({ series: [] }, true); }; @@ -1630,9 +1687,7 @@ echartsProto.clear = function () { */ echartsProto.dispose = function () { if (this._disposed) { - if (__DEV__) { - console.warn('Instance ' + this.id + ' has been disposed'); - } + disposedWarning(this.id); return; } this._disposed = true; @@ -1657,6 +1712,12 @@ echartsProto.dispose = function () { zrUtil.mixin(ECharts, Eventful); +function disposedWarning(id) { + if (__DEV__) { + console.warn('Instance ' + id + ' has been disposed'); + } +} + function updateHoverLayerStatus(ecIns, ecModel) { var zr = ecIns._zr; var storage = zr.storage; @@ -2006,9 +2067,9 @@ export function init(dom, theme, opts) { ) ) { console.warn('Can\'t get DOM width or height. Please check ' - + 'dom.clientWidth and dom.clientHeight. They should not be 0.' - + 'For example, you may need to call this in the callback ' - + 'of window.onload.'); + + 'dom.clientWidth and dom.clientHeight. They should not be 0.' + + 'For example, you may need to call this in the callback ' + + 'of window.onload.'); } } From a27ab13ba3d58206584c2db91310e88f965dadd9 Mon Sep 17 00:00:00 2001 From: Ovilia Date: Fri, 2 Aug 2019 14:27:40 +0800 Subject: [PATCH 023/127] fix: da1b75e4754bd3e42c8b3d678ad0d2e45ef022b3 --- src/echarts.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/echarts.js b/src/echarts.js index fc9621c4f9..4fc0b0af9e 100644 --- a/src/echarts.js +++ b/src/echarts.js @@ -99,12 +99,12 @@ var ACTION_REG = /^[a-zA-Z0-9_]+$/; function createRegisterEventWithLowercaseName(method, ignoreDisposed) { - if (!ignoreDisposed && this._disposed) { - disposedWarning(this.id); - return; - } - return function (eventName, handler, context) { + if (!ignoreDisposed && this._disposed) { + disposedWarning(this.id); + return; + } + // Event name is all lowercase eventName = eventName && eventName.toLowerCase(); Eventful.prototype[method].call(this, eventName, handler, context); From cce4abdfad3aba76d384327b5b95d8aeec6c5634 Mon Sep 17 00:00:00 2001 From: Benson Muite Date: Sun, 18 Aug 2019 06:49:04 +0300 Subject: [PATCH 024/127] Update README.md Update links to documentation --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 0b3abbb3b8..a58c639bab 100644 --- a/README.md +++ b/README.md @@ -32,17 +32,17 @@ ECharts-GL is an extension pack of ECharts, which provides 3D plots, globe visua ## Docs -+ [Tutorial](http://echarts.baidu.com/tutorial.html) - + [中文](http://echarts.baidu.com/tutorial.html) - + [English](http://ecomfe.github.io/echarts-doc/public/en/tutorial.html) ++ Tutorial + + [中文](https://echarts.apache.org/zh/tutorial.html) + + [English](https://echarts.apache.org/en/tutorial.html) -+ [API](http://echarts.baidu.com/api.html) - + [中文](http://echarts.baidu.com/api.html) - + [English](http://ecomfe.github.io/echarts-doc/public/en/api.html) ++ API + + [中文](https://echarts.apache.org/zh/api.html) + + [English](https://echarts.apache.org/en/api.html) -+ [Option Manual](http://echarts.baidu.com/option.html) - + [中文](http://echarts.baidu.com/option.html) - + [English](http://ecomfe.github.io/echarts-doc/public/en/option.html) ++ Option Manual + + [中文](https://echarts.apache.org/zh/option.html) + + [English](https://echarts.apache.org/en/option.html) ## Resources From a88b6e116ee57506ae3228c648dd0ad673376eb5 Mon Sep 17 00:00:00 2001 From: hejinxin Date: Thu, 6 Jun 2019 12:09:48 +0800 Subject: [PATCH 025/127] refinement: shortened _trim regex --- src/util/number.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/number.js b/src/util/number.js index 77e8966e38..efc4d740af 100644 --- a/src/util/number.js +++ b/src/util/number.js @@ -31,7 +31,7 @@ import * as zrUtil from 'zrender/src/core/util'; var RADIAN_EPSILON = 1e-4; function _trim(str) { - return str.replace(/^\s+/, '').replace(/\s+$/, ''); + return str.replace(/^\s+|\s+$/g, ''); } /** From d5b803555a4d47293e6377f23ebe33bf563a1dc0 Mon Sep 17 00:00:00 2001 From: Ovilia Date: Thu, 22 Aug 2019 13:14:40 +0800 Subject: [PATCH 026/127] doc: update email info in readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index a58c639bab..d567e8b00e 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,12 @@ ECharts-GL is an extension pack of ECharts, which provides 3D plots, globe visua + [中文](https://echarts.apache.org/zh/option.html) + [English](https://echarts.apache.org/en/option.html) +## Get Helped + ++ [GitHub Issues](https://github.com/apache/incubator-echarts/issues) for bug report and feature requests ++ Email [dev@echarts.apache.org](dev@echarts.apache.org) for general questions ++ Subscribe [mailing list](https://echarts.apache.org/en/maillist.html) to get updated with the project + ## Resources From a1922141933ed3d0e4ff148042f16c10c2454cd7 Mon Sep 17 00:00:00 2001 From: Nguyen Thuy Date: Thu, 22 Aug 2019 11:53:35 +0700 Subject: [PATCH 027/127] fix wording coodToData to coordToData --- src/coord/radar/Radar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coord/radar/Radar.js b/src/coord/radar/Radar.js index be308cabd4..01234b1ff4 100644 --- a/src/coord/radar/Radar.js +++ b/src/coord/radar/Radar.js @@ -120,7 +120,7 @@ Radar.prototype.pointToData = function (pt) { } } - return [closestAxisIdx, +(closestAxis && closestAxis.coodToData(radius))]; + return [closestAxisIdx, +(closestAxis && closestAxis.coordToData(radius))]; }; Radar.prototype.resize = function (radarModel, api) { From 6587e3294bc058e35d7a83b00c489bfea6e0b39a Mon Sep 17 00:00:00 2001 From: deqingli Date: Mon, 26 Aug 2019 16:39:39 +0800 Subject: [PATCH 028/127] update legend selector default option --- src/chart/sankey/sankeyAction.js | 2 +- src/chart/tree/treeAction.js | 1 - src/component/legend/LegendModel.js | 4 +--- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/chart/sankey/sankeyAction.js b/src/chart/sankey/sankeyAction.js index 5a0ad64a3b..584c0b3937 100644 --- a/src/chart/sankey/sankeyAction.js +++ b/src/chart/sankey/sankeyAction.js @@ -27,7 +27,7 @@ import '../helper/focusNodeAdjacencyAction'; echarts.registerAction({ type: 'dragNode', - event: 'dragNode', + event: 'dragnode', // here can only use 'update' now, other value is not support in echarts. update: 'update' }, function (payload, ecModel) { diff --git a/src/chart/tree/treeAction.js b/src/chart/tree/treeAction.js index 3b9ca490e1..cdaa5c7297 100644 --- a/src/chart/tree/treeAction.js +++ b/src/chart/tree/treeAction.js @@ -35,7 +35,6 @@ echarts.registerAction({ var tree = seriesModel.getData().tree; var node = tree.getNodeByDataIndex(dataIndex); node.isExpand = !node.isExpand; - }); }); diff --git a/src/component/legend/LegendModel.js b/src/component/legend/LegendModel.js index 187cfb4acb..70bf54040e 100644 --- a/src/component/legend/LegendModel.js +++ b/src/component/legend/LegendModel.js @@ -296,15 +296,13 @@ var LegendModel = echarts.extendComponentModel({ // data: [], // Usage: - // selector: [{type: 'all or inverse', icon: 'xxx', title: xxx}] + // selector: [{type: 'all or inverse', title: xxx}] // or // selector: true // or // selector: ['all', 'inverse'] selector: false, - selectorIconSize: 14, - selectorLabel: { show: true, borderRadius: 10, From 99dd860e7c57be88ed864369713f7faface088d8 Mon Sep 17 00:00:00 2001 From: Ovilia Date: Wed, 28 Aug 2019 14:54:22 +0800 Subject: [PATCH 029/127] doc: update readme, adding debug instructions --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d567e8b00e..578baec7a1 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,11 @@ ECharts-GL is an extension pack of ECharts, which provides 3D plots, globe visua + [中文](https://echarts.apache.org/zh/option.html) + [English](https://echarts.apache.org/en/option.html) -## Get Helped +## Debug + +If you wish to debug locally, or make pull requests, please refer to [contributing](https://github.com/apache/incubator-echarts/blob/master/.github/CONTRIBUTING.md) document. + +## Get Help + [GitHub Issues](https://github.com/apache/incubator-echarts/issues) for bug report and feature requests + Email [dev@echarts.apache.org](dev@echarts.apache.org) for general questions From dfb7f5dda4ed725e01318b3f253a8bef5e03e75a Mon Sep 17 00:00:00 2001 From: Ovilia Date: Wed, 28 Aug 2019 15:07:57 +0800 Subject: [PATCH 030/127] doc: update readme --- README.md | 133 ++++++++---------------------------------------------- 1 file changed, 18 insertions(+), 115 deletions(-) diff --git a/README.md b/README.md index 578baec7a1..ebcb9fd320 100644 --- a/README.md +++ b/README.md @@ -9,16 +9,16 @@ ECharts is a free, powerful charting and visualization library offering an easy Now ECharts is an incubator project of Apache Software Foundation. Please check its incubator status [here](http://incubator.apache.org/projects/echarts.html) -**[中文官网](http://echarts.baidu.com)** | **[ENGLISH HOMEPAGE](https://echarts.apache.org/index.html)** +**[中文官网](https://echarts.apache.org/zh/index.html)** | **[ENGLISH HOMEPAGE](https://echarts.apache.org/index.html)** -[![Build Status](https://travis-ci.org/apache/incubator-echarts.svg?branch=master)](https://travis-ci.org/apache/incubator-echarts) [![](https://img.shields.io/npm/dw/echarts.svg?label=npm%20downloads&style=flat)](https://www.npmjs.com/package/echarts) ![Commits Since 4.0.0](https://img.shields.io/github/commits-since/apache/incubator-echarts/4.0.0.svg?colorB=%234c1&style=flat) +[![Build Status](https://travis-ci.org/apache/incubator-echarts.svg?branch=master)](https://travis-ci.org/apache/incubator-echarts) [![](https://img.shields.io/npm/dw/echarts.svg?label=npm%20downloads&style=flat)](https://www.npmjs.com/package/echarts) [![Last npm release](https://img.shields.io/npm/v/echarts)](https://www.npmjs.com/package/echarts) ## Get ECharts You may choose one of the following methods: -+ Download from Official Website in [中文下载页](http://echarts.baidu.com/download.html) -+ Download from Official Website in [English](https://ecomfe.github.io/echarts-doc/public/en/download.html) ++ Download from Official Website in [中文下载页](https://echarts.apache.org/zh/download.html) ++ Download from Official Website in [English](https://echarts.apache.org/en/download.html) + `npm install echarts --save` + CDN: [jsDelivr CDN](https://www.jsdelivr.com/package/npm/echarts?path=dist) @@ -44,135 +44,39 @@ ECharts-GL is an extension pack of ECharts, which provides 3D plots, globe visua + [中文](https://echarts.apache.org/zh/option.html) + [English](https://echarts.apache.org/en/option.html) -## Debug - -If you wish to debug locally, or make pull requests, please refer to [contributing](https://github.com/apache/incubator-echarts/blob/master/.github/CONTRIBUTING.md) document. - ## Get Help + [GitHub Issues](https://github.com/apache/incubator-echarts/issues) for bug report and feature requests + Email [dev@echarts.apache.org](dev@echarts.apache.org) for general questions + Subscribe [mailing list](https://echarts.apache.org/en/maillist.html) to get updated with the project -## Resources +## Build + +Check this tutorial [Create Custom Build of ECharts](https://echarts.apache.org/en/tutorial.html#Create%20Custom%20Build%20of%20ECharts) + please. + +## Contribution +If you wish to debug locally, or make pull requests, please refer to [contributing](https://github.com/apache/incubator-echarts/blob/master/.github/CONTRIBUTING.md) document. + +## Resources ### Awesome ECharts [https://github.com/ecomfe/awesome-echarts](https://github.com/ecomfe/awesome-echarts) -### Official Extensions - -+ [水球图 Liquidfill](https://github.com/ecomfe/echarts-liquidfill) +### Extensions -+ [字符云 Wordcloud](https://github.com/ecomfe/echarts-wordcloud) ++ [Liquidfill 水球图](https://github.com/ecomfe/echarts-liquidfill) -+ [Graph Modularity](https://github.com/ecomfe/echarts-graph-modularity) Graph modularity extension for community detection ++ [Wordcloud 字符云](https://github.com/ecomfe/echarts-wordcloud) -+ [百度地图扩展](https://github.com/ecomfe/echarts/tree/master/extension/bmap) ++ [Baidu Map 百度地图扩展](https://github.com/apache/incubator-echarts/tree/master/extension/bmap) + [vue-echarts](https://github.com/ecomfe/vue-echarts) ECharts component for Vue.js + [echarts-stat](https://github.com/ecomfe/echarts-stat) Statistics tool for ECharts - -### Developers Contributions - - -#### GIS - -+ [leaflet-echarts](https://github.com/wandergis/leaflet-echarts3) by wandergis -+ [arcgis-echarts](https://github.com/wandergis/arcgis-echarts3) by wandergis - -+ [echarts-leaflet](https://github.com/gnijuohz/echarts-leaflet) by gnijuohz - -+ [ol3Echarts](https://github.com/sakitam-fdd/ol3Echarts) by sakitam-fdd - -#### Map Data and Tools - -+ [echarts-mapmaker](https://github.com/echarts-maps/echarts-mapmaker) by chfw -+ [echarts-cities-js](https://github.com/echarts-maps/echarts-cities-js) by chfw -+ [echarts-china-cities-js](https://github.com/echarts-maps/echarts-china-cities-js) by chfw -+ [echarts-countries-js](https://github.com/echarts-maps/echarts-countries-js) by chfw - - -#### AngularJS Binding - -+ [angular-echarts](https://github.com/wangshijun/angular-echarts) by wangshijun -+ [echarts-ng](https://github.com/bornkiller/echarts-ng) by bornkiller -+ [ng-echarts](https://github.com/liekkas/ng-echarts) by liekkas -+ [ngx-echarts](https://github.com/xieziyu/ngx-echarts) by xieziyu - -#### Ember Binding -+ [echarts-ember](https://github.com/bruckwubete/echarts-ember) by [bruck wubete](https://github.com/bruckwubete) -+ [ember-cli-echarts](https://github.com/funnelcloudinc/ember-cli-echarts) by FunnelCloud - -#### Vue Component - -+ [vue-echarts](https://github.com/ecomfe/vue-echarts) by ecomfe -+ [vue-echarts](https://github.com/panteng/vue-echarts) by panteng -+ [vue-echarts-v3](https://github.com/xlsdg/vue-echarts-v3) by xlsdg - -#### React Component - -+ [echarts-for-react](https://github.com/hustcc/echarts-for-react) by hustcc -+ [react-echarts](https://github.com/somonus/react-echarts) by somonus -+ [re-echarts](https://github.com/liekkas/re-echarts) by liekkas -+ [react-echarts-v3](https://github.com/xlsdg/react-echarts-v3) by xlsdg -+ [d2recharts](https://github.com/leungwensen/d2recharts) by leungwensen -+ [react-component-echarts](https://github.com/dawiwt/react-component-echarts) by dawiwt - -#### React Native Component - -+ [react-native-echarts](https://github.com/somonus/react-native-echarts) by somonus - -### Other Languages -#### Python - -+ [echarts-python](https://github.com/yufeiminds/echarts-python) by yufeiminds -+ [krisk](https://github.com/napjon/krisk) by napjon -+ [pyecharts](https://github.com/chenjiandongx/pyecharts) by chenjiandong - -#### R - -+ [recharts](https://github.com/taiyun/recharts) by taiyun -+ [recharts](https://github.com/yihui/recharts) by yihui -+ [ECharts2Shiny](https://github.com/XD-DENG/ECharts2Shiny) by XD-DENG -+ [echarts4r](https://github.com/JohnCoene/echarts4r) by JohnCoene - -#### Julia - -+ [ECharts.jl](https://github.com/randyzwitch/ECharts.jl) by randyzwitch - -#### PureScript - -+ [purescript-echarts](https://github.com/slamdata/purescript-echarts/) - -#### iOS - -+ [iOS-Echarts](https://github.com/Pluto-Y/iOS-Echarts) by Pluto-Y - -#### Java - -+ [ECharts-Java](http://www.oschina.net/p/echarts-java) by Liuzh_533 - -#### .NET - -+ [EChartsSDK](https://github.com/idoku/EChartsSDK) by idoku - -#### PHP - -+ [Echarts-PHP](https://github.com/hisune/Echarts-PHP) by hisune - -#### Node - -+ [Node-Echarts](https://github.com/suxiaoxin/node-echarts) by suxiaoxin - -## Build - -Check this tutorial [Create Custom Build of ECharts](https://echarts.apache.org/en/tutorial.html#Create%20Custom%20Build%20of%20ECharts) - please. - ## License ECharts is available under the Apache License V2. @@ -181,9 +85,8 @@ ECharts is available under the Apache License V2. Please refer to [Apache Code of Conduct](https://www.apache.org/foundation/policies/conduct.html). -## Reference Paper +## Publication Deqing Li, Honghui Mei, Yi Shen, Shuang Su, Wenli Zhang, Junting Wang, Ming Zu, Wei Chen. [ECharts: A Declarative Framework for Rapid Construction of Web-based Visualization](https://www.sciencedirect.com/science/article/pii/S2468502X18300068). Visual Informatics, 2018. - From e7eaaa93a231ee0aca9762d7437499495e18da4d Mon Sep 17 00:00:00 2001 From: pissang Date: Thu, 29 Aug 2019 00:14:50 +0800 Subject: [PATCH 031/127] test: Run the tests automatically for visual regression test. --- package.json | 12 +- test/runTest/blacklist.js | 4 + test/runTest/cli.js | 312 ++++++++++++++++++++++++++++++ test/runTest/client/client.css | 26 +++ test/runTest/client/client.js | 35 ++++ test/runTest/client/index.html | 73 +++++++ test/runTest/compareScreenshot.js | 41 ++++ test/runTest/runtime.js | 71 +++++++ test/runTest/serve.js | 29 +++ 9 files changed, 601 insertions(+), 2 deletions(-) create mode 100644 test/runTest/blacklist.js create mode 100644 test/runTest/cli.js create mode 100644 test/runTest/client/client.css create mode 100644 test/runTest/client/client.js create mode 100644 test/runTest/client/index.html create mode 100644 test/runTest/compareScreenshot.js create mode 100644 test/runTest/runtime.js create mode 100644 test/runTest/serve.js diff --git a/package.json b/package.json index 18ad5a25b4..fe0c6dc259 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ }, "scripts": { "prepublish": "node build/build.js --prepublish", + "test:visual": "node build/build.js && node test/runTest/cli.js", "test": "node build/build.js" }, "dependencies": { @@ -31,10 +32,17 @@ "escodegen": "1.8.0", "esprima": "2.7.2", "estraverse": "4.1.1", - "fs-extra": "0.26.7", + "fs-extra": "^0.26.7", "glob": "7.0.0", + "open": "^6.4.0", + "pixelmatch": "^5.0.2", + "pngjs": "^3.4.0", + "puppeteer": "^1.19.0", "rollup": "0.50.0", "rollup-plugin-node-resolve": "3.0.0", - "rollup-plugin-uglify": "2.0.1" + "rollup-plugin-uglify": "2.0.1", + "seedrandom": "^3.0.3", + "serve-handler": "^6.1.1", + "slugify": "^1.3.4" } } diff --git a/test/runTest/blacklist.js b/test/runTest/blacklist.js new file mode 100644 index 0000000000..e0596078c2 --- /dev/null +++ b/test/runTest/blacklist.js @@ -0,0 +1,4 @@ +module.exports = [ +'-cases.html', +'geo-random-stream.html' +]; \ No newline at end of file diff --git a/test/runTest/cli.js b/test/runTest/cli.js new file mode 100644 index 0000000000..b560072b21 --- /dev/null +++ b/test/runTest/cli.js @@ -0,0 +1,312 @@ +const puppeteer = require('puppeteer'); +const slugify = require('slugify'); +const fse = require('fs-extra'); +const fs = require('fs'); +const https = require('https'); +const path = require('path'); +const open = require('open'); +const util = require('util'); +const glob = require('glob'); +const {serve, origin} = require('./serve'); +const compareScreenshot = require('./compareScreenshot'); +const blacklist = require('./blacklist'); + +const seedrandomCode = fs.readFileSync( + path.join(__dirname, '../../node_modules/seedrandom/seedrandom.js'), + 'utf-8' +); +const runtimeCode = fs.readFileSync(path.join(__dirname, './runtime.js'), 'utf-8'); + +function getVersionDir(version) { + version = version || 'developing'; + return `tmp/__version__/${version}`; +} + +function getScreenshotDir() { + return 'tmp/__screenshot__'; +} + +function getTestName(fileUrl) { + return path.basename(fileUrl, '.html'); +} + +function getCacheFilePath() { + return path.join(__dirname, 'tmp/__cache__.json'); +} + +function sortScreenshots(list) { + return list.sort((a, b) => { + return a.testName.localeCompare(b.testName); + }); +} + +function getClientRelativePath(absPath) { + return path.join('../', path.relative(__dirname, absPath)); +} + +function replaceEChartsVersion(interceptedRequest, version) { + // TODO Extensions and maps + if (interceptedRequest.url().endsWith('dist/echarts.js')) { + interceptedRequest.continue({ + url: `${origin}/test/runTest/${getVersionDir(version)}/echarts.js` + }); + } + else { + interceptedRequest.continue(); + } +} + +function prepareEChartsVersion(version) { + let versionFolder = path.join(__dirname, getVersionDir(version)); + fse.ensureDirSync(versionFolder); + if (!version) { + // Developing version, make sure it's new build + return fse.copy( + path.join(__dirname, '../../dist/echarts.js'), + `${versionFolder}/echarts.js` + ); + } + return new Promise(resolve => { + if (!fs.existsSync(`${versionFolder}/echarts.js`)) { + const file = fs.createWriteStream(`${versionFolder}/echarts.js`); + + console.log('Downloading echarts4.2.1 from ', `https://cdn.jsdelivr.net/npm/echarts@${version}/dist/echarts.js`); + https.get(`https://cdn.jsdelivr.net/npm/echarts@${version}/dist/echarts.js`, response => { + response.pipe(file); + + file.on('finish', () => { + resolve(); + }) + }); + } + else { + resolve(); + } + }); +} + +function waitPageForFinish(page) { + return new Promise(resolve => { + page.exposeFunction('puppeteerFinishTest', () => { + resolve(); + }); + }); +} + +function createWaitTimeout(maxTime) { + let timeoutHandle; + let resolve; + function keepWait(newMaxTime) { + newMaxTime = newMaxTime == null ? maxTime : newMaxTime; + clearTimeout(timeoutHandle); + createTimeout(newMaxTime); + } + + function createTimeout(maxTime) { + timeoutHandle = setTimeout(() => { + resolve(); + }, maxTime); + } + + function waitTimeout() { + return new Promise(_resolve => { + resolve = _resolve; + createTimeout(maxTime); + }); + } + + return {keepWait, waitTimeout} +} + +async function takeScreenshot(page, elementQuery, fileUrl, desc, version) { + let target = elementQuery ? await page.$(elementQuery) : page; + if (!target) { + console.error(`Can't find element '${elementQuery}'`); + return; + } + let fullPage = !elementQuery; + let testName = getTestName(fileUrl); + if (desc) { + testName += '-' + slugify(desc, { replacement: '-', lower: true }) + } + let screenshotPrefix = version ? 'expected' : 'actual'; + let screenshotPath = path.join(__dirname, `${getScreenshotDir()}/${testName}-${screenshotPrefix}.png`); + await target.screenshot({ + path: screenshotPath, + fullPage + }); + + return {testName, screenshotPath}; +} + +async function runTestPage(browser, fileUrl, version) { + + const {keepWait, waitTimeout} = createWaitTimeout(3200); + const testResults = []; + let screenshotPromises = []; + + const page = await browser.newPage(); + page.setRequestInterception(true); + page.on('request', replaceEChartsVersion); + await page.evaluateOnNewDocument(seedrandomCode); + await page.evaluateOnNewDocument(runtimeCode); + + let descAutoCounter = 0; + + page.exposeFunction('puppeteerScreenshot', (desc, elementQuery) => { + keepWait(); + desc = desc || (descAutoCounter++).toString(); + let promise = takeScreenshot(page, elementQuery, fileUrl, desc, version).then((result) => { + if (!result) { + return; + } + const {testName, screenshotPath} = result; + testResults.push({testName, desc, screenshotPath}); + }); + screenshotPromises.push(promise); + + return promise; + }); + // page.on('console', msg => { + // console.log(msg.text()); + // }); + // page.on('pageerror', error => { + // console.error(error); + // }) + + let pageFinishPromise = waitPageForFinish(page); + + await page.goto(`${origin}/test/${fileUrl}`, { + waitUntil: 'networkidle2', + timeout: 10000 + }); + + // Do auto screenshot for every 1 second. + let count = 1; + let autoSnapshotInterval = setInterval(async () => { + let desc = `autogen-${count++}`; + let promise = takeScreenshot(page, '', fileUrl, desc, version) + .then(({testName, screenshotPath}) => { + testResults.push({testName, desc, screenshotPath}); + }); + screenshotPromises.push(promise); + }, 1000); + + + // Wait for puppeteerFinishTest() is called + // Or compare the whole page if nothing happened after 10 seconds. + await Promise.race([ + pageFinishPromise, + waitTimeout().then(() => { + // console.warn('Test timeout after 3 seconds.'); + }) + ]); + + clearInterval(autoSnapshotInterval); + + // Wait for screenshot finished. + await Promise.all(screenshotPromises); + + await page.close(); + + return testResults; +} + +async function runTest(browser, testOpt) { + const fileUrl = testOpt.fileUrl; + const expectedShots = await runTestPage(browser, fileUrl, '4.2.1'); + const actualShots = await runTestPage(browser, fileUrl); + + sortScreenshots(expectedShots); + sortScreenshots(actualShots); + + const results = []; + expectedShots.forEach(async (shot, idx) => { + let expected = shot; + let actual = actualShots[idx]; + let {diffRatio, diffPNG} = await compareScreenshot( + expected.screenshotPath, + actual.screenshotPath + ); + + + let diffPath = `${path.resolve(__dirname, getScreenshotDir())}/${shot.testName}-diff.png`; + diffPNG.pack().pipe(fs.createWriteStream(diffPath)); + + results.push({ + actual: getClientRelativePath(actual.screenshotPath), + expected: getClientRelativePath(expected.screenshotPath), + diff: getClientRelativePath(diffPath), + name: actual.testName, + diffRatio + }); + }); + + testOpt.results = results; + testOpt.status = 'finished'; +} + +function writeTestsToCache(tests) { + fs.writeFileSync(getCacheFilePath(), JSON.stringify(tests, null, 2), 'utf-8'); +} + +async function getTestsList() { + let tmpFolder = path.join(__dirname, 'tmp'); + fse.ensureDirSync(tmpFolder); + try { + let cachedStr = fs.readFileSync(getCacheFilePath(), 'utf-8'); + let tests = JSON.parse(cachedStr); + return tests; + } + catch(e) { + let files = await util.promisify(glob)('**.html', { cwd: path.resolve(__dirname, '../') }); + let tests = files.filter(fileUrl => { + return blacklist.includes(fileUrl); + }).map(fileUrl => { + return { + fileUrl, + name: getTestName(fileUrl), + status: 'pending', + results: [] + }; + }); + return tests; + } +} + +async function start() { + await prepareEChartsVersion('4.2.1'); // Expected version. + await prepareEChartsVersion(); // Version to test + + fse.ensureDirSync(path.join(__dirname, getScreenshotDir())); + // Start a static server for puppeteer open the html test cases. + let {broadcast, io} = serve(); + + open(`${origin}/test/runTest/client/index.html`); + + const browser = await puppeteer.launch({ /* headless: false */ }); + + const tests = await getTestsList(); + + broadcast({tests}); + + io.on('connect', socket => { + broadcast({tests}); + }); + + for (let testOpt of tests) { + if (testOpt.status === 'finished') { + continue; + } + console.log(`Running test ${testOpt.fileUrl}`) + await runTest(browser, testOpt); + broadcast({tests}); + writeTestsToCache(tests); + } + +} + +start().catch(e => { + console.log('Error during test'); + console.log(e); +}) \ No newline at end of file diff --git a/test/runTest/client/client.css b/test/runTest/client/client.css new file mode 100644 index 0000000000..22ce528f3c --- /dev/null +++ b/test/runTest/client/client.css @@ -0,0 +1,26 @@ +#main { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; +} + +* { + font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; +} + +.menu-link { + display: block; + text-decoration: none; + font-size: 18px; +} + +.test-screenshots { + margin-top: 50px; +} + +.test-screenshots img { + /* height: 200px; */ + width: 100%; +} \ No newline at end of file diff --git a/test/runTest/client/client.js b/test/runTest/client/client.js new file mode 100644 index 0000000000..5bc96b64f3 --- /dev/null +++ b/test/runTest/client/client.js @@ -0,0 +1,35 @@ +const socket = io(); +socket.on('connect', () => { + console.log('Connected'); + + const app = new Vue({ + el: '#app', + data: { + tests: [], + selectedTestName: '' + }, + computed: { + selectedTest() { + let selectedTest = this.tests.find(item => item.name === this.selectedTestName); + if (!selectedTest) { + selectedTest = this.tests[0]; + } + return selectedTest; + } + } + }); + app.$el.style.display = 'block'; + + socket.on('broadcast', msg => { + app.tests = msg.tests; + }); + + function updateTestHash() { + let testName = window.location.hash.slice(1); + app.selectedTestName = testName; + } + + updateTestHash(); + window.addEventListener('hashchange', updateTestHash); +}); + diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html new file mode 100644 index 0000000000..8bfdf3b09d --- /dev/null +++ b/test/runTest/client/index.html @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/runTest/compareScreenshot.js b/test/runTest/compareScreenshot.js new file mode 100644 index 0000000000..339ab566de --- /dev/null +++ b/test/runTest/compareScreenshot.js @@ -0,0 +1,41 @@ +const PNG = require('pngjs').PNG; +const pixelmatch = require('pixelmatch'); +const fs = require('fs'); + +function readPNG(path) { + return new Promise(resolve => { + fs.createReadStream(path) + .pipe(new PNG()) + .on('parsed', function () { + resolve({ + data: this.data, + width: this.width, + height: this.height + }); + }); + }); +} + +module.exports = function (expectedShotPath, actualShotPath, threshold = 0.1) { + return Promise.all([ + readPNG(expectedShotPath), + readPNG(actualShotPath) + ]).then(([expectedImg, actualImg]) => { + let width = expectedImg.width; + let height = expectedImg.height; + if ( + (width !== actualImg.width) + || (height !== actualImg.height) + ) { + throw new Error('Image size not match'); + } + const diffPNG = new PNG({width, height}); + let diffPixelsCount = pixelmatch(expectedImg.data, actualImg.data, diffPNG.data, width, height, {threshold}); + let totalPixelsCount = width * height; + + return { + diffRatio: diffPixelsCount / totalPixelsCount, + diffPNG + }; + }); +}; \ No newline at end of file diff --git a/test/runTest/runtime.js b/test/runTest/runtime.js new file mode 100644 index 0000000000..1a17c6a0ee --- /dev/null +++ b/test/runTest/runtime.js @@ -0,0 +1,71 @@ +(function (global) { + if (global.autorun) { + return; + } + + var autorun = {}; + var inPuppeteer = typeof puppeteerScreenshot !== 'undefined'; + + var NativeDate = window.Date; + + var fixedTimestamp = 1566458693300; + var actualTimestamp = NativeDate.now(); + + function MockDate(params) { + if (!params) { + var elapsedTime = NativeDate.now() - actualTimestamp; + return new NativeDate(fixedTimestamp + elapsedTime); + } + else { + return new NativeDate(params); + } + } + MockDate.prototype = new Date(); + + autorun.createScreenshotTest = function (desc, elementQuery, waitTime) { + + } + + /** + * Take screenshot immediately. + * @param {string} desc + * @param {string} [elementQuery] If only screenshot specifed element. Will do full page screenshot if it's not give. + */ + autorun.compareScreenshot = function (desc, elementQuery) { + if (!inPuppeteer) { + return Promise.resolve(); + } + + return puppeteerScreenshot(desc, elementQuery); + }; + + autorun.shouldBe = function (expected, actual) { + + }; + + /** + * Finish the test. + */ + autorun.finish = function () { + if (!inPuppeteer) { + return Promise.resolve(); + } + return puppeteerFinishTest(); + }; + + + if (inPuppeteer) { + let myRandom = new Math.seedrandom('echarts-test'); + // Fixed random generator + Math.random = function () { + var val = myRandom(); + return val; + }; + + // Fixed date + window.Date = MockDate; + } + + global.autorun = autorun; + +})(window); \ No newline at end of file diff --git a/test/runTest/serve.js b/test/runTest/serve.js new file mode 100644 index 0000000000..42f3ffa253 --- /dev/null +++ b/test/runTest/serve.js @@ -0,0 +1,29 @@ +const handler = require('serve-handler'); +const http = require('http'); +const port = 8866; +const origin = `http://localhost:${port}`; + +function serve() { + const server = http.createServer((request, response) => { + return handler(request, response, { + cleanUrls: false, + // Root folder of echarts + public: __dirname + '/../../' + }); + }); + + server.listen(port, () => { + console.log(`Server started. ${origin}`); + }); + + + const io = require('socket.io')(server); + return { + broadcast(data) { + io.emit('broadcast', data); + }, + io + } +} + +module.exports = {serve, origin}; \ No newline at end of file From b6c6719628da5158d88ffaf5dfee0c49e3085815 Mon Sep 17 00:00:00 2001 From: pissang Date: Thu, 29 Aug 2019 00:16:36 +0800 Subject: [PATCH 032/127] doc: Update CONTRIBUTING doc for test section --- .github/CONTRIBUTING.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6e8ca44d08..68a7145636 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -77,7 +77,15 @@ Then, open the test cases under `~/workspace/echarts/test` in Web browser. You c ![Chrome inspect](../asset/contributing-inspect.png) -### 4. Make a pull request +### 4. Run test + +```bash +node test/runTest/cli.js +``` + +It will run all the test cases under `~/workspace/echarts/test` automatically to compare with the previous version. You can use this to check if your code bring some breaking change. + +### 5. Make a pull request Fork ECharts project into your own project. Checkout a branch from master branch named `fix-xxxx`, where xxxx is the issue id related. If there's no related issue, you need to create one in most cases to describe what's wrong or what new feature is required. From ea440f6b2584ad60e528f29627e5122d92ce6e7f Mon Sep 17 00:00:00 2001 From: pissang Date: Thu, 29 Aug 2019 20:33:55 +0800 Subject: [PATCH 033/127] test: Improve visual regression test UI --- test/runTest/blacklist.js | 4 +- test/runTest/cli.js | 59 ++++++++++++------ test/runTest/client/client.css | 107 +++++++++++++++++++++++++++++++-- test/runTest/client/client.js | 102 ++++++++++++++++++++++++++++--- test/runTest/client/index.html | 62 +++++++++++++++---- 5 files changed, 287 insertions(+), 47 deletions(-) diff --git a/test/runTest/blacklist.js b/test/runTest/blacklist.js index e0596078c2..77cdd23fa9 100644 --- a/test/runTest/blacklist.js +++ b/test/runTest/blacklist.js @@ -1,4 +1,4 @@ module.exports = [ -'-cases.html', -'geo-random-stream.html' + '-cases.html', + 'geo-random-stream.html' ]; \ No newline at end of file diff --git a/test/runTest/cli.js b/test/runTest/cli.js index b560072b21..69d318869d 100644 --- a/test/runTest/cli.js +++ b/test/runTest/cli.js @@ -140,7 +140,6 @@ async function takeScreenshot(page, elementQuery, fileUrl, desc, version) { } async function runTestPage(browser, fileUrl, version) { - const {keepWait, waitTimeout} = createWaitTimeout(3200); const testResults = []; let screenshotPromises = []; @@ -176,10 +175,16 @@ async function runTestPage(browser, fileUrl, version) { let pageFinishPromise = waitPageForFinish(page); - await page.goto(`${origin}/test/${fileUrl}`, { - waitUntil: 'networkidle2', - timeout: 10000 - }); + try { + await page.goto(`${origin}/test/${fileUrl}`, { + waitUntil: 'networkidle2', + timeout: 10000 + }); + } + catch(e) { + // TODO Timeout Error + console.error(e); + } // Do auto screenshot for every 1 second. let count = 1; @@ -213,6 +218,7 @@ async function runTestPage(browser, fileUrl, version) { } async function runTest(browser, testOpt) { + testOpt.status === 'running'; const fileUrl = testOpt.fileUrl; const expectedShots = await runTestPage(browser, fileUrl, '4.2.1'); const actualShots = await runTestPage(browser, fileUrl); @@ -238,6 +244,7 @@ async function runTest(browser, testOpt) { expected: getClientRelativePath(expected.screenshotPath), diff: getClientRelativePath(diffPath), name: actual.testName, + desc: actual.desc, diffRatio }); }); @@ -292,21 +299,37 @@ async function start() { io.on('connect', socket => { broadcast({tests}); + // TODO Stop previous? + socket.on('run', async testsNameList => { + console.log(testsNameList); + + const pendingTests = tests.filter(testOpt => { + return testsNameList.includes(testOpt.name); + }); + + for (let testOpt of pendingTests) { + // Reset all tests results + testOpt.status = 'pending'; + testOpt.results = []; + } + + broadcast({tests}); + + try { + for (let testOpt of pendingTests) { + await runTest(browser, testOpt); + broadcast({tests}); + writeTestsToCache(tests); + } + } + catch(e) { + console.log(e); + } + }); }); - for (let testOpt of tests) { - if (testOpt.status === 'finished') { - continue; - } - console.log(`Running test ${testOpt.fileUrl}`) - await runTest(browser, testOpt); - broadcast({tests}); - writeTestsToCache(tests); - } + // runTests(browser, tests, tests); } -start().catch(e => { - console.log('Error during test'); - console.log(e); -}) \ No newline at end of file +start() \ No newline at end of file diff --git a/test/runTest/client/client.css b/test/runTest/client/client.css index 22ce528f3c..62c1ca33a1 100644 --- a/test/runTest/client/client.css +++ b/test/runTest/client/client.css @@ -10,17 +10,112 @@ font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; } -.menu-link { - display: block; +.header { + background-color: #293c55; + box-shadow: 0 0 20px rgba(0, 0, 0, 0.2); + position: relative; + z-index: 10; +} + +.header h1 { + color: #fff; + line-height: 50px; + margin: 0; + font-weight: 200; + font-size: 20px; +} + +#logo>* { + display: inline-block; + vertical-align: middle; +} + +#logo img { + height: 30px; + margin-right: 20px; +} + +.nav-toolbar { + padding: 10px 10px; + background: #162436; + box-shadow: inset 0 0 5px black; +} +.nav-toolbar .controls { + margin-top: 10px; +} + +.test-list { + overflow-x: hidden; + background: #293c55; + margin: 0; + padding: 0; +} +.test-list li { + list-style: none; + padding-left: 10px; + cursor: pointer; + color: #f3f3f3; +} +.test-list li a.menu-link { + display: inline-block; text-decoration: none; - font-size: 18px; + font-size: 14px; + line-height: 40px; + color: #f3f3f3; + margin-left: 3px; + cursor: pointer; } -.test-screenshots { - margin-top: 50px; +.test-list li.active { + background: #e43c59; +} +.test-list li:hover { + background: #162436; +} +.test-list li>* { + vertical-align: middle; + display: inline-block } -.test-screenshots img { +.test-list .el-progress__text { + font-size: 12px!important; +} + +.test-result { + margin-top: 80px; + padding: 0 20px; +} + +.test-result img { /* height: 200px; */ width: 100%; +} +.test-result h4 { + font-size: 30px; + font-weight: 200; + margin-left: -20px; +} + + +::-webkit-scrollbar { + height:8px; + width:8px; + transition:all 0.3s ease-in-out; + border-radius:2px; + background: transparent; +} + +::-webkit-scrollbar-button { + display:none; +} + +::-webkit-scrollbar-thumb { + width:8px; + min-height:15px; + background:rgba(50, 50, 50, 0.6) !important; + transition:all 0.3s ease-in-out;border-radius:2px; +} + +::-webkit-scrollbar-thumb:hover { + background:rgba(0, 0, 0, 0.5) !important; } \ No newline at end of file diff --git a/test/runTest/client/client.js b/test/runTest/client/client.js index 5bc96b64f3..716fdadde6 100644 --- a/test/runTest/client/client.js +++ b/test/runTest/client/client.js @@ -1,32 +1,114 @@ const socket = io(); + +function processTestsData(tests) { + tests.forEach(test => { + let passed = 0; + test.results.forEach(result => { + // Threshold? + if (result.diffRatio < 0.001) { + passed++; + } + }); + test.percentage = passed === 0 ? 0 : Math.round(passed / test.results.length * 100); + if (test.percentage === 100) { + test.summary = 'success'; + } + else if (test.percentage < 50) { + test.summary = 'exception'; + } + else { + test.summary = 'warning' + } + test.selected = false; + }); + return tests; +} + socket.on('connect', () => { console.log('Connected'); - const app = new Vue({ el: '#app', data: { - tests: [], - selectedTestName: '' + fullTests: [], + currentTestName: '', + sortBy: 'name', + searchString: '', + running: false, + + allSelected: false }, computed: { - selectedTest() { - let selectedTest = this.tests.find(item => item.name === this.selectedTestName); - if (!selectedTest) { - selectedTest = this.tests[0]; + tests() { + let sortFunc = this.sortBy === 'name' + ? (a, b) => a.name.localeCompare(b.name) + : (a, b) => a.percentage - b.percentage; + + if (!this.searchString) { + return this.fullTests.sort(sortFunc); + } + + return this.fullTests.filter(test => { + return test.name.match(this.searchString); + }).sort(sortFunc); + }, + + currentTest() { + let currentTest = this.fullTests.find(item => item.name === this.currentTestName); + if (!currentTest) { + currentTest = this.fullTests[0]; + } + return currentTest; + }, + + isSelectAllIndeterminate() { + if (!this.tests.length) { + return true; + } + return this.tests.some(test => { + return test.selected !== this.tests[0].selected; + }); + } + }, + methods: { + goto(url) { + window.location.hash = '#' + url; + }, + toggleSort() { + this.sortBy = this.sortBy === 'name' ? 'percentage' : 'name'; + }, + handleSelectAllChange(val) { + // Only select filtered tests. + this.tests.forEach(test => { + test.selected = val; + }); + this.isSelectAllIndeterminate = false; + }, + runSelectedTests() { + this.running = true; + const tests = this.fullTests.filter(test => { + return test.selected; + }).map(test => { + return test.name + }); + if (tests.length > 0) { + socket.emit('run', tests); } - return selectedTest; + }, + stopTests() { + this.running = false; + socket.emit('stop'); } } }); app.$el.style.display = 'block'; socket.on('broadcast', msg => { - app.tests = msg.tests; + app.fullTests = processTestsData(msg.tests); }); function updateTestHash() { let testName = window.location.hash.slice(1); - app.selectedTestName = testName; + app.currentTestName = testName; } updateTestHash(); diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html index 8bfdf3b09d..e9797ecc2e 100644 --- a/test/runTest/client/index.html +++ b/test/runTest/client/index.html @@ -8,22 +8,58 @@

--> - - - - @@ -92,6 +94,48 @@

{{result.desc || result.name}}

+
+ + + + +
{{error}}
+
+ + + +
{{error}}
+
+
+
+ +
+ + + + +
{{log}}
+
+ + + +
{{log}}
+
+
+
+
@@ -99,6 +143,9 @@

{{result.desc || result.name}}

+ + + @@ -111,6 +158,7 @@

{{result.desc || result.name}}

+ \ No newline at end of file diff --git a/test/runTest/config.js b/test/runTest/config.js new file mode 100644 index 0000000000..723496506b --- /dev/null +++ b/test/runTest/config.js @@ -0,0 +1,4 @@ +module.exports = { + port: 8866, + origin: 'http://localhost:8866' +}; \ No newline at end of file diff --git a/test/runTest/runtime.js b/test/runTest/runtime.js deleted file mode 100644 index 1a17c6a0ee..0000000000 --- a/test/runTest/runtime.js +++ /dev/null @@ -1,71 +0,0 @@ -(function (global) { - if (global.autorun) { - return; - } - - var autorun = {}; - var inPuppeteer = typeof puppeteerScreenshot !== 'undefined'; - - var NativeDate = window.Date; - - var fixedTimestamp = 1566458693300; - var actualTimestamp = NativeDate.now(); - - function MockDate(params) { - if (!params) { - var elapsedTime = NativeDate.now() - actualTimestamp; - return new NativeDate(fixedTimestamp + elapsedTime); - } - else { - return new NativeDate(params); - } - } - MockDate.prototype = new Date(); - - autorun.createScreenshotTest = function (desc, elementQuery, waitTime) { - - } - - /** - * Take screenshot immediately. - * @param {string} desc - * @param {string} [elementQuery] If only screenshot specifed element. Will do full page screenshot if it's not give. - */ - autorun.compareScreenshot = function (desc, elementQuery) { - if (!inPuppeteer) { - return Promise.resolve(); - } - - return puppeteerScreenshot(desc, elementQuery); - }; - - autorun.shouldBe = function (expected, actual) { - - }; - - /** - * Finish the test. - */ - autorun.finish = function () { - if (!inPuppeteer) { - return Promise.resolve(); - } - return puppeteerFinishTest(); - }; - - - if (inPuppeteer) { - let myRandom = new Math.seedrandom('echarts-test'); - // Fixed random generator - Math.random = function () { - var val = myRandom(); - return val; - }; - - // Fixed date - window.Date = MockDate; - } - - global.autorun = autorun; - -})(window); \ No newline at end of file diff --git a/test/runTest/runtime/main.js b/test/runTest/runtime/main.js new file mode 100644 index 0000000000..d98016dd2f --- /dev/null +++ b/test/runTest/runtime/main.js @@ -0,0 +1,54 @@ +import seedrandom from 'seedrandom'; +import lolex from 'lolex'; + +const NativeDate = window.Date; + +const fixedTimestamp = 1566458693300; +// const actualTimestamp = NativeDate.now(); +// function MockDate(params) { +// if (!params) { +// const elapsedTime = NativeDate.now() - actualTimestamp; +// return new NativeDate(fixedTimestamp + elapsedTime); +// } +// else { +// return new NativeDate(params); +// } +// } +// MockDate.prototype = new Date(); + +export function createScreenshotTest (desc, elementQuery, waitTime) { + +} + +/** + * Take screenshot immediately. + * @param {string} desc + * @param {string} [elementQuery] If only screenshot specifed element. Will do full page screenshot if it's not give. + */ +export function compareScreenshot (desc, elementQuery) { + return puppeteerScreenshot(desc, elementQuery); +}; + +/** + * Finish the test. + */ +export function finish() { + return puppeteerFinishTest(); +}; + + +let myRandom = new seedrandom('echarts-test'); +// Fixed random generator +Math.random = function () { + const val = myRandom(); + return val; +}; + +// Fixed date +// window.Date = MockDate; + +lolex.install({ + shouldAdvanceTime: true, + advanceTimeDelta: 50, + now: fixedTimestamp +}); diff --git a/test/runTest/runtime/shim.js b/test/runTest/runtime/shim.js new file mode 100644 index 0000000000..d0febb410a --- /dev/null +++ b/test/runTest/runtime/shim.js @@ -0,0 +1,9 @@ +(function () { + if (typeof autorun !== 'undefined') { + return; + } + var autorun = {}; + autorun.createScreenshotTest = function () {}; + autorun.compareScreenshot = function () {}; + autorun.finish = function () {}; +})(); \ No newline at end of file diff --git a/test/runTest/serve.js b/test/runTest/serve.js deleted file mode 100644 index 1baade6ef8..0000000000 --- a/test/runTest/serve.js +++ /dev/null @@ -1,26 +0,0 @@ -const handler = require('serve-handler'); -const http = require('http'); -const port = 8866; -const origin = `http://localhost:${port}`; - -function serve() { - const server = http.createServer((request, response) => { - return handler(request, response, { - cleanUrls: false, - // Root folder of echarts - public: __dirname + '/../../' - }); - }); - - server.listen(port, () => { - console.log(`Server started. ${origin}`); - }); - - - const io = require('socket.io')(server); - return { - io - } -} - -module.exports = {serve, origin}; \ No newline at end of file diff --git a/test/runTest/server.js b/test/runTest/server.js new file mode 100644 index 0000000000..a35c51e253 --- /dev/null +++ b/test/runTest/server.js @@ -0,0 +1,113 @@ +const handler = require('serve-handler'); +const http = require('http'); +const rollup = require('rollup'); +const resolve = require('rollup-plugin-node-resolve'); +const commonjs = require('rollup-plugin-commonjs'); +const path = require('path'); +const open = require('open'); +const fse = require('fs-extra'); +const {fork} = require('child_process'); +const {port, origin} = require('./config'); +const {getTestsList, prepareTestsList, saveTestsList, mergeTestsResults} = require('./store'); +const {prepareEChartsVersion} = require('./util'); + +function serve() { + const server = http.createServer((request, response) => { + return handler(request, response, { + cleanUrls: false, + // Root folder of echarts + public: __dirname + '/../../' + }); + }); + + server.listen(port, () => { + console.log(`Server started. ${origin}`); + }); + + + const io = require('socket.io')(server); + return { + io + }; +}; + +async function buildRuntimeCode() { + const bundle = await rollup.rollup({ + input: path.join(__dirname, 'runtime/main.js'), + plugins: [ + resolve(), + commonjs() + ] + }); + const output = await bundle.generate({ + format: 'iife', + name: 'autorun' + }); + + return output.code; +} + + +function startTests(testsNameList, socket) { + console.log(testsNameList.join(',')); + + return new Promise(resolve => { + const pendingTests = getTestsList().filter(testOpt => { + return testsNameList.includes(testOpt.name); + }); + + for (let testOpt of pendingTests) { + // Reset all tests results + testOpt.status = 'pending'; + testOpt.results = []; + } + + socket.emit('update', {tests: getTestsList()}); + + let childProcess = fork(path.join(__dirname, 'cli.js'), [ + pendingTests.map(testOpt => testOpt.fileUrl) + ]); + // Finished one test + childProcess.on('message', testOpt => { + mergeTestsResults([testOpt]); + // Merge tests. + socket.emit('update', {tests: getTestsList(), running: true}); + saveTestsList(); + }); + // Finished all + childProcess.on('exit', () => { + resolve(); + }); + }); +} + +async function start() { + await prepareEChartsVersion('4.2.1'); // Expected version. + await prepareEChartsVersion(); // Version to test + + let runtimeCode = await buildRuntimeCode(); + // seedrandom use crypto as external module. Set it to null to avoid not defined error. + // TODO + runtimeCode = 'window.crypto = null\n' + runtimeCode; + fse.outputFileSync(path.join(__dirname, 'tmp/testRuntime.js'), runtimeCode, 'utf-8'); + + // Start a static server for puppeteer open the html test cases. + let {io} = serve(); + + io.on('connect', async socket => { + await prepareTestsList(); + + socket.emit('update', {tests: getTestsList()}); + // TODO Stop previous? + socket.on('run', async testsNameList => { + await startTests(testsNameList, socket); + socket.emit('finish'); + }); + }); + + console.log(`Dashboard: ${origin}/test/runTest/client/index.html`); + // open(`${origin}/test/runTest/client/index.html`); + +} + +start(); \ No newline at end of file diff --git a/test/runTest/store.js b/test/runTest/store.js new file mode 100644 index 0000000000..dbfaae9b79 --- /dev/null +++ b/test/runTest/store.js @@ -0,0 +1,72 @@ +const path = require('path'); +const fse = require('fs-extra'); +const fs = require('fs'); +const glob = require('glob'); +const {getTestName} = require('./util'); +const util = require('util'); +const blacklist = require('./blacklist'); + +let _tests = []; +let _testsMap = {}; + +function getCacheFilePath() { + return path.join(__dirname, 'tmp/__cache__.json');; +} + +module.exports.getTestsList = function () { + return _tests; +}; + +module.exports.getTestByFileUrl = function (url) { + return _testsMap[url]; +}; + +module.exports.prepareTestsList = async function () { + let tmpFolder = path.join(__dirname, 'tmp'); + fse.ensureDirSync(tmpFolder); + _tests = []; + _testsMap = {}; + try { + let cachedStr = fs.readFileSync(getCacheFilePath(), 'utf-8'); + _tests = JSON.parse(cachedStr); + _tests.forEach(test => { + _testsMap[test.fileUrl] = test; + }); + } + catch(e) { + _tests = []; + } + // Find if there is new html file + let files = await util.promisify(glob)('**.html', { cwd: path.resolve(__dirname, '../') }); + files.forEach(fileUrl => { + if (blacklist.includes(fileUrl)) { + return; + } + if (_testsMap[fileUrl]) { + return; + } + + let test = { + fileUrl, + name: getTestName(fileUrl), + status: 'pending', + results: [] + }; + + _tests.push(test); + _testsMap[fileUrl] = test; + }); + return _tests; +}; + +module.exports.saveTestsList = function () { + fse.outputFileSync(getCacheFilePath(), JSON.stringify(_tests, null, 2), 'utf-8'); +}; + +module.exports.mergeTestsResults = function (testsResults) { + testsResults.forEach(testResult => { + if (_testsMap[testResult.fileUrl]) { + Object.assign(_testsMap[testResult.fileUrl], testResult); + } + }); +}; \ No newline at end of file diff --git a/test/runTest/util.js b/test/runTest/util.js new file mode 100644 index 0000000000..cc721235f6 --- /dev/null +++ b/test/runTest/util.js @@ -0,0 +1,45 @@ +const path = require('path'); +const fse = require('fs-extra'); +const https = require('https'); +const fs = require('fs'); + +module.exports.getTestName = function(fileUrl) { + return path.basename(fileUrl, '.html'); +}; + + +function getVersionDir(version) { + version = version || 'developing'; + return `tmp/__version__/${version}`; +}; +module.exports.getVersionDir = getVersionDir; + + +module.exports.prepareEChartsVersion = function (version) { + let versionFolder = path.join(__dirname, getVersionDir(version)); + fse.ensureDirSync(versionFolder); + if (!version) { + // Developing version, make sure it's new build + return fse.copy( + path.join(__dirname, '../../dist/echarts.js'), + `${versionFolder}/echarts.js` + ); + } + return new Promise(resolve => { + if (!fs.existsSync(`${versionFolder}/echarts.js`)) { + const file = fs.createWriteStream(`${versionFolder}/echarts.js`); + + console.log('Downloading echarts4.2.1 from ', `https://cdn.jsdelivr.net/npm/echarts@${version}/dist/echarts.js`); + https.get(`https://cdn.jsdelivr.net/npm/echarts@${version}/dist/echarts.js`, response => { + response.pipe(file); + + file.on('finish', () => { + resolve(); + }); + }); + } + else { + resolve(); + } + }); +} \ No newline at end of file From 727b8fc0cb121ad61798d0e68664f4926460af82 Mon Sep 17 00:00:00 2001 From: pissang Date: Sun, 1 Sep 2019 17:22:52 +0800 Subject: [PATCH 040/127] style: move eslint config file to src folder. --- .../.eslintrc.yaml | 0 src/.eslintrc.yaml | 188 ++++++++++++++++++ 2 files changed, 188 insertions(+) rename .eslintrc.yaml => extension-src/.eslintrc.yaml (100%) create mode 100644 src/.eslintrc.yaml diff --git a/.eslintrc.yaml b/extension-src/.eslintrc.yaml similarity index 100% rename from .eslintrc.yaml rename to extension-src/.eslintrc.yaml diff --git a/src/.eslintrc.yaml b/src/.eslintrc.yaml new file mode 100644 index 0000000000..3c0e1c30a4 --- /dev/null +++ b/src/.eslintrc.yaml @@ -0,0 +1,188 @@ +parserOptions: + ecmaVersion: 3 + sourceType: "module" +env: + browser: true + node: true + es6: false +globals: + jQuery: true + Promise: true +rules: + no-console: + - 2 + - + allow: + - "warn" + - "error" + no-constant-condition: 0 + comma-dangle: 2 + no-debugger: 2 + no-dupe-keys: 2 + no-empty-character-class: 2 + no-ex-assign: 2 + no-extra-boolean-cast: 0 + no-func-assign: 2 + no-inner-declarations: 2 + no-invalid-regexp: 2 + no-negated-in-lhs: 2 + no-obj-calls: 2 + no-sparse-arrays: 2 + no-unreachable: 2 + use-isnan: 2 + valid-typeof: 2 + block-scoped-var: 0 + curly: + - 2 + - "all" + eqeqeq: + - 2 + - "allow-null" + guard-for-in: 2 + no-else-return: 0 + no-labels: + - 2 + - + allowLoop: true + no-eval: 2 + no-extend-native: 2 + no-extra-bind: 0 + no-implied-eval: 2 + no-iterator: 2 + no-irregular-whitespace: 2 + no-lone-blocks: 2 + no-loop-func: 2 + no-multi-str: 2 + no-native-reassign: 2 + no-new-wrappers: 2 + no-octal: 2 + no-octal-escape: 2 + no-proto: 2 + no-redeclare: 0 + no-self-compare: 2 + no-unneeded-ternary: 2 + no-with: 2 + radix: 2 + wrap-iife: + - 2 + - "any" + no-delete-var: 2 + no-dupe-args: 2 + no-duplicate-case: 2 + no-label-var: 2 + no-shadow-restricted-names: 2 + no-undef: 2 + no-undef-init: 2 + no-unused-vars: + - 2 + - + vars: "local" + args: "none" + no-use-before-define: 0 + brace-style: + - 2 + - "stroustrup" + - {} + comma-spacing: + - 2 + - + before: false + after: true + comma-style: + - 2 + - "last" + new-parens: 2 + no-array-constructor: 2 + no-multi-spaces: + - 2 + - + ignoreEOLComments: true + exceptions: + Property: true + no-new-object: 2 + no-spaced-func: 2 + no-trailing-spaces: 2 + no-extra-parens: + - 2 + - "functions" + no-mixed-spaces-and-tabs: 2 + one-var: + - 2 + - "never" + operator-linebreak: + - 2 + - "before" + - + overrides: + "=": "after" + quotes: + - 2 + - "single" + semi: + - 2 + - "always" + semi-spacing: 2 + keyword-spacing: 2 + key-spacing: + - 2 + - + beforeColon: false + afterColon: true + space-before-function-paren: + - 2 + - + anonymous: "always" + named: "never" + space-before-blocks: + - 2 + - "always" + computed-property-spacing: + - 2 + - "never" + space-in-parens: + - 2 + - "never" + space-unary-ops: 2 + spaced-comment: 0 + + max-nested-callbacks: + - 1 + - 5 + max-depth: + - 1 + - 6 + max-len: + - 2 + - 120 + - 4 + - + ignoreUrls: true + ignoreComments: true + max-params: + - 1 + - 15 + + space-infix-ops: 2 + dot-notation: + - 2 + - + allowKeywords: true + allowPattern: "^catch$" + + arrow-spacing: 2 + constructor-super: 2 + no-confusing-arrow: + - 2 + - + allowParens: true + no-class-assign: 2 + no-const-assign: 2 + no-dupe-class-members: 2 + no-this-before-super: 0 + no-var: 0 + no-duplicate-imports: 2 + prefer-rest-params: 0 + unicode-bom: 2 + max-statements-per-line: 2 + + no-useless-constructor: 0 \ No newline at end of file From 65f58a39fa5215b0267d6340eb62ca3be47abb41 Mon Sep 17 00:00:00 2001 From: pissang Date: Sun, 1 Sep 2019 18:44:52 +0800 Subject: [PATCH 041/127] test: Fix some logic issue of controlling test in dashboard. --- test/runTest/cli.js | 25 +++++++++++---- test/runTest/client/client.css | 5 +++ test/runTest/client/client.js | 19 +++++++----- test/runTest/client/index.html | 8 ++++- test/runTest/runtime/main.js | 37 +++++++++++----------- test/runTest/server.js | 57 +++++++++++++++++----------------- test/runTest/store.js | 8 ++++- test/runTest/util.js | 23 +++++++++++++- 8 files changed, 118 insertions(+), 64 deletions(-) diff --git a/test/runTest/cli.js b/test/runTest/cli.js index 60b70edb46..afcc8b507b 100644 --- a/test/runTest/cli.js +++ b/test/runTest/cli.js @@ -4,7 +4,7 @@ const fse = require('fs-extra'); const fs = require('fs'); const path = require('path'); const compareScreenshot = require('./compareScreenshot'); -const {getTestName, getVersionDir} = require('./util'); +const {getTestName, getVersionDir, buildRuntimeCode} = require('./util'); const {origin} = require('./config'); function getScreenshotDir() { @@ -63,7 +63,7 @@ function createWaitTimeout(maxTime) { }); } - return {keepWait, waitTimeout} + return {keepWait, waitTimeout}; } async function takeScreenshot(page, elementQuery, fileUrl, desc, version) { @@ -149,12 +149,14 @@ async function runTestPage(browser, fileUrl, version, runtimeCode) { // screenshotPromises.push(promise); // }, 100); + console.log('1111'); // Wait for puppeteerFinishTest() is called // Or compare the whole page if nothing happened after 10 seconds. await Promise.race([ pageFinishPromise, waitTimeout().then(() => { + console.log('2222'); // console.warn('Test timeout after 3 seconds.'); // Final shot. let desc = 'Final Shot'; @@ -179,6 +181,14 @@ async function runTestPage(browser, fileUrl, version, runtimeCode) { }; } +async function writePNG(diffPNG, diffPath) { + return new Promise(resolve => { + let writer = fs.createWriteStream(diffPath); + diffPNG.pack().pipe(writer); + writer.on('finish', () => {resolve();}); + }); +}; + async function runTest(browser, testOpt, runtimeCode) { testOpt.status === 'running'; const fileUrl = testOpt.fileUrl; @@ -199,7 +209,7 @@ async function runTest(browser, testOpt, runtimeCode) { ); let diffPath = `${path.resolve(__dirname, getScreenshotDir())}/${shot.testName}-diff.png`; - diffPNG.pack().pipe(fs.createWriteStream(diffPath)); + await writePNG(diffPNG, diffPath); screenshots.push({ actual: getClientRelativePath(actual.screenshotPath), @@ -221,9 +231,10 @@ async function runTest(browser, testOpt, runtimeCode) { } async function runTests(pendingTests) { - const browser = await puppeteer.launch({ headless: true }); + const browser = await puppeteer.launch({ headless: false }); // TODO Not hardcoded. - let runtimeCode = fs.readFileSync(path.join(__dirname, 'tmp/testRuntime.js'), 'utf-8'); + // let runtimeCode = fs.readFileSync(path.join(__dirname, 'tmp/testRuntime.js'), 'utf-8'); + let runtimeCode = await buildRuntimeCode(); try { for (let testOpt of pendingTests) { @@ -243,6 +254,8 @@ async function runTests(pendingTests) { catch(e) { console.log(e); } + + await browser.close(); } // Handling input arguments. @@ -252,6 +265,6 @@ runTests(testsFileUrlList.split(',').map(fileUrl => { fileUrl, name: getTestName(fileUrl), results: [], - status: 'pending' + status: 'unsettled' }; })); \ No newline at end of file diff --git a/test/runTest/client/client.css b/test/runTest/client/client.css index 4a160491d1..1d15d890cc 100644 --- a/test/runTest/client/client.css +++ b/test/runTest/client/client.css @@ -39,6 +39,10 @@ padding: 10px 10px; background: #162436; box-shadow: inset 0 0 5px black; + position: fixed; + top: 50px; + width: 280px; + z-index: 2; } .nav-toolbar .controls { margin-top: 10px; @@ -49,6 +53,7 @@ background: #293c55; margin: 0; padding: 0; + margin-top: 80px; } .test-list li { list-style: none; diff --git a/test/runTest/client/client.js b/test/runTest/client/client.js index 99b8b98d1f..0dc2607e0f 100644 --- a/test/runTest/client/client.js +++ b/test/runTest/client/client.js @@ -18,7 +18,7 @@ function processTestsData(tests, oldTestsData) { test.summary = 'exception'; } else { - test.summary = 'warning' + test.summary = 'warning'; } // Keep select status not change. @@ -55,10 +55,11 @@ socket.on('connect', () => { return a.name.localeCompare(b.name); } return a.percentage - b.percentage; - } + }; if (!this.searchString) { - return this.fullTests.sort(sortFunc); + // Not modify the original tests data. + return this.fullTests.slice().sort(sortFunc); } return this.fullTests.filter(test => { @@ -74,6 +75,10 @@ socket.on('connect', () => { return currentTest; }, + currentTestUrl() { + return window.location.origin + '/test/' + this.currentTest.fileUrl; + }, + isSelectAllIndeterminate: { get() { if (!this.tests.length) { @@ -123,7 +128,7 @@ socket.on('connect', () => { const tests = this.fullTests.filter(test => { return test.selected; }).map(test => { - return test.name + return test.name; }); if (tests.length > 0) { this.running = true; @@ -142,7 +147,7 @@ socket.on('connect', () => { socket.on('update', msg => { let hasFinishedTest = !!msg.tests.find(test => test.status === 'finished'); if (!hasFinishedTest && firstUpdate) { - app.$confirm("It seems you haven't run any test yet!
Do you want to start now?", 'Tip', { + app.$confirm('It seems you haven\'t run any test yet!
Do you want to start now?', 'Tip', { confirmButtonText: 'Yes', cancelButtonText: 'No', dangerouslyUseHTMLString: true, @@ -150,7 +155,7 @@ socket.on('connect', () => { }).then(value => { app.running = true; socket.emit('run', msg.tests.map(test => test.name)); - }).catch(() => {}) + }).catch(() => {}); } // TODO // app.running = !!msg.running; @@ -162,7 +167,7 @@ socket.on('connect', () => { app.$notify({ title: 'Test Complete', position: 'bottom-right' - }) + }); app.running = false; }); diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html index 72fd6adc94..ac3cc8abfa 100644 --- a/test/runTest/client/index.html +++ b/test/runTest/client/index.html @@ -25,7 +25,6 @@

Visual Regression Test

- Visual Regression Test

+ + +

{{result.desc || result.name}}

diff --git a/test/runTest/runtime/main.js b/test/runTest/runtime/main.js index d98016dd2f..df7cd2a993 100644 --- a/test/runTest/runtime/main.js +++ b/test/runTest/runtime/main.js @@ -4,17 +4,19 @@ import lolex from 'lolex'; const NativeDate = window.Date; const fixedTimestamp = 1566458693300; -// const actualTimestamp = NativeDate.now(); -// function MockDate(params) { -// if (!params) { -// const elapsedTime = NativeDate.now() - actualTimestamp; -// return new NativeDate(fixedTimestamp + elapsedTime); -// } -// else { -// return new NativeDate(params); -// } -// } -// MockDate.prototype = new Date(); +const actualTimestamp = NativeDate.now(); +function MockDate(params) { + if (!params) { + const elapsedTime = NativeDate.now() - actualTimestamp; + return new NativeDate(fixedTimestamp + elapsedTime); + } + else { + return new NativeDate(params); + } +} +MockDate.prototype = new Date(); +// Fixed date +window.Date = MockDate; export function createScreenshotTest (desc, elementQuery, waitTime) { @@ -44,11 +46,8 @@ Math.random = function () { return val; }; -// Fixed date -// window.Date = MockDate; - -lolex.install({ - shouldAdvanceTime: true, - advanceTimeDelta: 50, - now: fixedTimestamp -}); +// lolex.install({ +// shouldAdvanceTime: true, +// advanceTimeDelta: 200, +// now: fixedTimestamp +// }); diff --git a/test/runTest/server.js b/test/runTest/server.js index a35c51e253..f778a91ef2 100644 --- a/test/runTest/server.js +++ b/test/runTest/server.js @@ -1,15 +1,12 @@ const handler = require('serve-handler'); const http = require('http'); -const rollup = require('rollup'); -const resolve = require('rollup-plugin-node-resolve'); -const commonjs = require('rollup-plugin-commonjs'); const path = require('path'); const open = require('open'); const fse = require('fs-extra'); const {fork} = require('child_process'); const {port, origin} = require('./config'); const {getTestsList, prepareTestsList, saveTestsList, mergeTestsResults} = require('./store'); -const {prepareEChartsVersion} = require('./util'); +const {prepareEChartsVersion, buildRuntimeCode} = require('./util'); function serve() { const server = http.createServer((request, response) => { @@ -31,51 +28,53 @@ function serve() { }; }; -async function buildRuntimeCode() { - const bundle = await rollup.rollup({ - input: path.join(__dirname, 'runtime/main.js'), - plugins: [ - resolve(), - commonjs() - ] - }); - const output = await bundle.generate({ - format: 'iife', - name: 'autorun' - }); - - return output.code; +let testProcess; +let pendingTests; + +function stopRunningTests() { + if (testProcess) { + testProcess.kill(); + testProcess = null; + } + if (pendingTests) { + pendingTests.forEach(testOpt => { + if (testOpt.status === 'pending') { + testOpt.status = 'unsettled'; + } + }); + pendingTests = null; + } } - function startTests(testsNameList, socket) { console.log(testsNameList.join(',')); + stopRunningTests(); + return new Promise(resolve => { - const pendingTests = getTestsList().filter(testOpt => { + pendingTests = getTestsList().filter(testOpt => { return testsNameList.includes(testOpt.name); }); - - for (let testOpt of pendingTests) { + pendingTests.forEach(testOpt => { // Reset all tests results testOpt.status = 'pending'; testOpt.results = []; - } + }); socket.emit('update', {tests: getTestsList()}); - let childProcess = fork(path.join(__dirname, 'cli.js'), [ + testProcess = fork(path.join(__dirname, 'cli.js'), [ pendingTests.map(testOpt => testOpt.fileUrl) ]); // Finished one test - childProcess.on('message', testOpt => { + testProcess.on('message', testOpt => { mergeTestsResults([testOpt]); // Merge tests. socket.emit('update', {tests: getTestsList(), running: true}); saveTestsList(); }); // Finished all - childProcess.on('exit', () => { + testProcess.on('exit', () => { resolve(); }); }); @@ -86,9 +85,6 @@ async function start() { await prepareEChartsVersion(); // Version to test let runtimeCode = await buildRuntimeCode(); - // seedrandom use crypto as external module. Set it to null to avoid not defined error. - // TODO - runtimeCode = 'window.crypto = null\n' + runtimeCode; fse.outputFileSync(path.join(__dirname, 'tmp/testRuntime.js'), runtimeCode, 'utf-8'); // Start a static server for puppeteer open the html test cases. @@ -103,6 +99,9 @@ async function start() { await startTests(testsNameList, socket); socket.emit('finish'); }); + socket.on('stop', () => { + stopRunningTests(); + }); }); console.log(`Dashboard: ${origin}/test/runTest/client/index.html`); diff --git a/test/runTest/store.js b/test/runTest/store.js index dbfaae9b79..4cd4fc9324 100644 --- a/test/runTest/store.js +++ b/test/runTest/store.js @@ -30,6 +30,11 @@ module.exports.prepareTestsList = async function () { let cachedStr = fs.readFileSync(getCacheFilePath(), 'utf-8'); _tests = JSON.parse(cachedStr); _tests.forEach(test => { + // In somehow tests are stopped and leave the status pending. + // Set the status to unsettled again. + if (test.status === 'pending') { + test.status = 'unsettled'; + } _testsMap[test.fileUrl] = test; }); } @@ -49,7 +54,8 @@ module.exports.prepareTestsList = async function () { let test = { fileUrl, name: getTestName(fileUrl), - status: 'pending', + // Default status should be unkown + // status: 'pending', results: [] }; diff --git a/test/runTest/util.js b/test/runTest/util.js index cc721235f6..95cab471dc 100644 --- a/test/runTest/util.js +++ b/test/runTest/util.js @@ -2,6 +2,9 @@ const path = require('path'); const fse = require('fs-extra'); const https = require('https'); const fs = require('fs'); +const rollup = require('rollup'); +const resolve = require('rollup-plugin-node-resolve'); +const commonjs = require('rollup-plugin-commonjs'); module.exports.getTestName = function(fileUrl) { return path.basename(fileUrl, '.html'); @@ -42,4 +45,22 @@ module.exports.prepareEChartsVersion = function (version) { resolve(); } }); -} \ No newline at end of file +}; + +module.exports.buildRuntimeCode = async function () { + const bundle = await rollup.rollup({ + input: path.join(__dirname, 'runtime/main.js'), + plugins: [ + resolve(), + commonjs() + ] + }); + const output = await bundle.generate({ + format: 'iife', + name: 'autorun' + }); + + // seedrandom use crypto as external module. Set it to null to avoid not defined error. + // TODO + return 'window.crypto = null\n' + output.code; +}; \ No newline at end of file From 63be6bf8c90c213132245ddeec8b2ca018991968 Mon Sep 17 00:00:00 2001 From: "Leon.Y" Date: Sun, 1 Sep 2019 19:25:05 -0700 Subject: [PATCH 042/127] doc: fix npm link instructions in contribution.md; fix #11138 --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 2da8f95564..db9fe870db 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -69,7 +69,7 @@ Sometimes, in order to fix an issue within echarts, changes have to be made insi cd ~/workspace/zrender npm link cd ~/workspace/echarts -npm link +npm link zrender ``` With this, you can see that `~/workspace/echarts/node_modules/zrender` is a link to `~/workspace/zrender`. From 1ccd41b2051a643e62d35f391ed7ff42b2f98643 Mon Sep 17 00:00:00 2001 From: pissang Date: Mon, 2 Sep 2019 14:58:22 +0800 Subject: [PATCH 043/127] docs(contribution): Add release milestone discussion --- .github/CONTRIBUTING.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index db9fe870db..96e432efe4 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -14,6 +14,16 @@ Please read the [documentation](http://echarts.apache.org/option.html) carefully Any questions in the form of *how can I use echarts to* or *how to use echarts x feature to* belong in [Stack Overflow](http://stackoverflow.com), issues with questions like that in the issue tracker will be closed. +## Release Milestone Discussion + +We will start the discussion about the bugs to fix and features of each release in the [mailing list](https://echarts.apache.org/en/maillist.html). You may subscribe our [mailing list](https://echarts.apache.org/en/maillist.html) to give your valuable advice in the milestone dicussion. + +About our release plan, we will release a mior version at the end of every month. Here is some detail. + +1. Assume our current stable release is 4.3.0. We will start the discussion of milestone of the release two ahead, which is 4.5.0 at the beginning of each month. At this time we should also kickoff the developing of the next release, which is 4.4.0. +2. Finish 4.4.0 developing at about 22th of this month and start the testing. And the 4.5.0 milestone discussion is frozen and published on the [GitHub](https://github.com/apache/incubator-echarts/milestone/14) +3. Vote in the mailing list for the 4.4.0 release at the end of this month. + ## Pull Requests ### Finding Easy Issues to Fix From 4a293207f6947be3414eaa383ca70066faf88241 Mon Sep 17 00:00:00 2001 From: pissang Date: Mon, 2 Sep 2019 22:15:10 +0800 Subject: [PATCH 044/127] test(autorun): Improve Dashboard UI --- test/runTest/cli.js | 9 +++++---- test/runTest/client/client.css | 28 +++++++++++++++++++++++++--- test/runTest/client/index.html | 14 ++++++-------- test/runTest/runtime/main.js | 32 ++++++++++++++++---------------- 4 files changed, 52 insertions(+), 31 deletions(-) diff --git a/test/runTest/cli.js b/test/runTest/cli.js index afcc8b507b..e44ebe7698 100644 --- a/test/runTest/cli.js +++ b/test/runTest/cli.js @@ -126,6 +126,10 @@ async function runTestPage(browser, fileUrl, version, runtimeCode) { let pageFinishPromise = waitPageForFinish(page); try { + await page.setViewport({ + width: 800, + height: 600 + }); await page.goto(`${origin}/test/${fileUrl}`, { waitUntil: 'networkidle2', // waitUntil: 'domcontentloaded', @@ -149,14 +153,11 @@ async function runTestPage(browser, fileUrl, version, runtimeCode) { // screenshotPromises.push(promise); // }, 100); - console.log('1111'); - // Wait for puppeteerFinishTest() is called // Or compare the whole page if nothing happened after 10 seconds. await Promise.race([ pageFinishPromise, waitTimeout().then(() => { - console.log('2222'); // console.warn('Test timeout after 3 seconds.'); // Final shot. let desc = 'Final Shot'; @@ -231,7 +232,7 @@ async function runTest(browser, testOpt, runtimeCode) { } async function runTests(pendingTests) { - const browser = await puppeteer.launch({ headless: false }); + const browser = await puppeteer.launch({ headless: true }); // TODO Not hardcoded. // let runtimeCode = fs.readFileSync(path.join(__dirname, 'tmp/testRuntime.js'), 'utf-8'); let runtimeCode = await buildRuntimeCode(); diff --git a/test/runTest/client/client.css b/test/runTest/client/client.css index 1d15d890cc..cfaad1af93 100644 --- a/test/runTest/client/client.css +++ b/test/runTest/client/client.css @@ -86,19 +86,41 @@ font-size: 12px!important; } -.test-result { +.test-result h3 { + font-size: 40px; + font-weight: 200; + padding: 0; + margin: 0; +} + +.test-result .title>* { + display: inline-block; + vertical-align: middle; +} +.test-result .title a { + margin-left: 10px; + font-size: 20px; + font-weight: 200; + text-decoration: none; +} +.test-result .title a:hover { + text-decoration: underline; +} + +.test-screenshots { margin-top: 80px; padding: 0 20px; } -.test-result img { +.test-screenshots img { /* height: 200px; */ width: 100%; } -.test-result h4 { +.test-screenshots h4 { font-size: 30px; font-weight: 200; margin-left: -20px; + color: #162436; } .test-errors, .test-logs { diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html index ac3cc8abfa..c45b49d501 100644 --- a/test/runTest/client/index.html +++ b/test/runTest/client/index.html @@ -33,7 +33,7 @@

Visual Regression Test

--> - +
    @@ -60,15 +60,13 @@

    Visual Regression Test

-
- -
-

- {{currentTest.name}} -

+
+
+

{{currentTest.name}}

+ Open Demo
-
+

{{result.desc || result.name}}

diff --git a/test/runTest/runtime/main.js b/test/runTest/runtime/main.js index df7cd2a993..2726a06f86 100644 --- a/test/runTest/runtime/main.js +++ b/test/runTest/runtime/main.js @@ -1,22 +1,22 @@ import seedrandom from 'seedrandom'; import lolex from 'lolex'; -const NativeDate = window.Date; - -const fixedTimestamp = 1566458693300; -const actualTimestamp = NativeDate.now(); -function MockDate(params) { - if (!params) { - const elapsedTime = NativeDate.now() - actualTimestamp; - return new NativeDate(fixedTimestamp + elapsedTime); - } - else { - return new NativeDate(params); - } -} -MockDate.prototype = new Date(); -// Fixed date -window.Date = MockDate; +// const NativeDate = window.Date; + +// const fixedTimestamp = 1566458693300; +// const actualTimestamp = NativeDate.now(); +// function MockDate(params) { +// if (!params) { +// const elapsedTime = NativeDate.now() - actualTimestamp; +// return new NativeDate(fixedTimestamp + elapsedTime); +// } +// else { +// return new NativeDate(params); +// } +// } +// MockDate.prototype = new Date(); +// // Fixed date +// window.Date = MockDate; export function createScreenshotTest (desc, elementQuery, waitTime) { From a48808751c66331a5e291ae9be06fb9526a4628f Mon Sep 17 00:00:00 2001 From: pissang Date: Tue, 3 Sep 2019 14:22:15 +0800 Subject: [PATCH 045/127] test: Remove puppeteer from devDependencies --- package.json | 1 - test/runTest/server.js | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 5568c99601..da86940aa0 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "open": "^6.4.0", "pixelmatch": "^5.0.2", "pngjs": "^3.4.0", - "puppeteer": "^1.19.0", "rollup": "0.50.0", "rollup-plugin-commonjs": "^8.4.1", "rollup-plugin-node-resolve": "3.0.0", diff --git a/test/runTest/server.js b/test/runTest/server.js index f778a91ef2..529a96c402 100644 --- a/test/runTest/server.js +++ b/test/runTest/server.js @@ -80,7 +80,22 @@ function startTests(testsNameList, socket) { }); } +function checkPuppeteer() { + try { + return require('puppeteer'); + } + catch (e) { + return null; + } +} + async function start() { + if (!checkPuppeteer()) { + // TODO Check version. + console.error(`Can't find puppeteer, use 'npm install puppeteer' to install`); + return; + } + await prepareEChartsVersion('4.2.1'); // Expected version. await prepareEChartsVersion(); // Version to test From 360b93cbf47f70cabcdba040840680ac8c218436 Mon Sep 17 00:00:00 2001 From: pissang Date: Tue, 3 Sep 2019 14:57:38 +0800 Subject: [PATCH 046/127] Update package-lock.json --- package-lock.json | 1504 ++++++++++++++++++++-------------------- package.json | 3 +- test/runTest/server.js | 2 +- 3 files changed, 768 insertions(+), 741 deletions(-) diff --git a/package-lock.json b/package-lock.json index bbc437b94a..0c8483c761 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,16 @@ { "name": "echarts", - "version": "4.2.1-rc.2", + "version": "4.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.0.0-beta.31", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.31.tgz", - "integrity": "sha512-yd7CkUughvHQoEahQqcMdrZw6o/6PwUxiRkfZuVDVHCDe77mysD/suoNyk5mK6phTnRW1kyIbPHyCJgxw++LXg==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", "dev": true, "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^3.0.0" + "@babel/highlight": "7.5.0" } }, "@babel/core": { @@ -21,77 +19,68 @@ "integrity": "sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.3.4", - "@babel/helpers": "^7.2.0", - "@babel/parser": "^7.3.4", - "@babel/template": "^7.2.2", - "@babel/traverse": "^7.3.4", - "@babel/types": "^7.3.4", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.11", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" + "@babel/code-frame": "7.5.5", + "@babel/generator": "7.5.5", + "@babel/helpers": "7.5.5", + "@babel/parser": "7.5.5", + "@babel/template": "7.4.4", + "@babel/traverse": "7.5.5", + "@babel/types": "7.5.5", + "convert-source-map": "1.6.0", + "debug": "4.1.1", + "json5": "2.1.0", + "lodash": "4.17.15", + "resolve": "1.12.0", + "semver": "5.7.1", + "source-map": "0.5.7" }, "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, "@babel/template": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", - "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.2.2", - "@babel/types": "^7.2.2" + "@babel/code-frame": "7.5.5", + "@babel/parser": "7.5.5", + "@babel/types": "7.5.5" } }, "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } }, "@babel/generator": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", - "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.5.5.tgz", + "integrity": "sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ==", "dev": true, "requires": { - "@babel/types": "^7.3.4", - "jsesc": "^2.5.1", - "lodash": "^4.17.11", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "@babel/types": "7.5.5", + "jsesc": "2.5.2", + "lodash": "4.17.15", + "source-map": "0.5.7", + "trim-right": "1.0.1" }, "dependencies": { "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } @@ -102,40 +91,31 @@ "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-get-function-arity": "7.0.0", + "@babel/template": "7.4.4", + "@babel/types": "7.5.5" }, "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, "@babel/template": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", - "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.2.2", - "@babel/types": "^7.2.2" + "@babel/code-frame": "7.5.5", + "@babel/parser": "7.5.5", + "@babel/types": "7.5.5" } }, "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } @@ -146,18 +126,18 @@ "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.5.5" }, "dependencies": { "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } @@ -169,7 +149,7 @@ "dev": true, "requires": { "@babel/types": "7.0.0-beta.31", - "lodash": "^4.2.0" + "lodash": "4.17.15" } }, "@babel/helper-module-transforms": { @@ -182,7 +162,7 @@ "@babel/helper-simple-access": "7.0.0-beta.31", "@babel/template": "7.0.0-beta.31", "@babel/types": "7.0.0-beta.31", - "lodash": "^4.2.0" + "lodash": "4.17.15" } }, "@babel/helper-simple-access": { @@ -193,98 +173,81 @@ "requires": { "@babel/template": "7.0.0-beta.31", "@babel/types": "7.0.0-beta.31", - "lodash": "^4.2.0" + "lodash": "4.17.15" } }, "@babel/helper-split-export-declaration": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", - "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.5.5" }, "dependencies": { "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } }, "@babel/helpers": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.3.1.tgz", - "integrity": "sha512-Q82R3jKsVpUV99mgX50gOPCWwco9Ec5Iln/8Vyu4osNIOQgSrd9RFrQeUvmvddFNoLwMyOUWU+5ckioEKpDoGA==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.5.5.tgz", + "integrity": "sha512-nRq2BUhxZFnfEn/ciJuhklHvFOqjJUD5wpx+1bxUF2axL9C+v4DE/dmp5sT2dKnpOs4orZWzpAZqlCy8QqE/7g==", "dev": true, "requires": { - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.5", - "@babel/types": "^7.3.0" + "@babel/template": "7.4.4", + "@babel/traverse": "7.5.5", + "@babel/types": "7.5.5" }, "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, "@babel/template": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", - "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.2.2", - "@babel/types": "^7.2.2" + "@babel/code-frame": "7.5.5", + "@babel/parser": "7.5.5", + "@babel/types": "7.5.5" } }, "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } }, "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", "dev": true, "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - } + "chalk": "2.4.2", + "esutils": "2.0.3", + "js-tokens": "4.0.0" } }, "@babel/parser": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", - "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz", + "integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==", "dev": true }, "@babel/template": { @@ -296,44 +259,54 @@ "@babel/code-frame": "7.0.0-beta.31", "@babel/types": "7.0.0-beta.31", "babylon": "7.0.0-beta.31", - "lodash": "^4.2.0" - } - }, - "@babel/traverse": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", - "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.3.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.3.4", - "@babel/types": "^7.3.4", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.11" + "lodash": "4.17.15" }, "dependencies": { "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "version": "7.0.0-beta.31", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.31.tgz", + "integrity": "sha512-yd7CkUughvHQoEahQqcMdrZw6o/6PwUxiRkfZuVDVHCDe77mysD/suoNyk5mK6phTnRW1kyIbPHyCJgxw++LXg==", "dev": true, "requires": { - "@babel/highlight": "^7.0.0" + "chalk": "2.4.2", + "esutils": "2.0.3", + "js-tokens": "3.0.2" } }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + } + } + }, + "@babel/traverse": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.5.5.tgz", + "integrity": "sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ==", + "dev": true, + "requires": { + "@babel/code-frame": "7.5.5", + "@babel/generator": "7.5.5", + "@babel/helper-function-name": "7.1.0", + "@babel/helper-split-export-declaration": "7.4.4", + "@babel/parser": "7.5.5", + "@babel/types": "7.5.5", + "debug": "4.1.1", + "globals": "11.12.0", + "lodash": "4.17.15" + }, + "dependencies": { "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } @@ -344,11 +317,50 @@ "integrity": "sha512-exAHB+NeFGxkfQ5dSUD03xl3zYGneeSk2Mw2ldTt/nTvYxuDiuSp3DlxgUBgzbdTFG4fbwPk0WtKWOoTXCmNGg==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.2.0", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "2.1.24", + "negotiator": "0.6.2" + }, + "dependencies": { + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + } + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", @@ -362,9 +374,15 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.3" } }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, "assert": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", @@ -374,25 +392,64 @@ "util": "0.10.3" } }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, "babylon": { "version": "7.0.0-beta.31", "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.31.tgz", "integrity": "sha512-6lm2mV3S51yEnKmQQNnswoABL1U1H1KHoCCVwdwI3hvIv+W7ya4ki7Aw4o4KxtUHjNKkK5WpZb22rrMMOcJXJQ==", "dev": true }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -419,15 +476,27 @@ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" } }, "color-convert": { @@ -451,21 +520,51 @@ "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", "dev": true }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, "convert-source-map": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", "dev": true, "requires": { - "safe-buffer": "~5.1.1" + "safe-buffer": "5.1.2" } }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, "coordtransform": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/coordtransform/-/coordtransform-2.0.2.tgz", @@ -478,7 +577,7 @@ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "deep-is": { @@ -487,6 +586,86 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "engine.io": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.3.2.tgz", + "integrity": "sha512-AsaA9KG7cWPXWHp5FvHdDWY3AMWeZ8x+2pUVLcn71qE5AtAzgGbxuclOytygskw8XGmiQafTmnI9Bix3uihu2w==", + "dev": true, + "requires": { + "accepts": "1.3.7", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "3.1.0", + "engine.io-parser": "2.1.3", + "ws": "6.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "engine.io-client": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.3.2.tgz", + "integrity": "sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "3.1.0", + "engine.io-parser": "2.1.3", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "6.1.4", + "xmlhttprequest-ssl": "1.5.5", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "1.0.3" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -499,11 +678,11 @@ "integrity": "sha1-skaq6CnOc9WeLFVyc1nt0cEwqBs=", "dev": true, "requires": { - "esprima": "^2.7.1", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.2.0" + "esprima": "2.7.2", + "estraverse": "1.9.3", + "esutils": "2.0.3", + "optionator": "0.8.2", + "source-map": "0.2.0" }, "dependencies": { "estraverse": { @@ -519,7 +698,7 @@ "dev": true, "optional": true, "requires": { - "amdefine": ">=0.0.4" + "amdefine": "1.0.1" } } } @@ -536,10 +715,16 @@ "integrity": "sha1-9srKcokzqFDvkGYdDheYK6RxEaI=", "dev": true }, + "estree-walker": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.2.tgz", + "integrity": "sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig==", + "dev": true + }, "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "fast-levenshtein": { @@ -548,17 +733,26 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, "fs-extra": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" + "graceful-fs": "4.2.2", + "jsonfile": "2.4.0", + "klaw": "1.3.1", + "path-is-absolute": "1.0.1", + "rimraf": "2.7.1" } }, "fs.realpath": { @@ -573,23 +767,38 @@ "integrity": "sha1-OyCjV//89GuzhK7W+K6aZH/basQ=", "dev": true, "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "inflight": "1.0.6", + "inherits": "2.0.1", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", "dev": true }, "has-flag": { @@ -598,14 +807,20 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -620,10 +835,16 @@ "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", "dev": true }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "jsesc": { @@ -638,7 +859,7 @@ "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", "dev": true, "requires": { - "minimist": "^1.2.0" + "minimist": "1.2.0" } }, "jsonfile": { @@ -647,7 +868,7 @@ "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { - "graceful-fs": "^4.1.6" + "graceful-fs": "4.2.2" } }, "klaw": { @@ -656,7 +877,7 @@ "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", "dev": true, "requires": { - "graceful-fs": "^4.1.9" + "graceful-fs": "4.2.2" } }, "levn": { @@ -665,23 +886,53 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "1.1.2", + "type-check": "0.3.2" } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "lolex": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", + "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", + "dev": true + }, + "magic-string": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", + "dev": true, + "requires": { + "vlq": "0.2.3" + } + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", "dev": true }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "requires": { + "mime-db": "1.33.0" + } + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -691,9 +942,21 @@ "dev": true }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", "dev": true }, "once": { @@ -702,7 +965,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "optionator": { @@ -711,12 +974,30 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "1.0.2" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "1.0.2" } }, "path-is-absolute": { @@ -725,48 +1006,87 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==", + "dev": true + }, + "pixelmatch": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.0.2.tgz", + "integrity": "sha512-b65UpTI40rGFY8QwN6IYuCbpmwAOL6M8d6voX4F3zR99UmDqh7r2QWLxoeHOazBRgEmDUdqNVESDREqFxQS7rQ==", + "dev": true, + "requires": { + "pngjs": "3.4.0" + } + }, + "pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "dev": true + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, "resolve": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", - "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", "dev": true, "requires": { - "path-parse": "^1.0.6" + "path-parse": "1.0.6" } }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "requires": { - "glob": "^7.1.3" + "glob": "7.1.4" }, "dependencies": { "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.1", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } } } @@ -777,16 +1097,29 @@ "integrity": "sha512-7RqCBQ9iwsOBPkjYgoIaeUij606mSkDMExP0NT7QDI3bqkHYQHrQ83uoNIXwPcQm/vP2VbsUz3kiyZZ1qPlLTQ==", "dev": true }, + "rollup-plugin-commonjs": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-8.4.1.tgz", + "integrity": "sha512-mg+WuD+jlwoo8bJtW3Mvx7Tz6TsIdMsdhuvCnDMoyjh0oxsVgsjB/N0X984RJCWwc5IIiqNVJhXeeITcc73++A==", + "dev": true, + "requires": { + "acorn": "5.7.3", + "estree-walker": "0.5.2", + "magic-string": "0.22.5", + "resolve": "1.12.0", + "rollup-pluginutils": "2.8.1" + } + }, "rollup-plugin-node-resolve": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-3.0.0.tgz", "integrity": "sha1-i4l8TDAw1QASd7BRSyXSygloPuA=", "dev": true, "requires": { - "browser-resolve": "^1.11.0", - "builtin-modules": "^1.1.0", - "is-module": "^1.0.0", - "resolve": "^1.1.6" + "browser-resolve": "1.11.3", + "builtin-modules": "1.1.1", + "is-module": "1.0.0", + "resolve": "1.12.0" } }, "rollup-plugin-uglify": { @@ -795,7 +1128,24 @@ "integrity": "sha1-Z7N60e/a+9g69MNrQMGJ7khmyWk=", "dev": true, "requires": { - "uglify-js": "^3.0.9" + "uglify-js": "3.6.0" + } + }, + "rollup-pluginutils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz", + "integrity": "sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg==", + "dev": true, + "requires": { + "estree-walker": "0.6.1" + }, + "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + } } }, "safe-buffer": { @@ -804,12 +1154,127 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "seedrandom": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.3.tgz", + "integrity": "sha512-PJLhhxIMjlMJaiIRtqiVW061EZn3cS+waZkbFe7eCa2R3g88HbNdWmw4NTFG1w5unxd0GeNaUUxZJP7gPAzSDQ==", + "dev": true + }, "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, + "serve-handler": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.1.tgz", + "integrity": "sha512-LQPvxGia2TYqyMkHKH4jW9jx6jlQUMcWz6gJavZ3+4vsnB+SaWbYTncb9YsK5YBR6SlvyumREZJAzLw8VaFAUQ==", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.0.4", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + } + }, + "slugify": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.4.tgz", + "integrity": "sha512-KP0ZYk5hJNBS8/eIjGkFDCzGQIoZ1mnfQRYS5WM3273z+fxGWXeN0fkwf2ebEweydv9tioZIHGZKoF21U07/nw==", + "dev": true + }, + "socket.io": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.2.0.tgz", + "integrity": "sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w==", + "dev": true, + "requires": { + "debug": "4.1.1", + "engine.io": "3.3.2", + "has-binary2": "1.0.3", + "socket.io-adapter": "1.1.1", + "socket.io-client": "2.2.0", + "socket.io-parser": "3.3.0" + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", + "dev": true + }, + "socket.io-client": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.2.0.tgz", + "integrity": "sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "3.1.0", + "engine.io-client": "3.3.2", + "has-binary2": "1.0.3", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "3.3.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "socket.io-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", + "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -822,9 +1287,15 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -843,23 +1314,23 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "~1.1.2" + "prelude-ls": "1.1.2" } }, "uglify-js": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", "dev": true, "requires": { - "commander": "~2.17.1", - "source-map": "~0.6.1" + "commander": "2.20.0", + "source-map": "0.6.1" }, "dependencies": { "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true }, "source-map": { @@ -879,6 +1350,12 @@ "inherits": "2.0.1" } }, + "vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", + "dev": true + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -891,480 +1368,31 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "ws": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", + "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", + "dev": true, + "requires": { + "async-limiter": "1.0.1" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, "zrender": { "version": "4.0.7", - "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "bundled": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/core": { - "version": "7.3.4", - "bundled": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.3.4", - "@babel/helpers": "^7.2.0", - "@babel/parser": "^7.3.4", - "@babel/template": "^7.2.2", - "@babel/traverse": "^7.3.4", - "@babel/types": "^7.3.4", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.11", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - }, - "source-map": { - "version": "0.5.7", - "bundled": true - } - } - }, - "@babel/generator": { - "version": "7.3.4", - "bundled": true, - "requires": { - "@babel/types": "^7.3.4", - "jsesc": "^2.5.1", - "lodash": "^4.17.11", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - }, - "source-map": { - "version": "0.5.7", - "bundled": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.1.0", - "bundled": true, - "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "bundled": true, - "requires": { - "@babel/types": "^7.0.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-module-imports": { - "version": "7.0.0", - "bundled": true, - "requires": { - "@babel/types": "^7.0.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-module-transforms": { - "version": "7.2.2", - "bundled": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/template": "^7.2.2", - "@babel/types": "^7.2.2", - "lodash": "^4.17.10" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-simple-access": { - "version": "7.1.0", - "bundled": true, - "requires": { - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.0.0", - "bundled": true, - "requires": { - "@babel/types": "^7.0.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helpers": { - "version": "7.3.1", - "bundled": true, - "requires": { - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.5", - "@babel/types": "^7.3.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/highlight": { - "version": "7.0.0", - "bundled": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.3.4", - "bundled": true - }, - "@babel/template": { - "version": "7.2.2", - "bundled": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.2.2", - "@babel/types": "^7.2.2" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/traverse": { - "version": "7.3.4", - "bundled": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.3.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.3.4", - "@babel/types": "^7.3.4", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.11" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/types": { - "version": "7.0.0-beta.31", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.2.0", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "bundled": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "assert": { - "version": "1.4.1", - "bundled": true, - "requires": { - "util": "0.10.3" - } - }, - "chalk": { - "version": "2.4.2", - "bundled": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "bundled": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "bundled": true - }, - "commander": { - "version": "2.11.0", - "bundled": true - }, - "convert-source-map": { - "version": "1.6.0", - "bundled": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "requires": { - "ms": "^2.1.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true - }, - "esutils": { - "version": "2.0.2", - "bundled": true - }, - "fs-extra": { - "version": "4.0.2", - "bundled": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "globals": { - "version": "11.11.0", - "bundled": true - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "has-flag": { - "version": "3.0.0", - "bundled": true - }, - "inherits": { - "version": "2.0.1", - "bundled": true - }, - "is-equal": { - "version": "0.1.0", - "bundled": true - }, - "js-tokens": { - "version": "4.0.0", - "bundled": true - }, - "jsdiff": { - "version": "1.1.1", - "bundled": true, - "requires": { - "is-equal": "~0.1.0" - } - }, - "jsesc": { - "version": "2.5.2", - "bundled": true - }, - "json5": { - "version": "2.1.0", - "bundled": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "jsonfile": { - "version": "4.0.0", - "bundled": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "lodash": { - "version": "4.17.11", - "bundled": true - }, - "minimist": { - "version": "1.2.0", - "bundled": true - }, - "ms": { - "version": "2.1.1", - "bundled": true - }, - "path-parse": { - "version": "1.0.6", - "bundled": true - }, - "resolve": { - "version": "1.10.0", - "bundled": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "rollup": { - "version": "0.50.0", - "bundled": true - }, - "rollup-plugin-uglify": { - "version": "2.0.1", - "bundled": true, - "requires": { - "uglify-js": "^3.0.9" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true - }, - "semver": { - "version": "5.6.0", - "bundled": true - }, - "source-map": { - "version": "0.6.1", - "bundled": true - }, - "supports-color": { - "version": "5.5.0", - "bundled": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "to-fast-properties": { - "version": "2.0.0", - "bundled": true - }, - "trim-right": { - "version": "1.0.1", - "bundled": true - }, - "uglify-js": { - "version": "3.1.6", - "bundled": true, - "requires": { - "commander": "~2.11.0", - "source-map": "~0.6.1" - } - }, - "universalify": { - "version": "0.1.1", - "bundled": true - }, - "util": { - "version": "0.10.3", - "bundled": true, - "requires": { - "inherits": "2.0.1" - } - } - } + "resolved": "https://registry.npmjs.org/zrender/-/zrender-4.0.7.tgz", + "integrity": "sha512-TNloHe0ums6zxbHfnaCryM61J4IWDajZwNq6dHk9vfWhhysO/OeFvvR0drBs/nbXha2YxSzfQj2FiCd6RVBe+Q==" } } } diff --git a/package.json b/package.json index da86940aa0..16fde6c97d 100644 --- a/package.json +++ b/package.json @@ -32,10 +32,9 @@ "escodegen": "1.8.0", "esprima": "2.7.2", "estraverse": "4.1.1", - "fs-extra": "^0.26.7", + "fs-extra": "0.26.7", "glob": "7.0.0", "lolex": "^4.2.0", - "open": "^6.4.0", "pixelmatch": "^5.0.2", "pngjs": "^3.4.0", "rollup": "0.50.0", diff --git a/test/runTest/server.js b/test/runTest/server.js index 529a96c402..8900f948a2 100644 --- a/test/runTest/server.js +++ b/test/runTest/server.js @@ -1,7 +1,7 @@ const handler = require('serve-handler'); const http = require('http'); const path = require('path'); -const open = require('open'); +// const open = require('open'); const fse = require('fs-extra'); const {fork} = require('child_process'); const {port, origin} = require('./config'); From 8b31c574ba544bb6d913089e7d1891da376a7720 Mon Sep 17 00:00:00 2001 From: pissang Date: Tue, 3 Sep 2019 16:46:55 +0800 Subject: [PATCH 047/127] style: fix code style. --- test/runTest/blacklist.js | 2 +- test/runTest/compareScreenshot.js | 2 +- test/runTest/runtime/main.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/runTest/blacklist.js b/test/runTest/blacklist.js index 77cdd23fa9..9e9ad44d3f 100644 --- a/test/runTest/blacklist.js +++ b/test/runTest/blacklist.js @@ -1,4 +1,4 @@ module.exports = [ '-cases.html', 'geo-random-stream.html' -]; \ No newline at end of file +]; diff --git a/test/runTest/compareScreenshot.js b/test/runTest/compareScreenshot.js index 339ab566de..8fd36c8236 100644 --- a/test/runTest/compareScreenshot.js +++ b/test/runTest/compareScreenshot.js @@ -38,4 +38,4 @@ module.exports = function (expectedShotPath, actualShotPath, threshold = 0.1) { diffPNG }; }); -}; \ No newline at end of file +}; diff --git a/test/runTest/runtime/main.js b/test/runTest/runtime/main.js index 2726a06f86..35da2f164e 100644 --- a/test/runTest/runtime/main.js +++ b/test/runTest/runtime/main.js @@ -18,9 +18,9 @@ import lolex from 'lolex'; // // Fixed date // window.Date = MockDate; -export function createScreenshotTest (desc, elementQuery, waitTime) { +// export function createScreenshotTest (desc, elementQuery, waitTime) { -} +// }; /** * Take screenshot immediately. From 4af177937bac7e6e6429b17e27d9e5ab520d5e28 Mon Sep 17 00:00:00 2001 From: Yi Shen Date: Tue, 3 Sep 2019 16:51:27 +0800 Subject: [PATCH 048/127] Add tool to run all tests automatically. (#11154) * test: Run the tests automatically for visual regression test. * doc: Update CONTRIBUTING doc for test section * test: Improve visual regression test UI * test: Add tests select and run control in dashboard * test: Use child process to run test. Add logs in dashboard * test: Fix some logic issue of controlling test in dashboard. * test(autorun): Improve Dashboard UI * test: Remove puppeteer from devDependencies * Update package-lock.json * style: fix code style. --- .github/CONTRIBUTING.md | 10 +- package-lock.json | 1504 +++++++++++++++-------------- package.json | 11 +- test/runTest/blacklist.js | 4 + test/runTest/cli.js | 271 ++++++ test/runTest/client/client.css | 163 ++++ test/runTest/client/client.js | 182 ++++ test/runTest/client/index.html | 168 ++++ test/runTest/compareScreenshot.js | 41 + test/runTest/config.js | 4 + test/runTest/runtime/main.js | 53 + test/runTest/runtime/shim.js | 9 + test/runTest/server.js | 127 +++ test/runTest/store.js | 78 ++ test/runTest/util.js | 66 ++ 15 files changed, 1951 insertions(+), 740 deletions(-) create mode 100644 test/runTest/blacklist.js create mode 100644 test/runTest/cli.js create mode 100644 test/runTest/client/client.css create mode 100644 test/runTest/client/client.js create mode 100644 test/runTest/client/index.html create mode 100644 test/runTest/compareScreenshot.js create mode 100644 test/runTest/config.js create mode 100644 test/runTest/runtime/main.js create mode 100644 test/runTest/runtime/shim.js create mode 100644 test/runTest/server.js create mode 100644 test/runTest/store.js create mode 100644 test/runTest/util.js diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 96e432efe4..4577ff4d80 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -103,7 +103,15 @@ Then, open the test cases under `~/workspace/echarts/test` in Web browser. You c ![Chrome inspect](../asset/contributing-inspect.png) -### 4. Make a pull request +### 4. Run test + +```bash +node test/runTest/cli.js +``` + +It will run all the test cases under `~/workspace/echarts/test` automatically to compare with the previous version. You can use this to check if your code bring some breaking change. + +### 5. Make a pull request Fork ECharts project into your own project. Checkout a branch from master branch named `fix-xxxx`, where xxxx is the issue id related. If there's no related issue, you need to create one in most cases to describe what's wrong or what new feature is required. diff --git a/package-lock.json b/package-lock.json index bbc437b94a..0c8483c761 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,16 @@ { "name": "echarts", - "version": "4.2.1-rc.2", + "version": "4.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.0.0-beta.31", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.31.tgz", - "integrity": "sha512-yd7CkUughvHQoEahQqcMdrZw6o/6PwUxiRkfZuVDVHCDe77mysD/suoNyk5mK6phTnRW1kyIbPHyCJgxw++LXg==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", "dev": true, "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^3.0.0" + "@babel/highlight": "7.5.0" } }, "@babel/core": { @@ -21,77 +19,68 @@ "integrity": "sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.3.4", - "@babel/helpers": "^7.2.0", - "@babel/parser": "^7.3.4", - "@babel/template": "^7.2.2", - "@babel/traverse": "^7.3.4", - "@babel/types": "^7.3.4", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.11", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" + "@babel/code-frame": "7.5.5", + "@babel/generator": "7.5.5", + "@babel/helpers": "7.5.5", + "@babel/parser": "7.5.5", + "@babel/template": "7.4.4", + "@babel/traverse": "7.5.5", + "@babel/types": "7.5.5", + "convert-source-map": "1.6.0", + "debug": "4.1.1", + "json5": "2.1.0", + "lodash": "4.17.15", + "resolve": "1.12.0", + "semver": "5.7.1", + "source-map": "0.5.7" }, "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, "@babel/template": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", - "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.2.2", - "@babel/types": "^7.2.2" + "@babel/code-frame": "7.5.5", + "@babel/parser": "7.5.5", + "@babel/types": "7.5.5" } }, "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } }, "@babel/generator": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", - "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.5.5.tgz", + "integrity": "sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ==", "dev": true, "requires": { - "@babel/types": "^7.3.4", - "jsesc": "^2.5.1", - "lodash": "^4.17.11", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" + "@babel/types": "7.5.5", + "jsesc": "2.5.2", + "lodash": "4.17.15", + "source-map": "0.5.7", + "trim-right": "1.0.1" }, "dependencies": { "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } @@ -102,40 +91,31 @@ "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-get-function-arity": "7.0.0", + "@babel/template": "7.4.4", + "@babel/types": "7.5.5" }, "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, "@babel/template": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", - "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.2.2", - "@babel/types": "^7.2.2" + "@babel/code-frame": "7.5.5", + "@babel/parser": "7.5.5", + "@babel/types": "7.5.5" } }, "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } @@ -146,18 +126,18 @@ "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.5.5" }, "dependencies": { "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } @@ -169,7 +149,7 @@ "dev": true, "requires": { "@babel/types": "7.0.0-beta.31", - "lodash": "^4.2.0" + "lodash": "4.17.15" } }, "@babel/helper-module-transforms": { @@ -182,7 +162,7 @@ "@babel/helper-simple-access": "7.0.0-beta.31", "@babel/template": "7.0.0-beta.31", "@babel/types": "7.0.0-beta.31", - "lodash": "^4.2.0" + "lodash": "4.17.15" } }, "@babel/helper-simple-access": { @@ -193,98 +173,81 @@ "requires": { "@babel/template": "7.0.0-beta.31", "@babel/types": "7.0.0-beta.31", - "lodash": "^4.2.0" + "lodash": "4.17.15" } }, "@babel/helper-split-export-declaration": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", - "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "7.5.5" }, "dependencies": { "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } }, "@babel/helpers": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.3.1.tgz", - "integrity": "sha512-Q82R3jKsVpUV99mgX50gOPCWwco9Ec5Iln/8Vyu4osNIOQgSrd9RFrQeUvmvddFNoLwMyOUWU+5ckioEKpDoGA==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.5.5.tgz", + "integrity": "sha512-nRq2BUhxZFnfEn/ciJuhklHvFOqjJUD5wpx+1bxUF2axL9C+v4DE/dmp5sT2dKnpOs4orZWzpAZqlCy8QqE/7g==", "dev": true, "requires": { - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.5", - "@babel/types": "^7.3.0" + "@babel/template": "7.4.4", + "@babel/traverse": "7.5.5", + "@babel/types": "7.5.5" }, "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, "@babel/template": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", - "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.2.2", - "@babel/types": "^7.2.2" + "@babel/code-frame": "7.5.5", + "@babel/parser": "7.5.5", + "@babel/types": "7.5.5" } }, "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } }, "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", "dev": true, "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - } + "chalk": "2.4.2", + "esutils": "2.0.3", + "js-tokens": "4.0.0" } }, "@babel/parser": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", - "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz", + "integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==", "dev": true }, "@babel/template": { @@ -296,44 +259,54 @@ "@babel/code-frame": "7.0.0-beta.31", "@babel/types": "7.0.0-beta.31", "babylon": "7.0.0-beta.31", - "lodash": "^4.2.0" - } - }, - "@babel/traverse": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", - "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.3.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.3.4", - "@babel/types": "^7.3.4", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.11" + "lodash": "4.17.15" }, "dependencies": { "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "version": "7.0.0-beta.31", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.31.tgz", + "integrity": "sha512-yd7CkUughvHQoEahQqcMdrZw6o/6PwUxiRkfZuVDVHCDe77mysD/suoNyk5mK6phTnRW1kyIbPHyCJgxw++LXg==", "dev": true, "requires": { - "@babel/highlight": "^7.0.0" + "chalk": "2.4.2", + "esutils": "2.0.3", + "js-tokens": "3.0.2" } }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + } + } + }, + "@babel/traverse": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.5.5.tgz", + "integrity": "sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ==", + "dev": true, + "requires": { + "@babel/code-frame": "7.5.5", + "@babel/generator": "7.5.5", + "@babel/helper-function-name": "7.1.0", + "@babel/helper-split-export-declaration": "7.4.4", + "@babel/parser": "7.5.5", + "@babel/types": "7.5.5", + "debug": "4.1.1", + "globals": "11.12.0", + "lodash": "4.17.15" + }, + "dependencies": { "@babel/types": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", - "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } } } @@ -344,11 +317,50 @@ "integrity": "sha512-exAHB+NeFGxkfQ5dSUD03xl3zYGneeSk2Mw2ldTt/nTvYxuDiuSp3DlxgUBgzbdTFG4fbwPk0WtKWOoTXCmNGg==", "dev": true, "requires": { - "esutils": "^2.0.2", - "lodash": "^4.2.0", - "to-fast-properties": "^2.0.0" + "esutils": "2.0.3", + "lodash": "4.17.15", + "to-fast-properties": "2.0.0" } }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "2.1.24", + "negotiator": "0.6.2" + }, + "dependencies": { + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + } + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", @@ -362,9 +374,15 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.3" } }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, "assert": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", @@ -374,25 +392,64 @@ "util": "0.10.3" } }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, "babylon": { "version": "7.0.0-beta.31", "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.31.tgz", "integrity": "sha512-6lm2mV3S51yEnKmQQNnswoABL1U1H1KHoCCVwdwI3hvIv+W7ya4ki7Aw4o4KxtUHjNKkK5WpZb22rrMMOcJXJQ==", "dev": true }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.0", "concat-map": "0.0.1" } }, @@ -419,15 +476,27 @@ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" } }, "color-convert": { @@ -451,21 +520,51 @@ "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", "dev": true }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, "convert-source-map": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", "dev": true, "requires": { - "safe-buffer": "~5.1.1" + "safe-buffer": "5.1.2" } }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, "coordtransform": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/coordtransform/-/coordtransform-2.0.2.tgz", @@ -478,7 +577,7 @@ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "deep-is": { @@ -487,6 +586,86 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "engine.io": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.3.2.tgz", + "integrity": "sha512-AsaA9KG7cWPXWHp5FvHdDWY3AMWeZ8x+2pUVLcn71qE5AtAzgGbxuclOytygskw8XGmiQafTmnI9Bix3uihu2w==", + "dev": true, + "requires": { + "accepts": "1.3.7", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "3.1.0", + "engine.io-parser": "2.1.3", + "ws": "6.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "engine.io-client": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.3.2.tgz", + "integrity": "sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "3.1.0", + "engine.io-parser": "2.1.3", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "6.1.4", + "xmlhttprequest-ssl": "1.5.5", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "1.0.3" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -499,11 +678,11 @@ "integrity": "sha1-skaq6CnOc9WeLFVyc1nt0cEwqBs=", "dev": true, "requires": { - "esprima": "^2.7.1", - "estraverse": "^1.9.1", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.2.0" + "esprima": "2.7.2", + "estraverse": "1.9.3", + "esutils": "2.0.3", + "optionator": "0.8.2", + "source-map": "0.2.0" }, "dependencies": { "estraverse": { @@ -519,7 +698,7 @@ "dev": true, "optional": true, "requires": { - "amdefine": ">=0.0.4" + "amdefine": "1.0.1" } } } @@ -536,10 +715,16 @@ "integrity": "sha1-9srKcokzqFDvkGYdDheYK6RxEaI=", "dev": true }, + "estree-walker": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.2.tgz", + "integrity": "sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig==", + "dev": true + }, "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "fast-levenshtein": { @@ -548,17 +733,26 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-url-parser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", + "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, "fs-extra": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" + "graceful-fs": "4.2.2", + "jsonfile": "2.4.0", + "klaw": "1.3.1", + "path-is-absolute": "1.0.1", + "rimraf": "2.7.1" } }, "fs.realpath": { @@ -573,23 +767,38 @@ "integrity": "sha1-OyCjV//89GuzhK7W+K6aZH/basQ=", "dev": true, "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "inflight": "1.0.6", + "inherits": "2.0.1", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "globals": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", - "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", "dev": true }, "has-flag": { @@ -598,14 +807,20 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -620,10 +835,16 @@ "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", "dev": true }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "jsesc": { @@ -638,7 +859,7 @@ "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", "dev": true, "requires": { - "minimist": "^1.2.0" + "minimist": "1.2.0" } }, "jsonfile": { @@ -647,7 +868,7 @@ "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { - "graceful-fs": "^4.1.6" + "graceful-fs": "4.2.2" } }, "klaw": { @@ -656,7 +877,7 @@ "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", "dev": true, "requires": { - "graceful-fs": "^4.1.9" + "graceful-fs": "4.2.2" } }, "levn": { @@ -665,23 +886,53 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "1.1.2", + "type-check": "0.3.2" } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "lolex": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", + "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", + "dev": true + }, + "magic-string": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", + "dev": true, + "requires": { + "vlq": "0.2.3" + } + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", "dev": true }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "requires": { + "mime-db": "1.33.0" + } + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -691,9 +942,21 @@ "dev": true }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", "dev": true }, "once": { @@ -702,7 +965,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "optionator": { @@ -711,12 +974,30 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "1.0.2" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "1.0.2" } }, "path-is-absolute": { @@ -725,48 +1006,87 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "path-to-regexp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz", + "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==", + "dev": true + }, + "pixelmatch": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.0.2.tgz", + "integrity": "sha512-b65UpTI40rGFY8QwN6IYuCbpmwAOL6M8d6voX4F3zR99UmDqh7r2QWLxoeHOazBRgEmDUdqNVESDREqFxQS7rQ==", + "dev": true, + "requires": { + "pngjs": "3.4.0" + } + }, + "pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "dev": true + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, "resolve": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", - "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", "dev": true, "requires": { - "path-parse": "^1.0.6" + "path-parse": "1.0.6" } }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "requires": { - "glob": "^7.1.3" + "glob": "7.1.4" }, "dependencies": { "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.1", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } } } @@ -777,16 +1097,29 @@ "integrity": "sha512-7RqCBQ9iwsOBPkjYgoIaeUij606mSkDMExP0NT7QDI3bqkHYQHrQ83uoNIXwPcQm/vP2VbsUz3kiyZZ1qPlLTQ==", "dev": true }, + "rollup-plugin-commonjs": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-8.4.1.tgz", + "integrity": "sha512-mg+WuD+jlwoo8bJtW3Mvx7Tz6TsIdMsdhuvCnDMoyjh0oxsVgsjB/N0X984RJCWwc5IIiqNVJhXeeITcc73++A==", + "dev": true, + "requires": { + "acorn": "5.7.3", + "estree-walker": "0.5.2", + "magic-string": "0.22.5", + "resolve": "1.12.0", + "rollup-pluginutils": "2.8.1" + } + }, "rollup-plugin-node-resolve": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-3.0.0.tgz", "integrity": "sha1-i4l8TDAw1QASd7BRSyXSygloPuA=", "dev": true, "requires": { - "browser-resolve": "^1.11.0", - "builtin-modules": "^1.1.0", - "is-module": "^1.0.0", - "resolve": "^1.1.6" + "browser-resolve": "1.11.3", + "builtin-modules": "1.1.1", + "is-module": "1.0.0", + "resolve": "1.12.0" } }, "rollup-plugin-uglify": { @@ -795,7 +1128,24 @@ "integrity": "sha1-Z7N60e/a+9g69MNrQMGJ7khmyWk=", "dev": true, "requires": { - "uglify-js": "^3.0.9" + "uglify-js": "3.6.0" + } + }, + "rollup-pluginutils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz", + "integrity": "sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg==", + "dev": true, + "requires": { + "estree-walker": "0.6.1" + }, + "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + } } }, "safe-buffer": { @@ -804,12 +1154,127 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "seedrandom": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.3.tgz", + "integrity": "sha512-PJLhhxIMjlMJaiIRtqiVW061EZn3cS+waZkbFe7eCa2R3g88HbNdWmw4NTFG1w5unxd0GeNaUUxZJP7gPAzSDQ==", + "dev": true + }, "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, + "serve-handler": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.1.tgz", + "integrity": "sha512-LQPvxGia2TYqyMkHKH4jW9jx6jlQUMcWz6gJavZ3+4vsnB+SaWbYTncb9YsK5YBR6SlvyumREZJAzLw8VaFAUQ==", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "fast-url-parser": "1.1.3", + "mime-types": "2.1.18", + "minimatch": "3.0.4", + "path-is-inside": "1.0.2", + "path-to-regexp": "2.2.1", + "range-parser": "1.2.0" + } + }, + "slugify": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.4.tgz", + "integrity": "sha512-KP0ZYk5hJNBS8/eIjGkFDCzGQIoZ1mnfQRYS5WM3273z+fxGWXeN0fkwf2ebEweydv9tioZIHGZKoF21U07/nw==", + "dev": true + }, + "socket.io": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.2.0.tgz", + "integrity": "sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w==", + "dev": true, + "requires": { + "debug": "4.1.1", + "engine.io": "3.3.2", + "has-binary2": "1.0.3", + "socket.io-adapter": "1.1.1", + "socket.io-client": "2.2.0", + "socket.io-parser": "3.3.0" + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", + "dev": true + }, + "socket.io-client": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.2.0.tgz", + "integrity": "sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "3.1.0", + "engine.io-client": "3.3.2", + "has-binary2": "1.0.3", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "3.3.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "socket.io-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", + "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -822,9 +1287,15 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -843,23 +1314,23 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "~1.1.2" + "prelude-ls": "1.1.2" } }, "uglify-js": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", "dev": true, "requires": { - "commander": "~2.17.1", - "source-map": "~0.6.1" + "commander": "2.20.0", + "source-map": "0.6.1" }, "dependencies": { "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true }, "source-map": { @@ -879,6 +1350,12 @@ "inherits": "2.0.1" } }, + "vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", + "dev": true + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -891,480 +1368,31 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "ws": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", + "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", + "dev": true, + "requires": { + "async-limiter": "1.0.1" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, "zrender": { "version": "4.0.7", - "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "bundled": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/core": { - "version": "7.3.4", - "bundled": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.3.4", - "@babel/helpers": "^7.2.0", - "@babel/parser": "^7.3.4", - "@babel/template": "^7.2.2", - "@babel/traverse": "^7.3.4", - "@babel/types": "^7.3.4", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.11", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - }, - "source-map": { - "version": "0.5.7", - "bundled": true - } - } - }, - "@babel/generator": { - "version": "7.3.4", - "bundled": true, - "requires": { - "@babel/types": "^7.3.4", - "jsesc": "^2.5.1", - "lodash": "^4.17.11", - "source-map": "^0.5.0", - "trim-right": "^1.0.1" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - }, - "source-map": { - "version": "0.5.7", - "bundled": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.1.0", - "bundled": true, - "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "bundled": true, - "requires": { - "@babel/types": "^7.0.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-module-imports": { - "version": "7.0.0", - "bundled": true, - "requires": { - "@babel/types": "^7.0.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-module-transforms": { - "version": "7.2.2", - "bundled": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/template": "^7.2.2", - "@babel/types": "^7.2.2", - "lodash": "^4.17.10" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-simple-access": { - "version": "7.1.0", - "bundled": true, - "requires": { - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.0.0", - "bundled": true, - "requires": { - "@babel/types": "^7.0.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helpers": { - "version": "7.3.1", - "bundled": true, - "requires": { - "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.5", - "@babel/types": "^7.3.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/highlight": { - "version": "7.0.0", - "bundled": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.3.4", - "bundled": true - }, - "@babel/template": { - "version": "7.2.2", - "bundled": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.2.2", - "@babel/types": "^7.2.2" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/traverse": { - "version": "7.3.4", - "bundled": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.3.4", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "@babel/parser": "^7.3.4", - "@babel/types": "^7.3.4", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.11" - }, - "dependencies": { - "@babel/types": { - "version": "7.3.4", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.11", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/types": { - "version": "7.0.0-beta.31", - "bundled": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.2.0", - "to-fast-properties": "^2.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "bundled": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "assert": { - "version": "1.4.1", - "bundled": true, - "requires": { - "util": "0.10.3" - } - }, - "chalk": { - "version": "2.4.2", - "bundled": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "bundled": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "bundled": true - }, - "commander": { - "version": "2.11.0", - "bundled": true - }, - "convert-source-map": { - "version": "1.6.0", - "bundled": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "requires": { - "ms": "^2.1.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true - }, - "esutils": { - "version": "2.0.2", - "bundled": true - }, - "fs-extra": { - "version": "4.0.2", - "bundled": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "globals": { - "version": "11.11.0", - "bundled": true - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "has-flag": { - "version": "3.0.0", - "bundled": true - }, - "inherits": { - "version": "2.0.1", - "bundled": true - }, - "is-equal": { - "version": "0.1.0", - "bundled": true - }, - "js-tokens": { - "version": "4.0.0", - "bundled": true - }, - "jsdiff": { - "version": "1.1.1", - "bundled": true, - "requires": { - "is-equal": "~0.1.0" - } - }, - "jsesc": { - "version": "2.5.2", - "bundled": true - }, - "json5": { - "version": "2.1.0", - "bundled": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "jsonfile": { - "version": "4.0.0", - "bundled": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "lodash": { - "version": "4.17.11", - "bundled": true - }, - "minimist": { - "version": "1.2.0", - "bundled": true - }, - "ms": { - "version": "2.1.1", - "bundled": true - }, - "path-parse": { - "version": "1.0.6", - "bundled": true - }, - "resolve": { - "version": "1.10.0", - "bundled": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "rollup": { - "version": "0.50.0", - "bundled": true - }, - "rollup-plugin-uglify": { - "version": "2.0.1", - "bundled": true, - "requires": { - "uglify-js": "^3.0.9" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true - }, - "semver": { - "version": "5.6.0", - "bundled": true - }, - "source-map": { - "version": "0.6.1", - "bundled": true - }, - "supports-color": { - "version": "5.5.0", - "bundled": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "to-fast-properties": { - "version": "2.0.0", - "bundled": true - }, - "trim-right": { - "version": "1.0.1", - "bundled": true - }, - "uglify-js": { - "version": "3.1.6", - "bundled": true, - "requires": { - "commander": "~2.11.0", - "source-map": "~0.6.1" - } - }, - "universalify": { - "version": "0.1.1", - "bundled": true - }, - "util": { - "version": "0.10.3", - "bundled": true, - "requires": { - "inherits": "2.0.1" - } - } - } + "resolved": "https://registry.npmjs.org/zrender/-/zrender-4.0.7.tgz", + "integrity": "sha512-TNloHe0ums6zxbHfnaCryM61J4IWDajZwNq6dHk9vfWhhysO/OeFvvR0drBs/nbXha2YxSzfQj2FiCd6RVBe+Q==" } } } diff --git a/package.json b/package.json index 18ad5a25b4..16fde6c97d 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ }, "scripts": { "prepublish": "node build/build.js --prepublish", + "test:visual": "node test/runTest/server.js", "test": "node build/build.js" }, "dependencies": { @@ -33,8 +34,16 @@ "estraverse": "4.1.1", "fs-extra": "0.26.7", "glob": "7.0.0", + "lolex": "^4.2.0", + "pixelmatch": "^5.0.2", + "pngjs": "^3.4.0", "rollup": "0.50.0", + "rollup-plugin-commonjs": "^8.4.1", "rollup-plugin-node-resolve": "3.0.0", - "rollup-plugin-uglify": "2.0.1" + "rollup-plugin-uglify": "2.0.1", + "seedrandom": "^3.0.3", + "serve-handler": "^6.1.1", + "slugify": "^1.3.4", + "socket.io": "^2.2.0" } } diff --git a/test/runTest/blacklist.js b/test/runTest/blacklist.js new file mode 100644 index 0000000000..9e9ad44d3f --- /dev/null +++ b/test/runTest/blacklist.js @@ -0,0 +1,4 @@ +module.exports = [ + '-cases.html', + 'geo-random-stream.html' +]; diff --git a/test/runTest/cli.js b/test/runTest/cli.js new file mode 100644 index 0000000000..e44ebe7698 --- /dev/null +++ b/test/runTest/cli.js @@ -0,0 +1,271 @@ +const puppeteer = require('puppeteer'); +const slugify = require('slugify'); +const fse = require('fs-extra'); +const fs = require('fs'); +const path = require('path'); +const compareScreenshot = require('./compareScreenshot'); +const {getTestName, getVersionDir, buildRuntimeCode} = require('./util'); +const {origin} = require('./config'); + +function getScreenshotDir() { + return 'tmp/__screenshot__'; +} + +function sortScreenshots(list) { + return list.sort((a, b) => { + return a.testName.localeCompare(b.testName); + }); +} + +function getClientRelativePath(absPath) { + return path.join('../', path.relative(__dirname, absPath)); +} + +function replaceEChartsVersion(interceptedRequest, version) { + // TODO Extensions and maps + if (interceptedRequest.url().endsWith('dist/echarts.js')) { + interceptedRequest.continue({ + url: `${origin}/test/runTest/${getVersionDir(version)}/echarts.js` + }); + } + else { + interceptedRequest.continue(); + } +} + +function waitPageForFinish(page) { + return new Promise(resolve => { + page.exposeFunction('puppeteerFinishTest', () => { + resolve(); + }); + }); +} + +function createWaitTimeout(maxTime) { + let timeoutHandle; + let resolve; + function keepWait(newMaxTime) { + newMaxTime = newMaxTime == null ? maxTime : newMaxTime; + clearTimeout(timeoutHandle); + createTimeout(newMaxTime); + } + + function createTimeout(maxTime) { + timeoutHandle = setTimeout(() => { + resolve(); + }, maxTime); + } + + function waitTimeout() { + return new Promise(_resolve => { + resolve = _resolve; + createTimeout(maxTime); + }); + } + + return {keepWait, waitTimeout}; +} + +async function takeScreenshot(page, elementQuery, fileUrl, desc, version) { + let target = elementQuery ? await page.$(elementQuery) : page; + if (!target) { + console.error(`Can't find element '${elementQuery}'`); + return; + } + let fullPage = !elementQuery; + let testName = getTestName(fileUrl); + if (desc) { + testName += '-' + slugify(desc, { replacement: '-', lower: true }) + } + let screenshotPrefix = version ? 'expected' : 'actual'; + fse.ensureDirSync(path.join(__dirname, getScreenshotDir())); + let screenshotPath = path.join(__dirname, `${getScreenshotDir()}/${testName}-${screenshotPrefix}.png`); + await target.screenshot({ + path: screenshotPath, + fullPage + }); + + return {testName, screenshotPath}; +} + +async function runTestPage(browser, fileUrl, version, runtimeCode) { + const {keepWait, waitTimeout} = createWaitTimeout(1500); + const screenshots = []; + const logs = []; + const errors = []; + let screenshotPromises = []; + + const page = await browser.newPage(); + page.setRequestInterception(true); + page.on('request', replaceEChartsVersion); + await page.evaluateOnNewDocument(runtimeCode); + + let descAutoCounter = 0; + + page.exposeFunction('puppeteerScreenshot', (desc, elementQuery) => { + keepWait(); + desc = desc || (descAutoCounter++).toString(); + let promise = takeScreenshot(page, elementQuery, fileUrl, desc, version).then((result) => { + if (!result) { + return; + } + const {testName, screenshotPath} = result; + screenshots.push({testName, desc, screenshotPath}); + }); + screenshotPromises.push(promise); + + return promise; + }); + page.on('console', msg => { + logs.push(msg.text()); + }); + page.on('pageerror', error => { + errors.push(error); + }); + + let pageFinishPromise = waitPageForFinish(page); + + try { + await page.setViewport({ + width: 800, + height: 600 + }); + await page.goto(`${origin}/test/${fileUrl}`, { + waitUntil: 'networkidle2', + // waitUntil: 'domcontentloaded', + timeout: 10000 + }); + } + catch(e) { + // TODO Timeout Error + console.error(e); + } + + // TODO Animation + + // Do auto screenshot after 100ms for animation. + // let autoSnapshotTimeout = setTimeout(async () => { + // let desc = `Animation Interval`; + // let promise = takeScreenshot(page, '', fileUrl, desc, version) + // .then(({testName, screenshotPath}) => { + // screenshots.push({testName, desc, screenshotPath}); + // }); + // screenshotPromises.push(promise); + // }, 100); + + // Wait for puppeteerFinishTest() is called + // Or compare the whole page if nothing happened after 10 seconds. + await Promise.race([ + pageFinishPromise, + waitTimeout().then(() => { + // console.warn('Test timeout after 3 seconds.'); + // Final shot. + let desc = 'Final Shot'; + return takeScreenshot(page, '', fileUrl, desc, version) + .then(({testName, screenshotPath}) => { + screenshots.push({testName, desc, screenshotPath}); + }); + }) + ]); + + // clearTimeout(autoSnapshotTimeout); + + // Wait for screenshot finished. + await Promise.all(screenshotPromises); + + await page.close(); + + return { + logs, + errors, + screenshots: screenshots + }; +} + +async function writePNG(diffPNG, diffPath) { + return new Promise(resolve => { + let writer = fs.createWriteStream(diffPath); + diffPNG.pack().pipe(writer); + writer.on('finish', () => {resolve();}); + }); +}; + +async function runTest(browser, testOpt, runtimeCode) { + testOpt.status === 'running'; + const fileUrl = testOpt.fileUrl; + const expectedResult = await runTestPage(browser, fileUrl, '4.2.1', runtimeCode); + const actualResult = await runTestPage(browser, fileUrl, '', runtimeCode); + + sortScreenshots(expectedResult.screenshots); + sortScreenshots(actualResult.screenshots); + + const screenshots = []; + let idx = 0; + for (let shot of expectedResult.screenshots) { + let expected = shot; + let actual = actualResult.screenshots[idx++]; + let {diffRatio, diffPNG} = await compareScreenshot( + expected.screenshotPath, + actual.screenshotPath + ); + + let diffPath = `${path.resolve(__dirname, getScreenshotDir())}/${shot.testName}-diff.png`; + await writePNG(diffPNG, diffPath); + + screenshots.push({ + actual: getClientRelativePath(actual.screenshotPath), + expected: getClientRelativePath(expected.screenshotPath), + diff: getClientRelativePath(diffPath), + name: actual.testName, + desc: actual.desc, + diffRatio + }); + } + + testOpt.results = screenshots; + testOpt.status = 'finished'; + testOpt.actualLogs = actualResult.logs; + testOpt.expectedLogs = expectedResult.logs; + testOpt.actualErrors = actualResult.errors; + testOpt.expectedErrors = expectedResult.errors; + +} + +async function runTests(pendingTests) { + const browser = await puppeteer.launch({ headless: true }); + // TODO Not hardcoded. + // let runtimeCode = fs.readFileSync(path.join(__dirname, 'tmp/testRuntime.js'), 'utf-8'); + let runtimeCode = await buildRuntimeCode(); + + try { + for (let testOpt of pendingTests) { + console.log('Running Test', testOpt.name); + try { + await runTest(browser, testOpt, runtimeCode); + } + catch (e) { + // Restore status + testOpt.status = 'pending'; + console.log(e); + } + + process.send(testOpt); + } + } + catch(e) { + console.log(e); + } + + await browser.close(); +} + +// Handling input arguments. +const testsFileUrlList = process.argv[2] || ''; +runTests(testsFileUrlList.split(',').map(fileUrl => { + return { + fileUrl, + name: getTestName(fileUrl), + results: [], + status: 'unsettled' + }; +})); \ No newline at end of file diff --git a/test/runTest/client/client.css b/test/runTest/client/client.css new file mode 100644 index 0000000000..cfaad1af93 --- /dev/null +++ b/test/runTest/client/client.css @@ -0,0 +1,163 @@ +#main { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; +} + +* { + font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; +} + +.header { + background-color: #293c55; + box-shadow: 0 0 20px rgba(0, 0, 0, 0.2); + position: relative; + z-index: 10; +} + +.header h1 { + color: #fff; + line-height: 50px; + margin: 0; + font-weight: 200; + font-size: 20px; +} + +#logo>* { + display: inline-block; + vertical-align: middle; +} + +#logo img { + height: 30px; + margin-right: 20px; +} + +.nav-toolbar { + padding: 10px 10px; + background: #162436; + box-shadow: inset 0 0 5px black; + position: fixed; + top: 50px; + width: 280px; + z-index: 2; +} +.nav-toolbar .controls { + margin-top: 10px; +} + +.test-list { + overflow-x: hidden; + background: #293c55; + margin: 0; + padding: 0; + margin-top: 80px; +} +.test-list li { + list-style: none; + padding-left: 10px; + cursor: pointer; + color: #f3f3f3; +} +.test-list li a.menu-link { + display: inline-block; + text-decoration: none; + font-size: 14px; + line-height: 40px; + color: #f3f3f3; + margin-left: 3px; + cursor: pointer; +} + +.test-list li.active { + background: #e43c59; +} +.test-list li:hover { + background: #162436; +} +.test-list li>* { + vertical-align: middle; + display: inline-block +} + +.test-list .el-progress__text { + font-size: 12px!important; +} + +.test-result h3 { + font-size: 40px; + font-weight: 200; + padding: 0; + margin: 0; +} + +.test-result .title>* { + display: inline-block; + vertical-align: middle; +} +.test-result .title a { + margin-left: 10px; + font-size: 20px; + font-weight: 200; + text-decoration: none; +} +.test-result .title a:hover { + text-decoration: underline; +} + +.test-screenshots { + margin-top: 80px; + padding: 0 20px; +} + +.test-screenshots img { + /* height: 200px; */ + width: 100%; +} +.test-screenshots h4 { + font-size: 30px; + font-weight: 200; + margin-left: -20px; + color: #162436; +} + +.test-errors, .test-logs { + margin-top: 20px; + padding: 0 50px; +} + +.test-logs .log-item { + margin: 10px 20px; + color: #909399; +} + +.test-errors .error-item { + margin: 10px 20px; + color: #f56c6c +} + + +::-webkit-scrollbar { + height:8px; + width:8px; + transition:all 0.3s ease-in-out; + border-radius:2px; + background: transparent; +} + +::-webkit-scrollbar-button { + display:none; +} + +::-webkit-scrollbar-thumb { + width:8px; + min-height:15px; + background:rgba(50, 50, 50, 0.6) !important; + transition:all 0.3s ease-in-out;border-radius:2px; +} + +::-webkit-scrollbar-thumb:hover { + background:rgba(0, 0, 0, 0.5) !important; +} \ No newline at end of file diff --git a/test/runTest/client/client.js b/test/runTest/client/client.js new file mode 100644 index 0000000000..0dc2607e0f --- /dev/null +++ b/test/runTest/client/client.js @@ -0,0 +1,182 @@ +const socket = io(); + +function processTestsData(tests, oldTestsData) { + tests.forEach((test, idx) => { + let passed = 0; + test.index = idx; + test.results.forEach(result => { + // Threshold? + if (result.diffRatio < 0.001) { + passed++; + } + }); + test.percentage = passed === 0 ? 0 : Math.round(passed / test.results.length * 100); + if (test.percentage === 100) { + test.summary = 'success'; + } + else if (test.percentage < 50) { + test.summary = 'exception'; + } + else { + test.summary = 'warning'; + } + + // Keep select status not change. + if (oldTestsData && oldTestsData[idx]) { + test.selected = oldTestsData[idx].selected; + } + else { + test.selected = false; + } + }); + return tests; +} + +socket.on('connect', () => { + console.log('Connected'); + const app = new Vue({ + el: '#app', + data: { + fullTests: [], + currentTestName: '', + sortBy: 'name', + searchString: '', + running: false, + + allSelected: false, + lastSelectedIndex: -1 + }, + computed: { + tests() { + let sortFunc = this.sortBy === 'name' + ? (a, b) => a.name.localeCompare(b.name) + : (a, b) => { + if (a.percentage === b.percentage) { + return a.name.localeCompare(b.name); + } + return a.percentage - b.percentage; + }; + + if (!this.searchString) { + // Not modify the original tests data. + return this.fullTests.slice().sort(sortFunc); + } + + return this.fullTests.filter(test => { + return test.name.match(this.searchString); + }).sort(sortFunc); + }, + + currentTest() { + let currentTest = this.fullTests.find(item => item.name === this.currentTestName); + if (!currentTest) { + currentTest = this.fullTests[0]; + } + return currentTest; + }, + + currentTestUrl() { + return window.location.origin + '/test/' + this.currentTest.fileUrl; + }, + + isSelectAllIndeterminate: { + get() { + if (!this.tests.length) { + return true; + } + return this.tests.some(test => { + return test.selected !== this.tests[0].selected; + }); + }, + set() {} + } + }, + methods: { + goto(url) { + window.location.hash = '#' + url; + }, + toggleSort() { + this.sortBy = this.sortBy === 'name' ? 'percentage' : 'name'; + }, + handleSelectAllChange(val) { + // Only select filtered tests. + this.tests.forEach(test => { + test.selected = val; + }); + this.isSelectAllIndeterminate = false; + }, + handleSelect(idx) { + Vue.nextTick(() => { + this.lastSelectedIndex = idx; + }); + }, + handleShiftSelect(idx) { + if (this.lastSelectedIndex < 0) { + return; + } + let start = Math.min(this.lastSelectedIndex, idx); + let end = Math.max(this.lastSelectedIndex, idx); + let selected = !this.tests[idx].selected; // Will change + for (let i = start; i < end; i++) { + this.tests[i].selected = selected; + } + }, + refreshList() { + + }, + runSelectedTests() { + const tests = this.fullTests.filter(test => { + return test.selected; + }).map(test => { + return test.name; + }); + if (tests.length > 0) { + this.running = true; + socket.emit('run', tests); + } + }, + stopTests() { + this.running = false; + socket.emit('stop'); + } + } + }); + app.$el.style.display = 'block'; + + let firstUpdate = true; + socket.on('update', msg => { + let hasFinishedTest = !!msg.tests.find(test => test.status === 'finished'); + if (!hasFinishedTest && firstUpdate) { + app.$confirm('It seems you haven\'t run any test yet!
Do you want to start now?', 'Tip', { + confirmButtonText: 'Yes', + cancelButtonText: 'No', + dangerouslyUseHTMLString: true, + center: true + }).then(value => { + app.running = true; + socket.emit('run', msg.tests.map(test => test.name)); + }).catch(() => {}); + } + // TODO + // app.running = !!msg.running; + app.fullTests = processTestsData(msg.tests, app.fullTests); + + firstUpdate = false; + }); + socket.on('finish', () => { + app.$notify({ + title: 'Test Complete', + position: 'bottom-right' + }); + app.running = false; + }); + + function updateTestHash() { + let testName = window.location.hash.slice(1); + app.currentTestName = testName; + } + + updateTestHash(); + window.addEventListener('hashchange', updateTestHash); +}); + diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html new file mode 100644 index 0000000000..c45b49d501 --- /dev/null +++ b/test/runTest/client/index.html @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/runTest/compareScreenshot.js b/test/runTest/compareScreenshot.js new file mode 100644 index 0000000000..8fd36c8236 --- /dev/null +++ b/test/runTest/compareScreenshot.js @@ -0,0 +1,41 @@ +const PNG = require('pngjs').PNG; +const pixelmatch = require('pixelmatch'); +const fs = require('fs'); + +function readPNG(path) { + return new Promise(resolve => { + fs.createReadStream(path) + .pipe(new PNG()) + .on('parsed', function () { + resolve({ + data: this.data, + width: this.width, + height: this.height + }); + }); + }); +} + +module.exports = function (expectedShotPath, actualShotPath, threshold = 0.1) { + return Promise.all([ + readPNG(expectedShotPath), + readPNG(actualShotPath) + ]).then(([expectedImg, actualImg]) => { + let width = expectedImg.width; + let height = expectedImg.height; + if ( + (width !== actualImg.width) + || (height !== actualImg.height) + ) { + throw new Error('Image size not match'); + } + const diffPNG = new PNG({width, height}); + let diffPixelsCount = pixelmatch(expectedImg.data, actualImg.data, diffPNG.data, width, height, {threshold}); + let totalPixelsCount = width * height; + + return { + diffRatio: diffPixelsCount / totalPixelsCount, + diffPNG + }; + }); +}; diff --git a/test/runTest/config.js b/test/runTest/config.js new file mode 100644 index 0000000000..723496506b --- /dev/null +++ b/test/runTest/config.js @@ -0,0 +1,4 @@ +module.exports = { + port: 8866, + origin: 'http://localhost:8866' +}; \ No newline at end of file diff --git a/test/runTest/runtime/main.js b/test/runTest/runtime/main.js new file mode 100644 index 0000000000..35da2f164e --- /dev/null +++ b/test/runTest/runtime/main.js @@ -0,0 +1,53 @@ +import seedrandom from 'seedrandom'; +import lolex from 'lolex'; + +// const NativeDate = window.Date; + +// const fixedTimestamp = 1566458693300; +// const actualTimestamp = NativeDate.now(); +// function MockDate(params) { +// if (!params) { +// const elapsedTime = NativeDate.now() - actualTimestamp; +// return new NativeDate(fixedTimestamp + elapsedTime); +// } +// else { +// return new NativeDate(params); +// } +// } +// MockDate.prototype = new Date(); +// // Fixed date +// window.Date = MockDate; + +// export function createScreenshotTest (desc, elementQuery, waitTime) { + +// }; + +/** + * Take screenshot immediately. + * @param {string} desc + * @param {string} [elementQuery] If only screenshot specifed element. Will do full page screenshot if it's not give. + */ +export function compareScreenshot (desc, elementQuery) { + return puppeteerScreenshot(desc, elementQuery); +}; + +/** + * Finish the test. + */ +export function finish() { + return puppeteerFinishTest(); +}; + + +let myRandom = new seedrandom('echarts-test'); +// Fixed random generator +Math.random = function () { + const val = myRandom(); + return val; +}; + +// lolex.install({ +// shouldAdvanceTime: true, +// advanceTimeDelta: 200, +// now: fixedTimestamp +// }); diff --git a/test/runTest/runtime/shim.js b/test/runTest/runtime/shim.js new file mode 100644 index 0000000000..d0febb410a --- /dev/null +++ b/test/runTest/runtime/shim.js @@ -0,0 +1,9 @@ +(function () { + if (typeof autorun !== 'undefined') { + return; + } + var autorun = {}; + autorun.createScreenshotTest = function () {}; + autorun.compareScreenshot = function () {}; + autorun.finish = function () {}; +})(); \ No newline at end of file diff --git a/test/runTest/server.js b/test/runTest/server.js new file mode 100644 index 0000000000..8900f948a2 --- /dev/null +++ b/test/runTest/server.js @@ -0,0 +1,127 @@ +const handler = require('serve-handler'); +const http = require('http'); +const path = require('path'); +// const open = require('open'); +const fse = require('fs-extra'); +const {fork} = require('child_process'); +const {port, origin} = require('./config'); +const {getTestsList, prepareTestsList, saveTestsList, mergeTestsResults} = require('./store'); +const {prepareEChartsVersion, buildRuntimeCode} = require('./util'); + +function serve() { + const server = http.createServer((request, response) => { + return handler(request, response, { + cleanUrls: false, + // Root folder of echarts + public: __dirname + '/../../' + }); + }); + + server.listen(port, () => { + console.log(`Server started. ${origin}`); + }); + + + const io = require('socket.io')(server); + return { + io + }; +}; + +let testProcess; +let pendingTests; + +function stopRunningTests() { + if (testProcess) { + testProcess.kill(); + testProcess = null; + } + if (pendingTests) { + pendingTests.forEach(testOpt => { + if (testOpt.status === 'pending') { + testOpt.status = 'unsettled'; + } + }); + pendingTests = null; + } +} + +function startTests(testsNameList, socket) { + console.log(testsNameList.join(',')); + + stopRunningTests(); + + return new Promise(resolve => { + pendingTests = getTestsList().filter(testOpt => { + return testsNameList.includes(testOpt.name); + }); + pendingTests.forEach(testOpt => { + // Reset all tests results + testOpt.status = 'pending'; + testOpt.results = []; + }); + + socket.emit('update', {tests: getTestsList()}); + + testProcess = fork(path.join(__dirname, 'cli.js'), [ + pendingTests.map(testOpt => testOpt.fileUrl) + ]); + // Finished one test + testProcess.on('message', testOpt => { + mergeTestsResults([testOpt]); + // Merge tests. + socket.emit('update', {tests: getTestsList(), running: true}); + saveTestsList(); + }); + // Finished all + testProcess.on('exit', () => { + resolve(); + }); + }); +} + +function checkPuppeteer() { + try { + return require('puppeteer'); + } + catch (e) { + return null; + } +} + +async function start() { + if (!checkPuppeteer()) { + // TODO Check version. + console.error(`Can't find puppeteer, use 'npm install puppeteer' to install`); + return; + } + + await prepareEChartsVersion('4.2.1'); // Expected version. + await prepareEChartsVersion(); // Version to test + + let runtimeCode = await buildRuntimeCode(); + fse.outputFileSync(path.join(__dirname, 'tmp/testRuntime.js'), runtimeCode, 'utf-8'); + + // Start a static server for puppeteer open the html test cases. + let {io} = serve(); + + io.on('connect', async socket => { + await prepareTestsList(); + + socket.emit('update', {tests: getTestsList()}); + // TODO Stop previous? + socket.on('run', async testsNameList => { + await startTests(testsNameList, socket); + socket.emit('finish'); + }); + socket.on('stop', () => { + stopRunningTests(); + }); + }); + + console.log(`Dashboard: ${origin}/test/runTest/client/index.html`); + // open(`${origin}/test/runTest/client/index.html`); + +} + +start(); \ No newline at end of file diff --git a/test/runTest/store.js b/test/runTest/store.js new file mode 100644 index 0000000000..4cd4fc9324 --- /dev/null +++ b/test/runTest/store.js @@ -0,0 +1,78 @@ +const path = require('path'); +const fse = require('fs-extra'); +const fs = require('fs'); +const glob = require('glob'); +const {getTestName} = require('./util'); +const util = require('util'); +const blacklist = require('./blacklist'); + +let _tests = []; +let _testsMap = {}; + +function getCacheFilePath() { + return path.join(__dirname, 'tmp/__cache__.json');; +} + +module.exports.getTestsList = function () { + return _tests; +}; + +module.exports.getTestByFileUrl = function (url) { + return _testsMap[url]; +}; + +module.exports.prepareTestsList = async function () { + let tmpFolder = path.join(__dirname, 'tmp'); + fse.ensureDirSync(tmpFolder); + _tests = []; + _testsMap = {}; + try { + let cachedStr = fs.readFileSync(getCacheFilePath(), 'utf-8'); + _tests = JSON.parse(cachedStr); + _tests.forEach(test => { + // In somehow tests are stopped and leave the status pending. + // Set the status to unsettled again. + if (test.status === 'pending') { + test.status = 'unsettled'; + } + _testsMap[test.fileUrl] = test; + }); + } + catch(e) { + _tests = []; + } + // Find if there is new html file + let files = await util.promisify(glob)('**.html', { cwd: path.resolve(__dirname, '../') }); + files.forEach(fileUrl => { + if (blacklist.includes(fileUrl)) { + return; + } + if (_testsMap[fileUrl]) { + return; + } + + let test = { + fileUrl, + name: getTestName(fileUrl), + // Default status should be unkown + // status: 'pending', + results: [] + }; + + _tests.push(test); + _testsMap[fileUrl] = test; + }); + return _tests; +}; + +module.exports.saveTestsList = function () { + fse.outputFileSync(getCacheFilePath(), JSON.stringify(_tests, null, 2), 'utf-8'); +}; + +module.exports.mergeTestsResults = function (testsResults) { + testsResults.forEach(testResult => { + if (_testsMap[testResult.fileUrl]) { + Object.assign(_testsMap[testResult.fileUrl], testResult); + } + }); +}; \ No newline at end of file diff --git a/test/runTest/util.js b/test/runTest/util.js new file mode 100644 index 0000000000..95cab471dc --- /dev/null +++ b/test/runTest/util.js @@ -0,0 +1,66 @@ +const path = require('path'); +const fse = require('fs-extra'); +const https = require('https'); +const fs = require('fs'); +const rollup = require('rollup'); +const resolve = require('rollup-plugin-node-resolve'); +const commonjs = require('rollup-plugin-commonjs'); + +module.exports.getTestName = function(fileUrl) { + return path.basename(fileUrl, '.html'); +}; + + +function getVersionDir(version) { + version = version || 'developing'; + return `tmp/__version__/${version}`; +}; +module.exports.getVersionDir = getVersionDir; + + +module.exports.prepareEChartsVersion = function (version) { + let versionFolder = path.join(__dirname, getVersionDir(version)); + fse.ensureDirSync(versionFolder); + if (!version) { + // Developing version, make sure it's new build + return fse.copy( + path.join(__dirname, '../../dist/echarts.js'), + `${versionFolder}/echarts.js` + ); + } + return new Promise(resolve => { + if (!fs.existsSync(`${versionFolder}/echarts.js`)) { + const file = fs.createWriteStream(`${versionFolder}/echarts.js`); + + console.log('Downloading echarts4.2.1 from ', `https://cdn.jsdelivr.net/npm/echarts@${version}/dist/echarts.js`); + https.get(`https://cdn.jsdelivr.net/npm/echarts@${version}/dist/echarts.js`, response => { + response.pipe(file); + + file.on('finish', () => { + resolve(); + }); + }); + } + else { + resolve(); + } + }); +}; + +module.exports.buildRuntimeCode = async function () { + const bundle = await rollup.rollup({ + input: path.join(__dirname, 'runtime/main.js'), + plugins: [ + resolve(), + commonjs() + ] + }); + const output = await bundle.generate({ + format: 'iife', + name: 'autorun' + }); + + // seedrandom use crypto as external module. Set it to null to avoid not defined error. + // TODO + return 'window.crypto = null\n' + output.code; +}; \ No newline at end of file From 5661c6eaaf75b8e98fa9f92348c37842e31c3490 Mon Sep 17 00:00:00 2001 From: Ovilia Date: Tue, 3 Sep 2019 20:27:41 +0800 Subject: [PATCH 049/127] fix(svg): svg doesn't support addHover; fix #11054 (#11156) --- src/util/graphic.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/graphic.js b/src/util/graphic.js index 110288a857..7f12289741 100644 --- a/src/util/graphic.js +++ b/src/util/graphic.js @@ -274,14 +274,14 @@ function singleEnterEmphasis(el) { return; } - var useHoverLayer = el.useHoverLayer; - el.__highlighted = useHoverLayer ? 'layer' : 'plain'; - var zr = el.__zr; - if (el.isGroup || (!zr && useHoverLayer)) { + if (el.isGroup || (!zr && el.useHoverLayer)) { return; } + var useHoverLayer = el.useHoverLayer && zr.painter.type === 'canvas'; + el.__highlighted = useHoverLayer ? 'layer' : 'plain'; + var elTarget = el; var targetStyle = el.style; From ad58ca322c67d3ab544e06efcb55b95b7df2f9f6 Mon Sep 17 00:00:00 2001 From: deqingli Date: Fri, 6 Sep 2019 17:45:04 +0800 Subject: [PATCH 050/127] fix(tree): fix tree root disappear after pan and roam #10291 #10986 #10164 #9580 #9256 #9216 --- src/chart/tree/TreeSeries.js | 4 +++- src/chart/tree/TreeView.js | 13 +++++++------ test/tree-basic.html | 3 ++- test/tree-radial.html | 1 + 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/chart/tree/TreeSeries.js b/src/chart/tree/TreeSeries.js index 7dda0f6b7d..f132c98799 100644 --- a/src/chart/tree/TreeSeries.js +++ b/src/chart/tree/TreeSeries.js @@ -133,7 +133,9 @@ export default SeriesModel.extend({ // the layout of the tree, two value can be selected, 'orthogonal' or 'radial' layout: 'orthogonal', - roam: false, // true | false | 'move' | 'scale', see module:component/helper/RoamController. + // true | false | 'move' | 'scale', see module:component/helper/RoamController. + roam: false, + // Symbol size scale ratio in roam nodeScaleRatio: 0.4, diff --git a/src/chart/tree/TreeView.js b/src/chart/tree/TreeView.js index 9ded9ddef3..79cffebed6 100644 --- a/src/chart/tree/TreeView.js +++ b/src/chart/tree/TreeView.js @@ -84,7 +84,7 @@ export default echarts.extendChartView({ group.attr('position', [layoutInfo.x, layoutInfo.y]); } - this._updateViewCoordSys(seriesModel); + this._updateViewCoordSys(seriesModel, layoutInfo, layout); this._updateController(seriesModel, ecModel, api); var oldData = this._data; @@ -148,7 +148,7 @@ export default echarts.extendChartView({ this._data = data; }, - _updateViewCoordSys: function (seriesModel) { + _updateViewCoordSys: function (seriesModel, layoutInfo, layout) { var data = seriesModel.getData(); var points = []; data.each(function (idx) { @@ -160,14 +160,15 @@ export default echarts.extendChartView({ var min = []; var max = []; bbox.fromPoints(points, min, max); + var isRadial = layout === 'radial'; // If width or height is 0 if (max[0] - min[0] === 0) { - max[0] += 1; - min[0] -= 1; + min[0] = isRadial ? min[0] - 1 : layoutInfo.x; + max[0] = isRadial ? max[0] + 1 : min[0] + layoutInfo.width; } if (max[1] - min[1] === 0) { - max[1] += 1; - min[1] -= 1; + min[1] = isRadial ? min[1] - 1 : layoutInfo.y; + max[1] = isRadial ? max[1] + 1 : min[1] + layoutInfo.height; } var viewCoordSys = seriesModel.coordinateSystem = new View(); diff --git a/test/tree-basic.html b/test/tree-basic.html index 63e47c3ea2..bb8a4b7edc 100644 --- a/test/tree-basic.html +++ b/test/tree-basic.html @@ -68,13 +68,14 @@ { type: 'tree', id: '3', - + data: [data], top: '1%', left: '7%', bottom: '1%', right: '20%', + roam: true, symbolSize: 7, diff --git a/test/tree-radial.html b/test/tree-radial.html index 43e299c7cd..e5550ada43 100644 --- a/test/tree-radial.html +++ b/test/tree-radial.html @@ -67,6 +67,7 @@ top: '18%', bottom: '14%', + roam: true, layout: 'radial', From 129c33484640d09836d908a738e41f2325dd558f Mon Sep 17 00:00:00 2001 From: sushuang Date: Fri, 6 Sep 2019 01:20:07 +0800 Subject: [PATCH 051/127] fix(effectSymol): fix to es3 code. --- src/chart/helper/EffectSymbol.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chart/helper/EffectSymbol.js b/src/chart/helper/EffectSymbol.js index c515c7fa5a..1f3a5e2a39 100644 --- a/src/chart/helper/EffectSymbol.js +++ b/src/chart/helper/EffectSymbol.js @@ -38,7 +38,7 @@ function normalizeSymbolSize(symbolSize) { } function updateRipplePath(rippleGroup, effectCfg) { - const color = effectCfg.rippleEffectColor || effectCfg.color; + var color = effectCfg.rippleEffectColor || effectCfg.color; rippleGroup.eachChild(function (ripplePath) { ripplePath.attr({ z: effectCfg.z, From 55de79f167fcde587e06850987b4be5452502761 Mon Sep 17 00:00:00 2001 From: Ovilia Date: Fri, 6 Sep 2019 17:29:48 +0800 Subject: [PATCH 052/127] feat: support expansion animation for data update; fix #11029 --- src/chart/pie/PieSeries.js | 5 +- src/chart/pie/PieView.js | 78 +++++++++++------ test/pie-animation.html | 169 +++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+), 25 deletions(-) create mode 100644 test/pie-animation.html diff --git a/src/chart/pie/PieSeries.js b/src/chart/pie/PieSeries.js index 63035d62d9..42a44e61f9 100644 --- a/src/chart/pie/PieSeries.js +++ b/src/chart/pie/PieSeries.js @@ -170,9 +170,12 @@ var PieSeries = echarts.extendSeriesModel({ borderWidth: 1 }, - // Animation type canbe expansion, scale + // Animation type. Valid values: expansion, scale animationType: 'expansion', + // Animation type when update. Valid values: transition, expansion + animationTypeUpdate: 'transition', + animationEasing: 'cubicOut' } }); diff --git a/src/chart/pie/PieView.js b/src/chart/pie/PieView.js index 1c06b7a8e3..b766c3d398 100644 --- a/src/chart/pie/PieView.js +++ b/src/chart/pie/PieView.js @@ -112,6 +112,8 @@ piePieceProto.updateData = function (data, idx, firstCreate) { var sectorShape = zrUtil.extend({}, layout); sectorShape.label = null; + var animationTypeUpdate = seriesModel.getShallow('animationTypeUpdate'); + if (firstCreate) { sector.setShape(sectorShape); @@ -136,9 +138,15 @@ piePieceProto.updateData = function (data, idx, firstCreate) { } else { - graphic.updateProps(sector, { - shape: sectorShape - }, seriesModel, idx); + if (animationTypeUpdate === 'expansion') { + // Sectors are set to be target shape and an overlaying clipPath is used for animation + sector.setShape(sectorShape); + } else { + // Transition animation from the old shape + graphic.updateProps(sector, { + shape: sectorShape + }, seriesModel, idx); + } } // Update common style @@ -167,7 +175,9 @@ piePieceProto.updateData = function (data, idx, firstCreate) { seriesModel.get('animation') ); - this._updateLabel(data, idx); + // Label and text animation should be applied only for transition type animation when update + var withAnimation = !firstCreate && animationTypeUpdate === 'transition'; + this._updateLabel(data, idx, withAnimation); this.highDownOnUpdate = (itemModel.get('hoverAnimation') && seriesModel.isAnimationEnabled()) ? function (fromState, toState) { @@ -201,7 +211,7 @@ piePieceProto.updateData = function (data, idx, firstCreate) { graphic.setHoverStyle(this); }; -piePieceProto._updateLabel = function (data, idx) { +piePieceProto._updateLabel = function (data, idx, withAnimation) { var labelLine = this.childAt(1); var labelText = this.childAt(2); @@ -218,20 +228,33 @@ piePieceProto._updateLabel = function (data, idx) { return; } - graphic.updateProps(labelLine, { - shape: { - points: labelLayout.linePoints || [ - [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y] - ] - } - }, seriesModel, idx); + var targetLineShape = { + points: labelLayout.linePoints || [ + [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y], [labelLayout.x, labelLayout.y] + ] + }; + var targetTextStyle = { + x: labelLayout.x, + y: labelLayout.y + }; + if (withAnimation) { + graphic.updateProps(labelLine, { + shape: targetLineShape + }, seriesModel, idx); + + graphic.updateProps(labelText, { + style: targetTextStyle + }, seriesModel, idx); + } + else { + labelLine.attr({ + shape: targetLineShape + }); + labelText.attr({ + style: targetTextStyle + }); + } - graphic.updateProps(labelText, { - style: { - x: labelLayout.x, - y: labelLayout.y - } - }, seriesModel, idx); labelText.attr({ rotation: labelLayout.rotation, origin: [labelLayout.x, labelLayout.y], @@ -309,6 +332,7 @@ var PieView = ChartView.extend({ var hasAnimation = ecModel.get('animation'); var isFirstRender = !oldData; var animationType = seriesModel.get('animationType'); + var animationTypeUpdate = seriesModel.get('animationTypeUpdate'); var onSectorClick = zrUtil.curry( updateDataSelected, this.uid, seriesModel, hasAnimation, api @@ -334,6 +358,12 @@ var PieView = ChartView.extend({ .update(function (newIdx, oldIdx) { var piePiece = oldData.getItemGraphicEl(oldIdx); + if (!isFirstRender && animationTypeUpdate !== 'transition') { + piePiece.eachChild(function (child) { + child.stopAnimation(true); + }); + } + piePiece.updateData(data, newIdx); piePiece.off('click'); @@ -348,9 +378,8 @@ var PieView = ChartView.extend({ .execute(); if ( - hasAnimation && isFirstRender && data.count() > 0 - // Default expansion animation - && animationType !== 'scale' + hasAnimation && data.count() > 0 + && (isFirstRender ? animationType !== 'scale' : animationTypeUpdate !== 'transition') ) { var shape = data.getItemLayout(0); for (var s = 1; isNaN(shape.startAngle) && s < data.count(); ++s) { @@ -361,7 +390,7 @@ var PieView = ChartView.extend({ var removeClipPath = zrUtil.bind(group.removeClipPath, group); group.setClipPath(this._createClipPath( - shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel + shape.cx, shape.cy, r, shape.startAngle, shape.clockwise, removeClipPath, seriesModel, isFirstRender )); } else { @@ -375,7 +404,7 @@ var PieView = ChartView.extend({ dispose: function () {}, _createClipPath: function ( - cx, cy, r, startAngle, clockwise, cb, seriesModel + cx, cy, r, startAngle, clockwise, cb, seriesModel, isFirstRender ) { var clipPath = new graphic.Sector({ shape: { @@ -389,7 +418,8 @@ var PieView = ChartView.extend({ } }); - graphic.initProps(clipPath, { + var initOrUpdate = isFirstRender ? graphic.initProps : graphic.updateProps; + initOrUpdate(clipPath, { shape: { endAngle: startAngle + (clockwise ? 1 : -1) * Math.PI * 2 } diff --git a/test/pie-animation.html b/test/pie-animation.html new file mode 100644 index 0000000000..679b50bbb8 --- /dev/null +++ b/test/pie-animation.html @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + +
Animation: Transition from previous state to new state, in 10 seconds after clicking Go
+ +
+ +
Animation: Transition all over again, in 10 seconds after clicking Go
+ +
+ + + + + + + + + + + \ No newline at end of file From 9921edfa40bbdc58049144d7bc016c665a3e195a Mon Sep 17 00:00:00 2001 From: pissang Date: Sat, 7 Sep 2019 00:47:57 +0800 Subject: [PATCH 053/127] test: add interaction record tool, add headless control. --- package.json | 1 + test/runTest/blacklist.js | 6 +- test/runTest/cli.js | 21 ++++- test/runTest/client/client.css | 28 +++--- test/runTest/client/client.js | 22 +++-- test/runTest/client/index.html | 16 ++-- test/runTest/recorder/index.html | 57 ++++++++++++ test/runTest/recorder/recorder.css | 110 ++++++++++++++++++++++ test/runTest/recorder/recorder.js | 142 +++++++++++++++++++++++++++++ test/runTest/server.js | 70 ++++++++++---- test/runTest/store.js | 2 +- test/runTest/util.js | 4 + 12 files changed, 430 insertions(+), 49 deletions(-) create mode 100644 test/runTest/recorder/index.html create mode 100644 test/runTest/recorder/recorder.css create mode 100644 test/runTest/recorder/recorder.js diff --git a/package.json b/package.json index 16fde6c97d..463980d374 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "rollup-plugin-node-resolve": "3.0.0", "rollup-plugin-uglify": "2.0.1", "seedrandom": "^3.0.3", + "semver": "^6.3.0", "serve-handler": "^6.1.1", "slugify": "^1.3.4", "socket.io": "^2.2.0" diff --git a/test/runTest/blacklist.js b/test/runTest/blacklist.js index 9e9ad44d3f..90982d8b4c 100644 --- a/test/runTest/blacklist.js +++ b/test/runTest/blacklist.js @@ -1,4 +1,8 @@ module.exports = [ '-cases.html', - 'geo-random-stream.html' + 'geo-random-stream.html', + 'chord.html', + 'lines-ny.html', + 'lines-ny-appendData.html', + 'linesGL-ny-appendData.html' ]; diff --git a/test/runTest/cli.js b/test/runTest/cli.js index e44ebe7698..574cda8846 100644 --- a/test/runTest/cli.js +++ b/test/runTest/cli.js @@ -6,6 +6,8 @@ const path = require('path'); const compareScreenshot = require('./compareScreenshot'); const {getTestName, getVersionDir, buildRuntimeCode} = require('./util'); const {origin} = require('./config'); +const program = require('commander'); + function getScreenshotDir() { return 'tmp/__screenshot__'; @@ -231,8 +233,8 @@ async function runTest(browser, testOpt, runtimeCode) { } -async function runTests(pendingTests) { - const browser = await puppeteer.launch({ headless: true }); +async function runTests(pendingTests, headless) { + const browser = await puppeteer.launch({ headless: headless }); // TODO Not hardcoded. // let runtimeCode = fs.readFileSync(path.join(__dirname, 'tmp/testRuntime.js'), 'utf-8'); let runtimeCode = await buildRuntimeCode(); @@ -260,12 +262,21 @@ async function runTests(pendingTests) { } // Handling input arguments. -const testsFileUrlList = process.argv[2] || ''; -runTests(testsFileUrlList.split(',').map(fileUrl => { +program + .option('-t, --tests ', 'Tests names list') + .option('--no-headless', 'Not headless'); + +program.parse(process.argv); + +if (!program.tests) { + throw new Error('Tests are required'); +} + +runTests(program.tests.split(',').map(fileUrl => { return { fileUrl, name: getTestName(fileUrl), results: [], status: 'unsettled' }; -})); \ No newline at end of file +}), program.headless); \ No newline at end of file diff --git a/test/runTest/client/client.css b/test/runTest/client/client.css index cfaad1af93..1991711225 100644 --- a/test/runTest/client/client.css +++ b/test/runTest/client/client.css @@ -140,24 +140,28 @@ ::-webkit-scrollbar { - height:8px; - width:8px; - transition:all 0.3s ease-in-out; - border-radius:2px; - background: transparent; + height: 8px; + width: 8px; + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; + -webkit-border-radius: 2px; + border-radius: 2px } ::-webkit-scrollbar-button { - display:none; + display: none } ::-webkit-scrollbar-thumb { - width:8px; - min-height:15px; - background:rgba(50, 50, 50, 0.6) !important; - transition:all 0.3s ease-in-out;border-radius:2px; + width: 8px; + min-height: 15px; + background: rgba(50,50,50,0.6) !important; + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; + -webkit-border-radius: 2px; + border-radius: 2px } ::-webkit-scrollbar-thumb:hover { - background:rgba(0, 0, 0, 0.5) !important; -} \ No newline at end of file + background: rgba(0,0,0,0.5) !important +} diff --git a/test/runTest/client/client.js b/test/runTest/client/client.js index 0dc2607e0f..38f4a75ee3 100644 --- a/test/runTest/client/client.js +++ b/test/runTest/client/client.js @@ -1,4 +1,4 @@ -const socket = io(); +const socket = io('/client'); function processTestsData(tests, oldTestsData) { tests.forEach((test, idx) => { @@ -44,7 +44,9 @@ socket.on('connect', () => { running: false, allSelected: false, - lastSelectedIndex: -1 + lastSelectedIndex: -1, + + noHeadless: false, }, computed: { tests() { @@ -76,7 +78,11 @@ socket.on('connect', () => { }, currentTestUrl() { - return window.location.origin + '/test/' + this.currentTest.fileUrl; + return window.location.origin + '/test/' + this.currentTestName + '.html'; + }, + + currentTestRecordUrl() { + return window.location.origin + '/test/runTest/recorder/index.html#' + this.currentTestName; }, isSelectAllIndeterminate: { @@ -132,7 +138,7 @@ socket.on('connect', () => { }); if (tests.length > 0) { this.running = true; - socket.emit('run', tests); + socket.emit('run', {tests, noHeadless: this.noHeadless}); } }, stopTests() { @@ -154,7 +160,10 @@ socket.on('connect', () => { center: true }).then(value => { app.running = true; - socket.emit('run', msg.tests.map(test => test.name)); + socket.emit('run', { + tests: msg.tests.map(test => test.name), + noHeadless: this.noHeadless + }); }).catch(() => {}); } // TODO @@ -172,8 +181,7 @@ socket.on('connect', () => { }); function updateTestHash() { - let testName = window.location.hash.slice(1); - app.currentTestName = testName; + app.currentTestName = window.location.hash.slice(1); } updateTestHash(); diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html index c45b49d501..07880e0f9f 100644 --- a/test/runTest/client/index.html +++ b/test/runTest/client/index.html @@ -20,15 +20,18 @@

Visual Regression Test

- + + + - + + + + + + +
+
+ + +
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/runTest/recorder/recorder.css b/test/runTest/recorder/recorder.css new file mode 100644 index 0000000000..66d50f00cd --- /dev/null +++ b/test/runTest/recorder/recorder.css @@ -0,0 +1,110 @@ +* { + font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; +} + +iframe { + border: none; + position: absolute; + top: 50px; + left: 50%; + + width: 800px; + height: 600px; + margin-left: -400px; + + box-shadow: 0 0 30px rgba(0, 0, 0, 0.2); + overflow-x: hidden; +} + +#recording-status { + position: absolute; + bottom: 30px; + width: 100%; + border-radius: 20px; + text-align: center; +} + +#recording-status .recording-button { + width: 80px;; + height: 80px;; + border-radius: 50px; + font-size: 50px; +} + +#recording-status .hint { + font-size: 26px; + font-weight: 200; + margin: 20px; +} + +#recording-status .hint .emphasis { + color: #F56C6C; + font-weight: 400; + margin: 0 10px; +} + +#actions { + position: fixed; + right: 10px; + width: 300px; +} + +#actions .action-item { + line-height: 40px; + padding: 0 20px; + margin: 0 -20px; + cursor: pointer; +} + + +#actions .action-item:hover { + background: #eee; +} + +#actions .action-item.active { + background: #409Eff; + color: #ffffff; +} + +#actions .action-item .operations { + height: 30px; + font-size: 14px; +} +#actions .action-item .operations>* { + display: inline-block; + vertical-align: middle; +} + +#actions .action-item .operations .el-icon-delete { + color: #F56C6C; + margin-left: 10px; +} + + + +::-webkit-scrollbar { + height: 8px; + width: 8px; + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; + -webkit-border-radius: 2px; + border-radius: 2px +} + +::-webkit-scrollbar-button { + display: none +} + +::-webkit-scrollbar-thumb { + width: 8px; + min-height: 15px; + background: rgba(50,50,50,0.6) !important; + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; + -webkit-border-radius: 2px; + border-radius: 2px +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(0,0,0,0.5) !important +} diff --git a/test/runTest/recorder/recorder.js b/test/runTest/recorder/recorder.js new file mode 100644 index 0000000000..73d3f2222c --- /dev/null +++ b/test/runTest/recorder/recorder.js @@ -0,0 +1,142 @@ +const socket = io('/recorder'); + +const app = new Vue({ + el: '#app', + data: { + currentTestName: '', + actions: [], + currentAction: null, + recordingAction: null, + + deletePopoverVisible: false + }, + computed: { + url() { + if (!this.currentTestName) { + return ''; + } + return window.location.origin + '/test/' + this.currentTestName + '.html'; + } + }, + methods: { + newAction() { + this.currentAction = { + name: 'Action ' + (this.actions.length + 1), + ops: [] + }; + this.actions.push(this.currentAction); + }, + select(actionName) { + this.currentAction = this.actions.find(action => { + return action.name === actionName; + }); + }, + + doDelete(actionName) { + app.$confirm('Aure you sure?', 'Delete this action', { + confirmButtonText: 'Yes', + cancelButtonText: 'No', + type: 'warning' + }).then(() => { + this.deletePopoverVisible = false; + let idx = _.findIndex(this.actions, action => action.name === actionName); + if (idx >= 0) { + this.actions.splice(idx, 1); + saveData(); + } + }).catch(e => {}); + } + } +}); + +function saveData() { + // Save + if (app.currentTestName) { + socket.emit('save', { + testName: app.currentTestName, + actions: app.actions + }); + } +} + +function recordIframeEvents(iframe, app) { + let innerDocument = iframe.contentWindow.document; + + let startTime; + innerDocument.addEventListener('keyup', e => { + if (e.key.toLowerCase() === 'r' && e.shiftKey) { + if (!app.recordingAction) { + app.recordingAction = app.currentAction; + if (app.recordingAction) { + app.recordingAction.ops = []; + app.recordingAction.scrollY = iframe.contentWindow.scrollY; + app.recordingAction.scrollX = iframe.contentWindow.scrollX; + startTime = app.recordingAction.timestamp = Date.now(); + } + } + else { + app.recordingAction = null; + saveData(); + } + // Get scroll + } + }); + + function addMouseOp(type, e) { + if (app.recordingAction) { + app.recordingAction.ops.push({ + type, + time: Date.now() - startTime, + x: e.clientX, + y: e.clientY + }); + app.$notify.info({ + title: type, + message: `{x: ${e.clientX}, y: ${e.clientY}}`, + position: 'top-left' + }); + } + } + + innerDocument.body.addEventListener('mousemove', _.throttle(e => { + addMouseOp('mousemove', e); + }, 200), true); + + ['mouseup', 'mousedown', 'click'].forEach(eventType => { + innerDocument.body.addEventListener(eventType, e => { + addMouseOp(eventType, e); + }, true); + }); +} + +function init() { + app.$el.style.display = 'block'; + + socket.on('update', data => { + if (data.testName === app.currentTestName) { + app.actions = data.actions; + if (!app.currentAction) { + app.currentAction = app.actions[0]; + } + } + }); + + let $iframe = document.body.querySelector('iframe'); + $iframe.onload = () => { + console.log('loaded:' + app.currentTestName); + recordIframeEvents($iframe, app); + }; + + function updateTestHash() { + app.currentTestName = window.location.hash.slice(1); + socket.emit('changeTest', {testName: app.currentTestName}); + + } + updateTestHash(); + window.addEventListener('hashchange', updateTestHash); +} + +socket.on('connect', () => { + console.log('Connected'); + init(); +}); \ No newline at end of file diff --git a/test/runTest/server.js b/test/runTest/server.js index 8900f948a2..aa51450f8e 100644 --- a/test/runTest/server.js +++ b/test/runTest/server.js @@ -2,11 +2,13 @@ const handler = require('serve-handler'); const http = require('http'); const path = require('path'); // const open = require('open'); -const fse = require('fs-extra'); const {fork} = require('child_process'); +const semver = require('semver'); const {port, origin} = require('./config'); -const {getTestsList, prepareTestsList, saveTestsList, mergeTestsResults} = require('./store'); -const {prepareEChartsVersion, buildRuntimeCode} = require('./util'); +const {getTestsList, updateTestsList, saveTestsList, mergeTestsResults} = require('./store'); +const {prepareEChartsVersion, getActionsFullPath} = require('./util'); +const fse = require('fs-extra'); +const fs = require('fs'); function serve() { const server = http.createServer((request, response) => { @@ -18,7 +20,7 @@ function serve() { }); server.listen(port, () => { - console.log(`Server started. ${origin}`); + // console.log(`Server started. ${origin}`); }); @@ -46,7 +48,7 @@ function stopRunningTests() { } } -function startTests(testsNameList, socket) { +function startTests(testsNameList, socket, noHeadless) { console.log(testsNameList.join(',')); stopRunningTests(); @@ -64,7 +66,9 @@ function startTests(testsNameList, socket) { socket.emit('update', {tests: getTestsList()}); testProcess = fork(path.join(__dirname, 'cli.js'), [ - pendingTests.map(testOpt => testOpt.fileUrl) + '--tests', + pendingTests.map(testOpt => testOpt.fileUrl).join(','), + ...(noHeadless ? ['--no-headless'] : []) ]); // Finished one test testProcess.on('message', testOpt => { @@ -82,36 +86,44 @@ function startTests(testsNameList, socket) { function checkPuppeteer() { try { - return require('puppeteer'); + const packageConfig = require('puppeteer/package.json'); + return semver.satisfies(packageConfig.version, '>=1.19.0'); } catch (e) { - return null; + return false; } } async function start() { if (!checkPuppeteer()) { // TODO Check version. - console.error(`Can't find puppeteer, use 'npm install puppeteer' to install`); + console.error(`Can't find puppeteer >= 1.19.0, use 'npm install puppeteer' to install or update`); return; } await prepareEChartsVersion('4.2.1'); // Expected version. await prepareEChartsVersion(); // Version to test - let runtimeCode = await buildRuntimeCode(); - fse.outputFileSync(path.join(__dirname, 'tmp/testRuntime.js'), runtimeCode, 'utf-8'); + // let runtimeCode = await buildRuntimeCode(); + // fse.outputFileSync(path.join(__dirname, 'tmp/testRuntime.js'), runtimeCode, 'utf-8'); // Start a static server for puppeteer open the html test cases. let {io} = serve(); - io.on('connect', async socket => { - await prepareTestsList(); + io.of('/client').on('connect', async socket => { + await updateTestsList(); socket.emit('update', {tests: getTestsList()}); - // TODO Stop previous? - socket.on('run', async testsNameList => { - await startTests(testsNameList, socket); + + socket.on('run', async data => { + // TODO Should broadcast to all sockets. + try { + console.log(data); + await startTests(data.tests, socket, data.noHeadless); + } + catch (e) { + console.error(e); + } socket.emit('finish'); }); socket.on('stop', () => { @@ -119,6 +131,32 @@ async function start() { }); }); + io.of('/recorder').on('connect', async socket => { + // await updateTestsList(); + socket.on('save', data => { + if (data.testName) { + fse.outputFile( + getActionsFullPath(data.testName), + JSON.stringify(data.actions, null, 2), + 'utf-8' + ); + } + // TODO Broadcast the change? + }); + socket.on('changeTest', data => { + try { + const actionData = fs.readFileSync(getActionsFullPath(data.testName), 'utf-8'); + socket.emit('update', { + testName: data.testName, + actions: JSON.parse(actionData) + }); + } + catch(e) { + // Can't find file. + } + }); + }); + console.log(`Dashboard: ${origin}/test/runTest/client/index.html`); // open(`${origin}/test/runTest/client/index.html`); diff --git a/test/runTest/store.js b/test/runTest/store.js index 4cd4fc9324..9851b02030 100644 --- a/test/runTest/store.js +++ b/test/runTest/store.js @@ -21,7 +21,7 @@ module.exports.getTestByFileUrl = function (url) { return _testsMap[url]; }; -module.exports.prepareTestsList = async function () { +module.exports.updateTestsList = async function () { let tmpFolder = path.join(__dirname, 'tmp'); fse.ensureDirSync(tmpFolder); _tests = []; diff --git a/test/runTest/util.js b/test/runTest/util.js index 95cab471dc..91c5819637 100644 --- a/test/runTest/util.js +++ b/test/runTest/util.js @@ -17,6 +17,10 @@ function getVersionDir(version) { }; module.exports.getVersionDir = getVersionDir; +module.exports.getActionsFullPath = function (testName) { + return path.join(__dirname, 'actions', testName + '.json'); +}; + module.exports.prepareEChartsVersion = function (version) { let versionFolder = path.join(__dirname, getVersionDir(version)); From e3d8d6289950bdfb0e65728ee123ea9b8bf37bb1 Mon Sep 17 00:00:00 2001 From: pissang Date: Sat, 7 Sep 2019 21:33:53 +0800 Subject: [PATCH 054/127] test: add interaction playback, optimize recorder ui --- test/runTest/Timeline.js | 95 +++++++++++++ test/runTest/cli.js | 210 ++++++++++++----------------- test/runTest/recorder/index.html | 24 +++- test/runTest/recorder/recorder.css | 57 +++++++- test/runTest/recorder/recorder.js | 76 +++++++---- test/runTest/runtime/main.js | 21 --- test/runTest/runtime/shim.js | 3 - test/runTest/server.js | 28 ++-- test/runTest/util.js | 7 +- 9 files changed, 328 insertions(+), 193 deletions(-) create mode 100644 test/runTest/Timeline.js diff --git a/test/runTest/Timeline.js b/test/runTest/Timeline.js new file mode 100644 index 0000000000..2151939ee3 --- /dev/null +++ b/test/runTest/Timeline.js @@ -0,0 +1,95 @@ +module.exports = class Timeline { + + constructor(page) { + this._page = page; + + this._timer = 0; + this._current = 0; + + this._ops = []; + this._currentOpIndex = 0; + } + + _reset() { + this._currentOpIndex = 0; + this._current = Date.now(); + this._elapsedTime = 0; + } + + + async runAction(action, playbackSpeed) { + this.stop(); + + playbackSpeed = playbackSpeed || 1; + + if (!action.ops.length) { + return; + } + + this._ops = action.ops.slice().sort((a, b) => { + return a.time - b.time; + }); + let firstOp = this._ops[0]; + this._ops.forEach(op => { + op.time -= firstOp.time; + }); + + this._reset(); + + let self = this; + + return new Promise(resolve => { + async function tick() { + let current = Date.now(); + let dTime = current - self._current; + self._elapsedTime += dTime * playbackSpeed; + self._current = current; + + await self._update(); + if (self._currentOpIndex >= self._ops.length) { + // Finished + resolve(); + } + else { + self._timer = setTimeout(tick, 16); + } + } + tick(); + }); + } + + + stop() { + if (this._timer) { + clearTimeout(this._timer); + this._timer = 0; + } + } + + async _update() { + let op = this._ops[this._currentOpIndex]; + + if (op.time > this._elapsedTime) { + // Not yet. + return; + } + + let page = this._page; + switch (op.type) { + case 'mousedown': + await page.mouse.move(op.x, op.y); + await page.mouse.down(); + break; + case 'mouseup': + await page.mouse.move(op.x, op.y); + await page.mouse.up(); + break; + case 'mousemove': + page.mouse.move(op.x, op.y); + break; + } + + this._currentOpIndex++; + + } +}; \ No newline at end of file diff --git a/test/runTest/cli.js b/test/runTest/cli.js index 574cda8846..d0ac3bc0eb 100644 --- a/test/runTest/cli.js +++ b/test/runTest/cli.js @@ -3,10 +3,23 @@ const slugify = require('slugify'); const fse = require('fs-extra'); const fs = require('fs'); const path = require('path'); +const program = require('commander'); const compareScreenshot = require('./compareScreenshot'); -const {getTestName, getVersionDir, buildRuntimeCode} = require('./util'); +const {testNameFromFile, fileNameFromTest, getVersionDir, buildRuntimeCode} = require('./util'); const {origin} = require('./config'); -const program = require('commander'); +const Timeline = require('./Timeline'); + +// Handling input arguments. +program + .option('-t, --tests ', 'Tests names list') + .option('--no-headless', 'Not headless') + .option('-s, --speed ', 'Playback speed'); + +program.parse(process.argv); + +if (!program.tests) { + throw new Error('Tests are required'); +} function getScreenshotDir() { @@ -15,7 +28,7 @@ function getScreenshotDir() { function sortScreenshots(list) { return list.sort((a, b) => { - return a.testName.localeCompare(b.testName); + return a.screenshotName.localeCompare(b.screenshotName); }); } @@ -35,89 +48,72 @@ function replaceEChartsVersion(interceptedRequest, version) { } } -function waitPageForFinish(page) { +function waitTime(time) { return new Promise(resolve => { - page.exposeFunction('puppeteerFinishTest', () => { + setTimeout(() => { resolve(); - }); + }, time); }); } -function createWaitTimeout(maxTime) { - let timeoutHandle; - let resolve; - function keepWait(newMaxTime) { - newMaxTime = newMaxTime == null ? maxTime : newMaxTime; - clearTimeout(timeoutHandle); - createTimeout(newMaxTime); - } - - function createTimeout(maxTime) { - timeoutHandle = setTimeout(() => { - resolve(); - }, maxTime); - } - - function waitTimeout() { - return new Promise(_resolve => { - resolve = _resolve; - createTimeout(maxTime); - }); - } - - return {keepWait, waitTimeout}; -} - -async function takeScreenshot(page, elementQuery, fileUrl, desc, version) { - let target = elementQuery ? await page.$(elementQuery) : page; - if (!target) { - console.error(`Can't find element '${elementQuery}'`); - return; - } - let fullPage = !elementQuery; - let testName = getTestName(fileUrl); +async function takeScreenshot(page, fullPage, fileUrl, desc, version) { + let screenshotName = testNameFromFile(fileUrl); if (desc) { - testName += '-' + slugify(desc, { replacement: '-', lower: true }) + screenshotName += '-' + slugify(desc, { replacement: '-', lower: true }); } let screenshotPrefix = version ? 'expected' : 'actual'; fse.ensureDirSync(path.join(__dirname, getScreenshotDir())); - let screenshotPath = path.join(__dirname, `${getScreenshotDir()}/${testName}-${screenshotPrefix}.png`); - await target.screenshot({ + let screenshotPath = path.join(__dirname, `${getScreenshotDir()}/${screenshotName}-${screenshotPrefix}.png`); + await page.screenshot({ path: screenshotPath, fullPage }); - return {testName, screenshotPath}; + return {screenshotName, screenshotPath}; +} + +async function runActions(page, testOpt, version, screenshots) { + let timeline = new Timeline(page); + let actions; + try { + let actContent = fs.readFileSync(path.join(__dirname, 'actions', testOpt.name + '.json')); + actions = JSON.parse(actContent); + } + catch (e) { + // Can't find actions + return; + } + + let playbackSpeed = +program.speed || 1; + + for (let action of actions) { + await page.evaluate((x, y) => { + window.scrollTo(x, y); + }, action.scrollX, action.scrollY); + + await timeline.runAction(action, playbackSpeed); + // Wait for animation finished + // TODO Configuration. + await waitTime(action.wait == null ? 200 : action.wait); + + const desc = action.desc || action.name; + const {screenshotName, screenshotPath} = await takeScreenshot(page, false, testOpt.fileUrl, desc, version); + screenshots.push({screenshotName, desc, screenshotPath}); + } + timeline.stop(); } -async function runTestPage(browser, fileUrl, version, runtimeCode) { - const {keepWait, waitTimeout} = createWaitTimeout(1500); +async function runTestPage(browser, testOpt, version, runtimeCode) { + const fileUrl = testOpt.fileUrl; const screenshots = []; const logs = []; const errors = []; - let screenshotPromises = []; const page = await browser.newPage(); page.setRequestInterception(true); page.on('request', replaceEChartsVersion); await page.evaluateOnNewDocument(runtimeCode); - let descAutoCounter = 0; - - page.exposeFunction('puppeteerScreenshot', (desc, elementQuery) => { - keepWait(); - desc = desc || (descAutoCounter++).toString(); - let promise = takeScreenshot(page, elementQuery, fileUrl, desc, version).then((result) => { - if (!result) { - return; - } - const {testName, screenshotPath} = result; - screenshots.push({testName, desc, screenshotPath}); - }); - screenshotPromises.push(promise); - - return promise; - }); page.on('console', msg => { logs.push(msg.text()); }); @@ -125,55 +121,28 @@ async function runTestPage(browser, fileUrl, version, runtimeCode) { errors.push(error); }); - let pageFinishPromise = waitPageForFinish(page); - try { - await page.setViewport({ - width: 800, - height: 600 - }); + await page.setViewport({ width: 800, height: 600 }); await page.goto(`${origin}/test/${fileUrl}`, { waitUntil: 'networkidle2', - // waitUntil: 'domcontentloaded', timeout: 10000 }); } catch(e) { - // TODO Timeout Error console.error(e); } - // TODO Animation - - // Do auto screenshot after 100ms for animation. - // let autoSnapshotTimeout = setTimeout(async () => { - // let desc = `Animation Interval`; - // let promise = takeScreenshot(page, '', fileUrl, desc, version) - // .then(({testName, screenshotPath}) => { - // screenshots.push({testName, desc, screenshotPath}); - // }); - // screenshotPromises.push(promise); - // }, 100); - - // Wait for puppeteerFinishTest() is called - // Or compare the whole page if nothing happened after 10 seconds. - await Promise.race([ - pageFinishPromise, - waitTimeout().then(() => { - // console.warn('Test timeout after 3 seconds.'); - // Final shot. - let desc = 'Final Shot'; - return takeScreenshot(page, '', fileUrl, desc, version) - .then(({testName, screenshotPath}) => { - screenshots.push({testName, desc, screenshotPath}); - }); - }) - ]); - - // clearTimeout(autoSnapshotTimeout); - - // Wait for screenshot finished. - await Promise.all(screenshotPromises); + // Final shot. + let desc = 'Full Shot'; + const {screenshotName, screenshotPath} = await takeScreenshot(page, true, fileUrl, desc, version); + + screenshots.push({screenshotName, desc, screenshotPath}); + + await runActions(page, testOpt, version, screenshots); + + if (!screenshots.length) { + waitTime(500); // Wait for animation or something else. + } await page.close(); @@ -194,12 +163,11 @@ async function writePNG(diffPNG, diffPath) { async function runTest(browser, testOpt, runtimeCode) { testOpt.status === 'running'; - const fileUrl = testOpt.fileUrl; - const expectedResult = await runTestPage(browser, fileUrl, '4.2.1', runtimeCode); - const actualResult = await runTestPage(browser, fileUrl, '', runtimeCode); + const expectedResult = await runTestPage(browser, testOpt, '4.2.1', runtimeCode); + const actualResult = await runTestPage(browser, testOpt, '', runtimeCode); - sortScreenshots(expectedResult.screenshots); - sortScreenshots(actualResult.screenshots); + // sortScreenshots(expectedResult.screenshots); + // sortScreenshots(actualResult.screenshots); const screenshots = []; let idx = 0; @@ -211,14 +179,14 @@ async function runTest(browser, testOpt, runtimeCode) { actual.screenshotPath ); - let diffPath = `${path.resolve(__dirname, getScreenshotDir())}/${shot.testName}-diff.png`; + let diffPath = `${path.resolve(__dirname, getScreenshotDir())}/${shot.screenshotName}-diff.png`; await writePNG(diffPNG, diffPath); screenshots.push({ actual: getClientRelativePath(actual.screenshotPath), expected: getClientRelativePath(expected.screenshotPath), diff: getClientRelativePath(diffPath), - name: actual.testName, + name: actual.screenshotName, desc: actual.desc, diffRatio }); @@ -233,8 +201,11 @@ async function runTest(browser, testOpt, runtimeCode) { } -async function runTests(pendingTests, headless) { - const browser = await puppeteer.launch({ headless: headless }); +async function runTests(pendingTests) { + const browser = await puppeteer.launch({ + headless: program.headless, + args: [`--window-size=830,750`] // new option + }); // TODO Not hardcoded. // let runtimeCode = fs.readFileSync(path.join(__dirname, 'tmp/testRuntime.js'), 'utf-8'); let runtimeCode = await buildRuntimeCode(); @@ -261,22 +232,11 @@ async function runTests(pendingTests, headless) { await browser.close(); } -// Handling input arguments. -program - .option('-t, --tests ', 'Tests names list') - .option('--no-headless', 'Not headless'); - -program.parse(process.argv); - -if (!program.tests) { - throw new Error('Tests are required'); -} - -runTests(program.tests.split(',').map(fileUrl => { +runTests(program.tests.split(',').map(testName => { return { - fileUrl, - name: getTestName(fileUrl), + fileUrl: fileNameFromTest(testName), + name: testName, results: [], status: 'unsettled' }; -}), program.headless); \ No newline at end of file +})); \ No newline at end of file diff --git a/test/runTest/recorder/index.html b/test/runTest/recorder/index.html index 883828d45f..79e9a4ed4b 100644 --- a/test/runTest/recorder/index.html +++ b/test/runTest/recorder/index.html @@ -20,25 +20,41 @@
Actions - New +
+ + New +
{{action.name}}
- Data ({{action.ops.length}})
{ scrollX: {{action.scrollX}}, scrollY: {{action.scrollY}} }
{{op}}
- +
+ Data ({{action.ops.length}}) + +
-
+
+ + +
+
diff --git a/test/runTest/recorder/recorder.css b/test/runTest/recorder/recorder.css index 66d50f00cd..2bce7aae47 100644 --- a/test/runTest/recorder/recorder.css +++ b/test/runTest/recorder/recorder.css @@ -16,6 +16,61 @@ iframe { overflow-x: hidden; } +#open-nav { + position: fixed; + left: 20px; + top: 20px; +} + +.op-notice { + width: 200px; +} + +#tests-nav { + position: fixed; + top: 0; + bottom: 0; + z-index: 2000; + left: 0; + width: 300px; + box-shadow: 0 0 50px rgba(0, 0, 0, 0.4); + background-color: white; + padding: 20px; + overflow-y: scroll; +} + +#tests-nav ul { + margin: 0; + padding: 0; +} + +#tests-nav li { + list-style: none; +} + +#tests-nav a { + color: #444; + text-decoration: none; + line-height: 30px; + transition: .15s ease-out; +} + +#tests-nav a:hover, #tests-nav a.active { + color: #409eff; +} + +#tests-nav .el-icon-circle-close { + position: fixed; + left: 280px; + top: 10px; + cursor: pointer; + font-size: 30px; + z-index: 2100; +} +#tests-nav .el-icon-circle-close:hover { + color: #409eff; +} + #recording-status { position: absolute; bottom: 30px; @@ -80,8 +135,6 @@ iframe { margin-left: 10px; } - - ::-webkit-scrollbar { height: 8px; width: 8px; diff --git a/test/runTest/recorder/recorder.js b/test/runTest/recorder/recorder.js index 73d3f2222c..548e2a6e73 100644 --- a/test/runTest/recorder/recorder.js +++ b/test/runTest/recorder/recorder.js @@ -3,12 +3,15 @@ const socket = io('/recorder'); const app = new Vue({ el: '#app', data: { + tests: [], + currentTestName: '', actions: [], currentAction: null, recordingAction: null, - deletePopoverVisible: false + + drawerVisible: true }, computed: { url() { @@ -45,6 +48,12 @@ const app = new Vue({ saveData(); } }).catch(e => {}); + }, + + run() { + socket.emit('runSingle', { + testName: app.currentTestName + }); } } }); @@ -52,57 +61,60 @@ const app = new Vue({ function saveData() { // Save if (app.currentTestName) { - socket.emit('save', { + socket.emit('saveActions', { testName: app.currentTestName, actions: app.actions }); } } -function recordIframeEvents(iframe, app) { - let innerDocument = iframe.contentWindow.document; - - let startTime; - innerDocument.addEventListener('keyup', e => { - if (e.key.toLowerCase() === 'r' && e.shiftKey) { - if (!app.recordingAction) { - app.recordingAction = app.currentAction; - if (app.recordingAction) { - app.recordingAction.ops = []; - app.recordingAction.scrollY = iframe.contentWindow.scrollY; - app.recordingAction.scrollX = iframe.contentWindow.scrollX; - startTime = app.recordingAction.timestamp = Date.now(); - } +function keyboardRecordingHandler(e) { + if (e.key.toLowerCase() === 'r' && e.shiftKey) { + if (!app.recordingAction) { + app.recordingAction = app.currentAction; + if (app.recordingAction) { + let $iframe = document.body.querySelector('iframe'); + app.recordingAction.ops = []; + app.recordingAction.scrollY = $iframe.contentWindow.scrollY; + app.recordingAction.scrollX = $iframe.contentWindow.scrollX; + app.recordingAction.timestamp = Date.now(); } - else { - app.recordingAction = null; - saveData(); - } - // Get scroll } - }); + else { + app.recordingAction = null; + saveData(); + } + // Get scroll + } +} + +function recordIframeEvents(iframe, app) { + let innerDocument = iframe.contentWindow.document; function addMouseOp(type, e) { if (app.recordingAction) { app.recordingAction.ops.push({ type, - time: Date.now() - startTime, + time: Date.now() - app.recordingAction.timestamp, x: e.clientX, y: e.clientY }); app.$notify.info({ title: type, - message: `{x: ${e.clientX}, y: ${e.clientY}}`, - position: 'top-left' + message: `(x: ${e.clientX}, y: ${e.clientY})`, + position: 'top-left', + customClass: 'op-notice' }); } } + innerDocument.addEventListener('keyup', keyboardRecordingHandler); + innerDocument.body.addEventListener('mousemove', _.throttle(e => { addMouseOp('mousemove', e); }, 200), true); - ['mouseup', 'mousedown', 'click'].forEach(eventType => { + ['mouseup', 'mousedown'].forEach(eventType => { innerDocument.body.addEventListener(eventType, e => { addMouseOp(eventType, e); }, true); @@ -112,7 +124,9 @@ function recordIframeEvents(iframe, app) { function init() { app.$el.style.display = 'block'; - socket.on('update', data => { + document.addEventListener('keyup', keyboardRecordingHandler); + + socket.on('updateActions', data => { if (data.testName === app.currentTestName) { app.actions = data.actions; if (!app.currentAction) { @@ -120,6 +134,9 @@ function init() { } } }); + socket.on('getTests', ({tests}) => { + app.tests = tests; + }); let $iframe = document.body.querySelector('iframe'); $iframe.onload = () => { @@ -129,6 +146,11 @@ function init() { function updateTestHash() { app.currentTestName = window.location.hash.slice(1); + // Reset + app.actions = []; + app.currentAction = null; + app.recordingAction = null; + socket.emit('changeTest', {testName: app.currentTestName}); } diff --git a/test/runTest/runtime/main.js b/test/runTest/runtime/main.js index 35da2f164e..0beef5f5c3 100644 --- a/test/runTest/runtime/main.js +++ b/test/runTest/runtime/main.js @@ -18,27 +18,6 @@ import lolex from 'lolex'; // // Fixed date // window.Date = MockDate; -// export function createScreenshotTest (desc, elementQuery, waitTime) { - -// }; - -/** - * Take screenshot immediately. - * @param {string} desc - * @param {string} [elementQuery] If only screenshot specifed element. Will do full page screenshot if it's not give. - */ -export function compareScreenshot (desc, elementQuery) { - return puppeteerScreenshot(desc, elementQuery); -}; - -/** - * Finish the test. - */ -export function finish() { - return puppeteerFinishTest(); -}; - - let myRandom = new seedrandom('echarts-test'); // Fixed random generator Math.random = function () { diff --git a/test/runTest/runtime/shim.js b/test/runTest/runtime/shim.js index d0febb410a..4ad899db67 100644 --- a/test/runTest/runtime/shim.js +++ b/test/runTest/runtime/shim.js @@ -3,7 +3,4 @@ return; } var autorun = {}; - autorun.createScreenshotTest = function () {}; - autorun.compareScreenshot = function () {}; - autorun.finish = function () {}; })(); \ No newline at end of file diff --git a/test/runTest/server.js b/test/runTest/server.js index aa51450f8e..05472a344c 100644 --- a/test/runTest/server.js +++ b/test/runTest/server.js @@ -67,7 +67,9 @@ function startTests(testsNameList, socket, noHeadless) { testProcess = fork(path.join(__dirname, 'cli.js'), [ '--tests', - pendingTests.map(testOpt => testOpt.fileUrl).join(','), + pendingTests.map(testOpt => testOpt.name).join(','), + '--speed', + 5, ...(noHeadless ? ['--no-headless'] : []) ]); // Finished one test @@ -118,12 +120,10 @@ async function start() { socket.on('run', async data => { // TODO Should broadcast to all sockets. try { - console.log(data); await startTests(data.tests, socket, data.noHeadless); } - catch (e) { - console.error(e); - } + catch (e) { console.error(e); } + console.log('Finished'); socket.emit('finish'); }); socket.on('stop', () => { @@ -132,12 +132,12 @@ async function start() { }); io.of('/recorder').on('connect', async socket => { - // await updateTestsList(); - socket.on('save', data => { + await updateTestsList(); + socket.on('saveActions', data => { if (data.testName) { fse.outputFile( getActionsFullPath(data.testName), - JSON.stringify(data.actions, null, 2), + JSON.stringify(data.actions), 'utf-8' ); } @@ -146,7 +146,7 @@ async function start() { socket.on('changeTest', data => { try { const actionData = fs.readFileSync(getActionsFullPath(data.testName), 'utf-8'); - socket.emit('update', { + socket.emit('updateActions', { testName: data.testName, actions: JSON.parse(actionData) }); @@ -155,6 +155,16 @@ async function start() { // Can't find file. } }); + socket.on('runSingle', async data => { + try { + await startTests([data.testName], socket, true); + } + catch (e) { console.error(e); } + console.log('Finished'); + socket.emit('finish'); + }); + + socket.emit('getTests', {tests: getTestsList().map(test => test.name)}); }); console.log(`Dashboard: ${origin}/test/runTest/client/index.html`); diff --git a/test/runTest/util.js b/test/runTest/util.js index 91c5819637..3226594b4e 100644 --- a/test/runTest/util.js +++ b/test/runTest/util.js @@ -6,10 +6,13 @@ const rollup = require('rollup'); const resolve = require('rollup-plugin-node-resolve'); const commonjs = require('rollup-plugin-commonjs'); -module.exports.getTestName = function(fileUrl) { - return path.basename(fileUrl, '.html'); +module.exports.testNameFromFile = function(fileName) { + return path.basename(fileName, '.html'); }; +module.exports.fileNameFromTest = function (testName) { + return testName + '.html'; +}; function getVersionDir(version) { version = version || 'developing'; From 2973d0c9c74c9c3b0f463aa87a2e680ecd28c899 Mon Sep 17 00:00:00 2001 From: pissang Date: Sat, 7 Sep 2019 23:55:36 +0800 Subject: [PATCH 055/127] test: improve ui of recording screenshots. --- test/runTest/Timeline.js | 24 +++++++++++++--- test/runTest/cli.js | 44 +++++++++++++++--------------- test/runTest/client/client.css | 6 +++- test/runTest/client/index.html | 13 +++++---- test/runTest/recorder/index.html | 16 +++++++---- test/runTest/recorder/recorder.css | 25 ++++++++++++++++- test/runTest/recorder/recorder.js | 32 ++++++++++++++++++++-- test/runTest/util.js | 10 ++++++- 8 files changed, 129 insertions(+), 41 deletions(-) diff --git a/test/runTest/Timeline.js b/test/runTest/Timeline.js index 2151939ee3..b22746807f 100644 --- a/test/runTest/Timeline.js +++ b/test/runTest/Timeline.js @@ -1,3 +1,5 @@ +const {waitTime} = require('./util'); + module.exports = class Timeline { constructor(page) { @@ -17,7 +19,7 @@ module.exports = class Timeline { } - async runAction(action, playbackSpeed) { + async runAction(action, takeScreenshot, playbackSpeed) { this.stop(); playbackSpeed = playbackSpeed || 1; @@ -45,7 +47,7 @@ module.exports = class Timeline { self._elapsedTime += dTime * playbackSpeed; self._current = current; - await self._update(); + await self._update(takeScreenshot); if (self._currentOpIndex >= self._ops.length) { // Finished resolve(); @@ -66,7 +68,7 @@ module.exports = class Timeline { } } - async _update() { + async _update(takeScreenshot) { let op = this._ops[this._currentOpIndex]; if (op.time > this._elapsedTime) { @@ -85,11 +87,25 @@ module.exports = class Timeline { await page.mouse.up(); break; case 'mousemove': - page.mouse.move(op.x, op.y); + await page.mouse.move(op.x, op.y); + break; + case 'screenshot': + await takeScreenshot(); break; } this._currentOpIndex++; + // If next op is an auto screenshot + let nextOp = this._ops[this._currentOpIndex]; + console.log(nextOp.type); + if (nextOp && nextOp.type === 'screenshot-auto') { + // TODO Configuration time + await waitTime(300); + console.log(Date.now()); + await takeScreenshot(); + console.log(Date.now()); + this._currentOpIndex++; + } } }; \ No newline at end of file diff --git a/test/runTest/cli.js b/test/runTest/cli.js index d0ac3bc0eb..9f60116497 100644 --- a/test/runTest/cli.js +++ b/test/runTest/cli.js @@ -5,7 +5,7 @@ const fs = require('fs'); const path = require('path'); const program = require('commander'); const compareScreenshot = require('./compareScreenshot'); -const {testNameFromFile, fileNameFromTest, getVersionDir, buildRuntimeCode} = require('./util'); +const {testNameFromFile, fileNameFromTest, getVersionDir, buildRuntimeCode, waitTime} = require('./util'); const {origin} = require('./config'); const Timeline = require('./Timeline'); @@ -48,19 +48,14 @@ function replaceEChartsVersion(interceptedRequest, version) { } } -function waitTime(time) { - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, time); - }); -} - -async function takeScreenshot(page, fullPage, fileUrl, desc, version) { +async function takeScreenshot(page, fullPage, fileUrl, desc, version, minor) { let screenshotName = testNameFromFile(fileUrl); if (desc) { screenshotName += '-' + slugify(desc, { replacement: '-', lower: true }); } + if (minor) { + screenshotName += '-' + minor; + } let screenshotPrefix = version ? 'expected' : 'actual'; fse.ensureDirSync(path.join(__dirname, getScreenshotDir())); let screenshotPath = path.join(__dirname, `${getScreenshotDir()}/${screenshotName}-${screenshotPrefix}.png`); @@ -91,14 +86,23 @@ async function runActions(page, testOpt, version, screenshots) { window.scrollTo(x, y); }, action.scrollX, action.scrollY); - await timeline.runAction(action, playbackSpeed); - // Wait for animation finished - // TODO Configuration. - await waitTime(action.wait == null ? 200 : action.wait); + let count = 0; + async function _innerTakeScreenshot() { + const desc = action.desc || action.name; + const {screenshotName, screenshotPath} = await takeScreenshot(page, false, testOpt.fileUrl, desc, version, count++); + screenshots.push({screenshotName, desc, screenshotPath}); + } + await timeline.runAction(action, _innerTakeScreenshot, playbackSpeed); - const desc = action.desc || action.name; - const {screenshotName, screenshotPath} = await takeScreenshot(page, false, testOpt.fileUrl, desc, version); - screenshots.push({screenshotName, desc, screenshotPath}); + if (count === 0) { + // TODO Configuration time + await waitTime(300); + await _innerTakeScreenshot(); + } + + // const desc = action.desc || action.name; + // const {screenshotName, screenshotPath} = await takeScreenshot(page, false, testOpt.fileUrl, desc, version); + // screenshots.push({screenshotName, desc, screenshotPath}); } timeline.stop(); } @@ -132,18 +136,14 @@ async function runTestPage(browser, testOpt, version, runtimeCode) { console.error(e); } + await waitTime(500); // Wait for animation or something else. // Final shot. let desc = 'Full Shot'; const {screenshotName, screenshotPath} = await takeScreenshot(page, true, fileUrl, desc, version); - screenshots.push({screenshotName, desc, screenshotPath}); await runActions(page, testOpt, version, screenshots); - if (!screenshots.length) { - waitTime(500); // Wait for animation or something else. - } - await page.close(); return { diff --git a/test/runTest/client/client.css b/test/runTest/client/client.css index 1991711225..05d3ed9883 100644 --- a/test/runTest/client/client.css +++ b/test/runTest/client/client.css @@ -108,10 +108,14 @@ } .test-screenshots { - margin-top: 80px; + margin-top: 20px; padding: 0 20px; } +.test-screenshots h4 { + margin-top: 60px; +} + .test-screenshots img { /* height: 200px; */ width: 100%; diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html index 07880e0f9f..7f0ccd09d2 100644 --- a/test/runTest/client/index.html +++ b/test/runTest/client/index.html @@ -69,11 +69,14 @@

{{currentTest.name}}

Record Interaction -
-

{{result.desc || result.name}}

+
+ +

+ {{result.desc || result.name}} +

- +
Expected
@@ -82,7 +85,7 @@

{{result.desc || result.name}}

- +
Actual
@@ -91,7 +94,7 @@

{{result.desc || result.name}}

- +
Diff({{result.diffRatio.toFixed(4)}})
diff --git a/test/runTest/recorder/index.html b/test/runTest/recorder/index.html index 79e9a4ed4b..3707cda196 100644 --- a/test/runTest/recorder/index.html +++ b/test/runTest/recorder/index.html @@ -8,7 +8,7 @@
    @@ -130,7 +148,7 @@

    Visual Regression Test

    >

    {{currentTest.name}}

    - + Open Demo @@ -146,7 +164,7 @@

    - Expected + Expected - {{currentTest.expectedVersion || ''}}
    @@ -155,7 +173,7 @@

    - Actual + Actual - {{currentTest.actualVersion || ''}}
    @@ -164,7 +182,7 @@

    - Diff({{result.diffRatio.toFixed(4)}}) + Diff - {{result.diffRatio.toFixed(4)}}
    diff --git a/test/runTest/server.js b/test/runTest/server.js index 3d6805dcff..da2f769d9a 100644 --- a/test/runTest/server.js +++ b/test/runTest/server.js @@ -25,7 +25,7 @@ const {fork} = require('child_process'); const semver = require('semver'); const {port, origin} = require('./config'); const {getTestsList, updateTestsList, saveTestsList, mergeTestsResults, updateActionsMeta} = require('./store'); -const {prepareEChartsVersion, getActionsFullPath} = require('./util'); +const {prepareEChartsLib, getActionsFullPath, fetchVersions} = require('./util'); const fse = require('fs-extra'); const fs = require('fs'); @@ -75,12 +75,16 @@ class Thread { this.onUpdate; } - fork(noHeadless, replaySpeed) { + fork(noHeadless, replaySpeed, actualVersion, expectedVersion) { let p = fork(path.join(__dirname, 'cli.js'), [ '--tests', this.tests.map(testOpt => testOpt.name).join(','), '--speed', replaySpeed || 5, + '--actual', + actualVersion, + '--expected', + expectedVersion, ...(noHeadless ? ['--no-headless'] : []) ]); this.p = p; @@ -108,7 +112,9 @@ class Thread { function startTests(testsNameList, socket, { noHeadless, threadsCount, - replaySpeed + replaySpeed, + actualVersion, + expectedVersion }) { console.log('Received: ', testsNameList.join(',')); @@ -147,7 +153,7 @@ function startTests(testsNameList, socket, { for (let i = 0; i < threadsCount; i++) { runningThreads[i].onExit = onExit; runningThreads[i].onUpdate = onUpdate; - runningThreads[i].fork(noHeadless, replaySpeed); + runningThreads[i].fork(noHeadless, replaySpeed, actualVersion, expectedVersion); runningCount++; } // If something bad happens and no proccess are started successfully @@ -174,8 +180,7 @@ async function start() { return; } - await prepareEChartsVersion('4.2.1'); // Expected version. - await prepareEChartsVersion(); // Version to test + let versions = await fetchVersions(); // let runtimeCode = await buildRuntimeCode(); // fse.outputFileSync(path.join(__dirname, 'tmp/testRuntime.js'), runtimeCode, 'utf-8'); @@ -189,7 +194,12 @@ async function start() { socket.emit('update', {tests: getTestsList()}); socket.on('run', async data => { + let startTime = Date.now(); + + await prepareEChartsLib(data.expectedVersion); // Expected version. + await prepareEChartsLib(data.actualVersion); // Version to test + // TODO Should broadcast to all sockets. try { await startTests( @@ -198,7 +208,9 @@ async function start() { { noHeadless: data.noHeadless, threadsCount: data.threads, - replaySpeed: data.replaySpeed + replaySpeed: data.replaySpeed, + actualVersion: data.actualVersion, + expectedVersion: data.expectedVersion } ); } @@ -213,6 +225,8 @@ async function start() { socket.on('stop', () => { stopRunningTests(); }); + + socket.emit('versions', versions); }); io.of('/recorder').on('connect', async socket => { @@ -245,7 +259,9 @@ async function start() { await startTests([data.testName], socket, { noHeadless: true, threadsCount: 1, - replaySpeed: 2 + replaySpeed: 2, + actualVersion: data.actualVersion, + expectedVersion: data.expectedVersion }); } catch (e) { console.error(e); } @@ -264,7 +280,7 @@ async function start() { }); console.log(`Dashboard: ${origin}/test/runTest/client/index.html`); - console.log(`Interaction Recorder: ${origin}/test/runTest/recorder/index.html`); + // console.log(`Interaction Recorder: ${origin}/test/runTest/recorder/index.html`); // open(`${origin}/test/runTest/client/index.html`); } diff --git a/test/runTest/util.js b/test/runTest/util.js index c638f69d34..2e551e3bf6 100644 --- a/test/runTest/util.js +++ b/test/runTest/util.js @@ -34,7 +34,7 @@ module.exports.fileNameFromTest = function (testName) { }; function getVersionDir(version) { - version = version || 'developing'; + version = version || 'local'; return `tmp/__version__/${version}`; }; module.exports.getVersionDir = getVersionDir; @@ -44,10 +44,10 @@ module.exports.getActionsFullPath = function (testName) { }; -module.exports.prepareEChartsVersion = function (version) { +module.exports.prepareEChartsLib = function (version) { let versionFolder = path.join(__dirname, getVersionDir(version)); fse.ensureDirSync(versionFolder); - if (!version) { + if (!version || version === 'local') { // Developing version, make sure it's new build return fse.copy( path.join(__dirname, '../../dist/echarts.js'), @@ -58,7 +58,7 @@ module.exports.prepareEChartsVersion = function (version) { if (!fs.existsSync(`${versionFolder}/echarts.js`)) { const file = fs.createWriteStream(`${versionFolder}/echarts.js`); - console.log('Downloading echarts4.2.1 from ', `https://cdn.jsdelivr.net/npm/echarts@${version}/dist/echarts.js`); + console.log(`Downloading echarts@${version} from `, `https://cdn.jsdelivr.net/npm/echarts@${version}/dist/echarts.js`); https.get(`https://cdn.jsdelivr.net/npm/echarts@${version}/dist/echarts.js`, response => { response.pipe(file); @@ -73,6 +73,29 @@ module.exports.prepareEChartsVersion = function (version) { }); }; +module.exports.fetchVersions = function () { + return new Promise((resolve, reject) => { + https.get(`https://registry.npmjs.org/echarts`, res => { + if (res.statusCode !== 200) { + res.destroy(); + reject('Failed fetch versions from https://registry.npmjs.org/echarts'); + return; + } + var buffers = []; + res.on('data', buffers.push.bind(buffers)); + res.on('end', function () { + try { + var data = Buffer.concat(buffers); + resolve(Object.keys(JSON.parse(data).versions)); + } + catch (e) { + reject(e.toString()); + } + }); + }); + }); +}; + module.exports.buildRuntimeCode = async function () { const bundle = await rollup.rollup({ input: path.join(__dirname, 'runtime/main.js'), From 738038b91578f7257b6050c0ce8207d061bdd9bc Mon Sep 17 00:00:00 2001 From: pissang Date: Wed, 11 Sep 2019 16:35:40 +0800 Subject: [PATCH 086/127] test: case insensitive search --- test/runTest/client/client.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/runTest/client/client.js b/test/runTest/client/client.js index f910178928..2cd05634ff 100644 --- a/test/runTest/client/client.js +++ b/test/runTest/client/client.js @@ -103,8 +103,9 @@ const app = new Vue({ return this.fullTests.slice().sort(sortFunc); } + let searchString = this.searchString.toLowerCase(); return this.fullTests.filter(test => { - return test.name.match(this.searchString); + return test.name.toLowerCase().match(searchString); }).sort(sortFunc); }, From 064d679caa44d5635637737abc7b3b49e7b1e8d3 Mon Sep 17 00:00:00 2001 From: pissang Date: Wed, 11 Sep 2019 16:49:09 +0800 Subject: [PATCH 087/127] test: add more run options. --- test/runTest/client/client.js | 44 +++++++++++++++++++++++----------- test/runTest/client/index.html | 7 +++--- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/test/runTest/client/client.js b/test/runTest/client/client.js index 2cd05634ff..7f644eda2f 100644 --- a/test/runTest/client/client.js +++ b/test/runTest/client/client.js @@ -109,6 +109,22 @@ const app = new Vue({ }).sort(sortFunc); }, + selectedTests() { + return this.fullTests.filter(test => { + return test.selected; + }); + }, + unfinishedTests() { + return this.fullTests.filter(test => { + return test.status !== 'finished'; + }); + }, + failedTests() { + return this.fullTests.filter(test => { + return test.status === 'finished' && test.summary !== 'success'; + }); + }, + currentTest() { let currentTest = this.fullTests.find(item => item.name === this.currentTestName); if (!currentTest) { @@ -171,20 +187,20 @@ const app = new Vue({ runTests([testName]); }, run(runTarget) { - const tests = this.fullTests.filter(test => { - if (runTarget === 'selected') { - return test.selected; - } - else if (runTarget === 'unfinished') { - return test.status !== 'finished'; - } - else { // Run all - return true; - } - }).map(test => { - return test.name; - }); - runTests(tests); + let tests; + if (runTarget === 'selected') { + tests = this.selectedTests; + } + else if (runTarget === 'unfinished') { + tests = this.unfinishedTests; + } + else if (runTarget === 'failed') { + tests = this.failedTests; + } + else { + tests = this.fullTests; + } + runTests(tests.map(test => test.name)); }, stopTests() { this.running = false; diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html index 64c2eba62f..8706c3324b 100644 --- a/test/runTest/client/index.html +++ b/test/runTest/client/index.html @@ -46,10 +46,11 @@

    Visual Regression Test

    @click="run('selected')" @command="run" > - Run selected + Run selected ({{selectedTests.length}}) - Run unfinished - Run all + Run unfinished ({{unfinishedTests.length}}) + Run failed ({{failedTests.length}}) + Run all ({{fullTests.length}}) From 4a9f6ec21347417f354ccbc5a71b356e9883c8d5 Mon Sep 17 00:00:00 2001 From: pissang Date: Wed, 11 Sep 2019 16:49:43 +0800 Subject: [PATCH 088/127] test: remove unused code --- test/runTest/client/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html index 8706c3324b..4b1f8d0a98 100644 --- a/test/runTest/client/index.html +++ b/test/runTest/client/index.html @@ -185,7 +185,7 @@

    Diff - {{result.diffRatio.toFixed(4)}}

- + From e57d21dcfbaf3b33146b49acb04a4f44a8ff83b0 Mon Sep 17 00:00:00 2001 From: pissang Date: Wed, 11 Sep 2019 17:02:55 +0800 Subject: [PATCH 089/127] test: add alert if scroll changed during action recording --- test/runTest/actions/__meta__.json | 3 ++- test/runTest/actions/axes.json | 1 + test/runTest/recorder/recorder.js | 15 +++++++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 test/runTest/actions/axes.json diff --git a/test/runTest/actions/__meta__.json b/test/runTest/actions/__meta__.json index 8af1757b4d..d9b9e289c0 100644 --- a/test/runTest/actions/__meta__.json +++ b/test/runTest/actions/__meta__.json @@ -127,5 +127,6 @@ "treemap-obama": 1, "treemap-option": 1, "treemap-option2": 1, - "visualMap-categories": 1 + "visualMap-categories": 1, + "axes": 0 } \ No newline at end of file diff --git a/test/runTest/actions/axes.json b/test/runTest/actions/axes.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/test/runTest/actions/axes.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/test/runTest/recorder/recorder.js b/test/runTest/recorder/recorder.js index fc74b3810a..44c6323132 100644 --- a/test/runTest/recorder/recorder.js +++ b/test/runTest/recorder/recorder.js @@ -196,6 +196,7 @@ function notify(title, message) { function keyboardRecordingHandler(e) { if (e.key.toLowerCase() === 'r' && e.shiftKey) { + let $iframe = getIframe(); if (!app.recordingAction) { // Create a new action if currentAction has ops. if (!app.currentAction || app.currentAction.ops.length > 0) { @@ -204,7 +205,6 @@ function keyboardRecordingHandler(e) { app.recordingAction = app.currentAction; if (app.recordingAction) { - let $iframe = getIframe(); app.recordingAction.scrollY = $iframe.contentWindow.scrollY; app.recordingAction.scrollX = $iframe.contentWindow.scrollX; app.recordingAction.timestamp = Date.now(); @@ -213,8 +213,19 @@ function keyboardRecordingHandler(e) { } } else { + if (app.recordingAction && + (app.recordingAction.scrollY !== $iframe.contentWindow.scrollY + || app.recordingAction.scrollX !== $iframe.contentWindow.scrollX)) { + app.recordingAction.ops = []; + app.$alert('You can\'t scroll the page during the action recording. Please create another action after scrolled to the next demo.', 'Recording Fail', { + confirmButtonText: 'Get!' + }); + + } + else { + saveData(); + } app.recordingAction = null; - saveData(); } // Get scroll } From 1c9f5b3f0d5265573249d0e5a5cf480819a97fee Mon Sep 17 00:00:00 2001 From: pissang Date: Wed, 11 Sep 2019 17:19:26 +0800 Subject: [PATCH 090/127] test: fix echarts version replacement in runtime --- test/runTest/cli.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/runTest/cli.js b/test/runTest/cli.js index 62bf18df21..ffd133dcaa 100644 --- a/test/runTest/cli.js +++ b/test/runTest/cli.js @@ -63,6 +63,7 @@ function getClientRelativePath(absPath) { function replaceEChartsVersion(interceptedRequest, version) { // TODO Extensions and maps if (interceptedRequest.url().endsWith('dist/echarts.js')) { + console.log(getVersionDir(version)); interceptedRequest.continue({ url: `${origin}/test/runTest/${getVersionDir(version)}/echarts.js` }); @@ -138,7 +139,7 @@ async function runTestPage(browser, testOpt, version, runtimeCode) { const page = await browser.newPage(); page.setRequestInterception(true); - page.on('request', replaceEChartsVersion); + page.on('request', request => replaceEChartsVersion(request, version)); await page.evaluateOnNewDocument(runtimeCode); From 7574e1e6d007588468f6a97939de70d1bd9f9235 Mon Sep 17 00:00:00 2001 From: deqingli Date: Wed, 11 Sep 2019 17:33:47 +0800 Subject: [PATCH 091/127] text: add automatic test material for stackBar-dataZoom demo --- test/runTest/actions/__meta__.json | 3 ++- test/runTest/actions/stackBar-dataZoom.json | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 test/runTest/actions/stackBar-dataZoom.json diff --git a/test/runTest/actions/__meta__.json b/test/runTest/actions/__meta__.json index 8af1757b4d..d98dda46c5 100644 --- a/test/runTest/actions/__meta__.json +++ b/test/runTest/actions/__meta__.json @@ -127,5 +127,6 @@ "treemap-obama": 1, "treemap-option": 1, "treemap-option2": 1, - "visualMap-categories": 1 + "visualMap-categories": 1, + "stackBar-dataZoom": 7 } \ No newline at end of file diff --git a/test/runTest/actions/stackBar-dataZoom.json b/test/runTest/actions/stackBar-dataZoom.json new file mode 100644 index 0000000000..01504b3e75 --- /dev/null +++ b/test/runTest/actions/stackBar-dataZoom.json @@ -0,0 +1 @@ +[{"name":"Action 1","ops":[{"type":"mousemove","time":854,"x":677,"y":234},{"type":"mousemove","time":1054,"x":239,"y":194},{"type":"mousemove","time":1259,"x":130,"y":229},{"type":"mousemove","time":1471,"x":476,"y":202},{"type":"mousemove","time":1671,"x":717,"y":201},{"type":"mousemove","time":1876,"x":777,"y":178},{"type":"mousemove","time":2087,"x":759,"y":169},{"type":"mousemove","time":2294,"x":758,"y":168},{"type":"mousedown","time":2302,"x":758,"y":168},{"type":"mouseup","time":2412,"x":758,"y":168},{"time":2413,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":2465,"x":722,"y":181},{"type":"mousemove","time":2665,"x":180,"y":208},{"type":"mousemove","time":2870,"x":84,"y":194},{"type":"mousemove","time":3071,"x":58,"y":197},{"type":"mousemove","time":3271,"x":87,"y":216},{"type":"mousemove","time":3471,"x":102,"y":218},{"type":"mousemove","time":3677,"x":105,"y":219},{"type":"mousedown","time":3828,"x":105,"y":219},{"type":"mousemove","time":3911,"x":105,"y":219},{"type":"mousemove","time":4121,"x":411,"y":272},{"type":"mousemove","time":4326,"x":500,"y":470},{"type":"mousemove","time":4537,"x":525,"y":501},{"type":"mousemove","time":4742,"x":526,"y":501},{"type":"mouseup","time":4948,"x":526,"y":501},{"time":4949,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":4970,"x":525,"y":500},{"type":"mousemove","time":5170,"x":518,"y":496},{"type":"mousemove","time":5378,"x":516,"y":494},{"type":"mousemove","time":5422,"x":516,"y":493},{"type":"mousemove","time":5622,"x":745,"y":198},{"type":"mousemove","time":5828,"x":746,"y":193},{"type":"mousemove","time":6038,"x":755,"y":172},{"type":"mousemove","time":6244,"x":760,"y":169},{"type":"mousemove","time":6455,"x":241,"y":208},{"type":"mousemove","time":6661,"x":255,"y":214},{"type":"mousemove","time":6878,"x":249,"y":230},{"type":"mousemove","time":7054,"x":249,"y":230},{"type":"mousedown","time":7163,"x":250,"y":229},{"type":"mousemove","time":7257,"x":253,"y":228},{"type":"mousemove","time":7464,"x":498,"y":317},{"type":"mousemove","time":7671,"x":566,"y":461},{"type":"mousemove","time":7871,"x":589,"y":499},{"type":"mousemove","time":8077,"x":595,"y":503},{"type":"mousemove","time":8171,"x":595,"y":503},{"type":"mouseup","time":8487,"x":595,"y":503},{"time":8488,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":8588,"x":594,"y":503},{"type":"mousemove","time":8796,"x":594,"y":502},{"type":"mousemove","time":9021,"x":594,"y":502},{"type":"mousemove","time":9227,"x":586,"y":497}],"scrollY":0,"scrollX":0,"timestamp":1568192976737},{"name":"Action 2","ops":[{"type":"mousemove","time":759,"x":783,"y":144},{"type":"mousemove","time":959,"x":753,"y":114},{"type":"mousemove","time":1159,"x":757,"y":100},{"type":"mousedown","time":1305,"x":756,"y":99},{"type":"mousemove","time":1366,"x":756,"y":99},{"type":"mouseup","time":1432,"x":756,"y":99},{"time":1433,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":1484,"x":756,"y":105},{"type":"mousemove","time":1684,"x":144,"y":150},{"type":"mousemove","time":1894,"x":57,"y":143},{"type":"mousemove","time":2101,"x":90,"y":152},{"type":"mousemove","time":2314,"x":104,"y":156},{"type":"mousedown","time":2489,"x":104,"y":156},{"type":"mousemove","time":2593,"x":105,"y":156},{"type":"mousemove","time":2793,"x":366,"y":235},{"type":"mousemove","time":2993,"x":443,"y":380},{"type":"mousemove","time":3193,"x":473,"y":430},{"type":"mousemove","time":3398,"x":476,"y":439},{"type":"mousemove","time":3609,"x":477,"y":449},{"type":"mousemove","time":3809,"x":468,"y":461},{"type":"mousemove","time":4010,"x":448,"y":465},{"type":"mousemove","time":4267,"x":448,"y":465},{"type":"mouseup","time":4436,"x":448,"y":465},{"time":4437,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":4526,"x":449,"y":464},{"type":"mousemove","time":4726,"x":485,"y":437},{"type":"mousemove","time":4927,"x":578,"y":349},{"type":"mousemove","time":5127,"x":709,"y":192},{"type":"mousemove","time":5334,"x":768,"y":132},{"type":"mousemove","time":5543,"x":771,"y":111},{"type":"mousemove","time":5743,"x":732,"y":110},{"type":"mousemove","time":5944,"x":377,"y":146},{"type":"mousemove","time":6154,"x":231,"y":179},{"type":"mousemove","time":6361,"x":227,"y":178},{"type":"mousemove","time":6569,"x":232,"y":171},{"type":"mousedown","time":6737,"x":234,"y":163},{"type":"mousemove","time":6783,"x":234,"y":163},{"type":"mousemove","time":6995,"x":479,"y":258},{"type":"mousemove","time":7203,"x":562,"y":397},{"type":"mousemove","time":7410,"x":597,"y":439},{"type":"mousemove","time":7617,"x":602,"y":445},{"type":"mousemove","time":7866,"x":601,"y":445},{"type":"mousemove","time":8044,"x":601,"y":445},{"type":"mouseup","time":8060,"x":601,"y":445},{"time":8061,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":8249,"x":601,"y":443},{"type":"mousemove","time":8461,"x":601,"y":443},{"type":"mousemove","time":8668,"x":602,"y":444},{"type":"mousemove","time":8794,"x":602,"y":443},{"type":"mousemove","time":9001,"x":602,"y":442},{"type":"mousemove","time":9127,"x":602,"y":442},{"type":"mousemove","time":9334,"x":603,"y":442},{"type":"mousemove","time":9411,"x":604,"y":442},{"type":"mousemove","time":9618,"x":758,"y":389}],"scrollY":506,"scrollX":0,"timestamp":1568192997548},{"name":"Action 3","ops":[{"type":"mousemove","time":674,"x":505,"y":227},{"type":"mousemove","time":874,"x":421,"y":253},{"type":"mousemove","time":1075,"x":378,"y":254},{"type":"mousemove","time":1281,"x":369,"y":244},{"type":"mousedown","time":1481,"x":359,"y":237},{"type":"mousemove","time":1498,"x":359,"y":237},{"type":"mouseup","time":1648,"x":359,"y":237},{"time":1649,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":1691,"x":359,"y":237},{"type":"mousemove","time":1896,"x":373,"y":265},{"type":"mousemove","time":11175,"x":373,"y":264},{"type":"mousemove","time":11381,"x":374,"y":260},{"type":"mousedown","time":11581,"x":374,"y":260},{"type":"mousemove","time":11598,"x":374,"y":260},{"type":"mouseup","time":11705,"x":374,"y":260},{"time":11706,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":12207,"x":373,"y":260},{"type":"mousemove","time":12409,"x":352,"y":264},{"type":"mousemove","time":14041,"x":352,"y":262},{"type":"mousemove","time":14251,"x":349,"y":248},{"type":"mousedown","time":14486,"x":349,"y":248},{"type":"mouseup","time":14688,"x":349,"y":248},{"time":14689,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":15041,"x":349,"y":248},{"type":"mousedown","time":16850,"x":349,"y":248},{"type":"mouseup","time":17032,"x":349,"y":248},{"time":17033,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":17557,"x":350,"y":248},{"type":"mousemove","time":17765,"x":376,"y":250}],"scrollY":986,"scrollX":0,"timestamp":1568193017000},{"name":"Action 4","ops":[{"type":"mousemove","time":472,"x":778,"y":344},{"type":"mousemove","time":681,"x":777,"y":375},{"type":"mousemove","time":923,"x":783,"y":84},{"type":"mousemove","time":1123,"x":749,"y":70},{"type":"mousemove","time":1323,"x":752,"y":66},{"type":"mousemove","time":1530,"x":756,"y":66},{"type":"mousemove","time":1739,"x":762,"y":65},{"type":"mousedown","time":1846,"x":770,"y":62},{"type":"mousemove","time":1939,"x":771,"y":64},{"type":"mouseup","time":1956,"x":771,"y":64},{"time":1957,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":2140,"x":280,"y":149},{"type":"mousemove","time":2349,"x":213,"y":115},{"type":"mousemove","time":2556,"x":203,"y":121},{"type":"mousemove","time":2756,"x":212,"y":128},{"type":"mousemove","time":2958,"x":216,"y":133},{"type":"mousemove","time":3173,"x":213,"y":148},{"type":"mousemove","time":3373,"x":195,"y":166},{"type":"mousemove","time":3573,"x":185,"y":135},{"type":"mousemove","time":3773,"x":175,"y":127},{"type":"mousemove","time":3980,"x":164,"y":123},{"type":"mousemove","time":4189,"x":497,"y":124},{"type":"mousemove","time":4389,"x":670,"y":95},{"type":"mousemove","time":4590,"x":759,"y":91},{"type":"mousemove","time":4798,"x":763,"y":77},{"type":"mousemove","time":5008,"x":762,"y":67},{"type":"mousedown","time":5148,"x":762,"y":65},{"type":"mousemove","time":5215,"x":762,"y":65},{"type":"mouseup","time":5233,"x":762,"y":65},{"time":5234,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":5424,"x":474,"y":123},{"type":"mousemove","time":5626,"x":272,"y":130},{"type":"mousemove","time":5836,"x":189,"y":131},{"type":"mousemove","time":6041,"x":158,"y":122},{"type":"mousemove","time":6252,"x":158,"y":120},{"type":"mousedown","time":6289,"x":160,"y":118},{"type":"mousemove","time":6459,"x":215,"y":123},{"type":"mousemove","time":6666,"x":428,"y":209},{"type":"mousemove","time":6882,"x":500,"y":360},{"type":"mousemove","time":7086,"x":586,"y":375},{"type":"mousemove","time":7297,"x":625,"y":369},{"type":"mousemove","time":7490,"x":625,"y":369},{"type":"mouseup","time":7525,"x":624,"y":370},{"time":7526,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":7691,"x":608,"y":367},{"type":"mousemove","time":7891,"x":602,"y":343},{"type":"mousemove","time":8113,"x":698,"y":117},{"type":"mousemove","time":8319,"x":742,"y":91},{"type":"mousemove","time":8526,"x":210,"y":134},{"type":"mousemove","time":8734,"x":197,"y":139},{"type":"mousemove","time":8941,"x":165,"y":136},{"type":"mousemove","time":9152,"x":155,"y":135},{"type":"mousedown","time":9219,"x":156,"y":135},{"type":"mousemove","time":9357,"x":202,"y":135},{"type":"mousemove","time":9557,"x":411,"y":165},{"type":"mousemove","time":9768,"x":490,"y":317},{"type":"mousemove","time":9975,"x":526,"y":359},{"type":"mousemove","time":10183,"x":526,"y":359},{"type":"mouseup","time":10234,"x":526,"y":359},{"time":10235,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":10395,"x":509,"y":330},{"type":"mousemove","time":10603,"x":398,"y":128},{"type":"mousemove","time":10816,"x":297,"y":55},{"type":"mousemove","time":11023,"x":337,"y":78},{"type":"mousemove","time":11223,"x":325,"y":62},{"type":"mousedown","time":11333,"x":323,"y":59},{"type":"mousemove","time":11424,"x":323,"y":59},{"type":"mouseup","time":11444,"x":323,"y":59},{"time":11445,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":11633,"x":323,"y":61},{"type":"mousedown","time":12886,"x":323,"y":61},{"type":"mouseup","time":12970,"x":323,"y":61},{"time":12971,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":13007,"x":323,"y":61},{"type":"mousemove","time":13207,"x":333,"y":62},{"type":"mousemove","time":13417,"x":427,"y":73},{"type":"mousemove","time":13623,"x":439,"y":71},{"type":"mousemove","time":13832,"x":450,"y":69},{"type":"mousemove","time":14806,"x":450,"y":68},{"type":"mousemove","time":15014,"x":449,"y":65},{"type":"mousemove","time":17055,"x":450,"y":65},{"type":"mousemove","time":17255,"x":457,"y":72},{"type":"mousemove","time":17456,"x":410,"y":259},{"type":"mousemove","time":17656,"x":475,"y":294},{"type":"mousemove","time":17856,"x":485,"y":290},{"type":"mousemove","time":18066,"x":481,"y":295}],"scrollY":1423,"scrollX":0,"timestamp":1568193043635},{"name":"Action 5","ops":[{"type":"mousemove","time":549,"x":678,"y":344},{"type":"mousemove","time":749,"x":373,"y":115},{"type":"mousemove","time":952,"x":192,"y":32},{"type":"mousemove","time":1152,"x":135,"y":90},{"type":"mousemove","time":1367,"x":61,"y":107},{"type":"mousemove","time":1567,"x":91,"y":165},{"type":"mousemove","time":1774,"x":85,"y":135},{"type":"mousemove","time":1990,"x":86,"y":99},{"type":"mousemove","time":2200,"x":84,"y":100},{"type":"mousemove","time":2407,"x":83,"y":101},{"type":"mousemove","time":2566,"x":83,"y":101},{"type":"mousemove","time":2767,"x":83,"y":99},{"type":"mousemove","time":3012,"x":83,"y":96},{"type":"mousemove","time":3184,"x":83,"y":96},{"type":"mousedown","time":3254,"x":83,"y":96},{"type":"mouseup","time":3358,"x":83,"y":96},{"time":3359,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":3583,"x":83,"y":96},{"type":"mousedown","time":3757,"x":83,"y":96},{"type":"mouseup","time":3843,"x":83,"y":96},{"time":3844,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":3861,"x":83,"y":97},{"type":"mousemove","time":4061,"x":77,"y":120},{"type":"mousemove","time":4267,"x":74,"y":121},{"type":"mousemove","time":4474,"x":66,"y":127},{"type":"mousedown","time":4575,"x":67,"y":126},{"type":"mousemove","time":4684,"x":74,"y":127},{"type":"mousemove","time":4884,"x":362,"y":210},{"type":"mousemove","time":5089,"x":559,"y":374},{"type":"mousemove","time":5296,"x":591,"y":435},{"type":"mousemove","time":5502,"x":591,"y":437},{"type":"mouseup","time":5712,"x":592,"y":439},{"time":5713,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":5761,"x":592,"y":439},{"type":"mousemove","time":5774,"x":591,"y":440},{"type":"mousemove","time":5977,"x":590,"y":440},{"type":"mousemove","time":6319,"x":587,"y":438},{"type":"mousemove","time":6526,"x":197,"y":166},{"type":"mousemove","time":6734,"x":117,"y":116},{"type":"mousemove","time":6934,"x":93,"y":107},{"type":"mousemove","time":7134,"x":126,"y":152},{"type":"mousemove","time":7344,"x":128,"y":158},{"type":"mousedown","time":7531,"x":128,"y":158},{"type":"mousemove","time":7541,"x":129,"y":158},{"type":"mousemove","time":7743,"x":486,"y":231},{"type":"mousemove","time":7942,"x":598,"y":355},{"type":"mousemove","time":8161,"x":622,"y":414},{"type":"mousemove","time":8362,"x":620,"y":440},{"type":"mousemove","time":8578,"x":621,"y":442},{"type":"mouseup","time":8588,"x":621,"y":442},{"time":8589,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":8668,"x":620,"y":443},{"type":"mousemove","time":8874,"x":618,"y":445},{"type":"mousemove","time":9080,"x":625,"y":449},{"type":"mousemove","time":9281,"x":628,"y":458},{"type":"mousemove","time":9493,"x":635,"y":463}],"scrollY":1834,"scrollX":0,"timestamp":1568193107991},{"name":"Action 6","ops":[{"type":"mousemove","time":479,"x":442,"y":253},{"type":"mousemove","time":679,"x":452,"y":262},{"type":"mousemove","time":883,"x":183,"y":217},{"type":"mousemove","time":1096,"x":178,"y":214},{"type":"mousemove","time":1296,"x":173,"y":236},{"type":"mousemove","time":1505,"x":175,"y":261},{"type":"mousemove","time":1724,"x":176,"y":263},{"type":"mousemove","time":1982,"x":177,"y":263},{"type":"mousemove","time":2183,"x":248,"y":197},{"type":"mousemove","time":2390,"x":238,"y":150},{"type":"mousemove","time":2597,"x":228,"y":147},{"type":"mousemove","time":2806,"x":231,"y":169},{"type":"mousemove","time":3013,"x":610,"y":212},{"type":"mousemove","time":3213,"x":631,"y":219},{"type":"mousemove","time":3423,"x":612,"y":214},{"type":"mousemove","time":3641,"x":226,"y":247},{"type":"mousemove","time":3843,"x":125,"y":419},{"type":"mousemove","time":4057,"x":137,"y":444},{"type":"mousemove","time":4262,"x":82,"y":463},{"type":"mousemove","time":4462,"x":64,"y":460},{"type":"mousemove","time":4670,"x":64,"y":460},{"type":"mousedown","time":4690,"x":64,"y":460},{"type":"mousemove","time":4879,"x":83,"y":461},{"type":"mousemove","time":5081,"x":142,"y":465},{"type":"mousemove","time":5284,"x":185,"y":471},{"type":"mousemove","time":5494,"x":191,"y":472},{"type":"mouseup","time":6256,"x":191,"y":472},{"time":6257,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":6448,"x":192,"y":472},{"type":"mousemove","time":6648,"x":234,"y":463},{"type":"mousemove","time":6860,"x":487,"y":483},{"type":"mousemove","time":7063,"x":752,"y":514},{"type":"mousemove","time":7263,"x":780,"y":464},{"type":"mousemove","time":7463,"x":772,"y":455},{"type":"mousemove","time":7672,"x":767,"y":454},{"type":"mousedown","time":7828,"x":767,"y":454},{"type":"mousemove","time":7840,"x":767,"y":454},{"type":"mousemove","time":8054,"x":730,"y":456},{"type":"mousemove","time":8258,"x":670,"y":454},{"type":"mousemove","time":8474,"x":609,"y":445},{"type":"mousemove","time":8678,"x":603,"y":443},{"type":"mouseup","time":9046,"x":603,"y":443},{"time":9047,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":9082,"x":603,"y":443},{"type":"mousemove","time":9293,"x":512,"y":482},{"type":"mousemove","time":9506,"x":428,"y":454},{"type":"mousemove","time":9724,"x":416,"y":447},{"type":"mousemove","time":9926,"x":417,"y":458},{"type":"mousedown","time":10124,"x":417,"y":458},{"type":"mousemove","time":10144,"x":417,"y":458},{"type":"mousemove","time":10346,"x":439,"y":463},{"type":"mousemove","time":10546,"x":469,"y":464},{"type":"mousemove","time":10746,"x":496,"y":460},{"type":"mousemove","time":10947,"x":502,"y":460},{"type":"mousemove","time":11164,"x":529,"y":464},{"type":"mousemove","time":11389,"x":553,"y":467},{"type":"mousemove","time":11597,"x":579,"y":469},{"type":"mousemove","time":11797,"x":606,"y":473},{"type":"mousemove","time":12008,"x":621,"y":475},{"type":"mousemove","time":12214,"x":636,"y":477},{"type":"mousemove","time":12423,"x":638,"y":477},{"type":"mouseup","time":12575,"x":638,"y":477},{"time":12576,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":12599,"x":637,"y":477},{"type":"mousemove","time":12798,"x":650,"y":468},{"type":"mousemove","time":13005,"x":670,"y":423},{"type":"mousemove","time":13224,"x":671,"y":422},{"type":"mousemove","time":13432,"x":508,"y":280},{"type":"mousemove","time":13645,"x":452,"y":287},{"type":"mousemove","time":13859,"x":450,"y":292}],"scrollY":2277,"scrollX":0,"timestamp":1568193126195},{"name":"Action 7","ops":[{"type":"mousemove","time":604,"x":273,"y":400},{"type":"mousemove","time":813,"x":291,"y":405},{"type":"mousemove","time":1039,"x":234,"y":521},{"type":"mousemove","time":1239,"x":170,"y":586},{"type":"mousemove","time":1439,"x":103,"y":586},{"type":"mousemove","time":1648,"x":50,"y":584},{"type":"mousemove","time":1856,"x":64,"y":580},{"type":"mousemove","time":2064,"x":65,"y":579},{"type":"mousedown","time":2170,"x":65,"y":578},{"type":"mousemove","time":2286,"x":69,"y":577},{"type":"mousemove","time":2486,"x":166,"y":587},{"type":"mousemove","time":2718,"x":188,"y":590},{"type":"mousemove","time":2923,"x":215,"y":594},{"type":"mousemove","time":3123,"x":264,"y":597},{"type":"mousemove","time":3333,"x":287,"y":599},{"type":"mousemove","time":3938,"x":507,"y":599},{"type":"mousemove","time":4139,"x":718,"y":595},{"type":"mousemove","time":4348,"x":767,"y":590},{"type":"mousemove","time":4555,"x":782,"y":582},{"type":"mousemove","time":4755,"x":780,"y":580},{"type":"mousemove","time":4965,"x":773,"y":577},{"type":"mousemove","time":5215,"x":769,"y":576},{"type":"mousedown","time":5251,"x":769,"y":576},{"type":"mousemove","time":5406,"x":767,"y":576},{"type":"mousemove","time":5609,"x":692,"y":573},{"type":"mousemove","time":5829,"x":643,"y":567},{"type":"mousemove","time":6036,"x":576,"y":562},{"type":"mousemove","time":6237,"x":527,"y":559},{"type":"mousemove","time":6460,"x":506,"y":558},{"type":"mousemove","time":6694,"x":503,"y":558},{"type":"mousemove","time":6973,"x":503,"y":558},{"type":"mousemove","time":7184,"x":503,"y":558},{"type":"mouseup","time":7204,"x":502,"y":557},{"time":7205,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":7395,"x":493,"y":566},{"type":"mousemove","time":7599,"x":411,"y":584},{"type":"mousemove","time":7821,"x":401,"y":581},{"type":"mousedown","time":8001,"x":401,"y":581},{"type":"mousemove","time":8160,"x":400,"y":581},{"type":"mousemove","time":8381,"x":353,"y":581},{"type":"mousemove","time":8591,"x":307,"y":577},{"type":"mousemove","time":8806,"x":258,"y":576},{"type":"mousemove","time":9006,"x":236,"y":574},{"type":"mousemove","time":9219,"x":230,"y":574},{"type":"mousemove","time":9420,"x":227,"y":573},{"type":"mousemove","time":9823,"x":226,"y":573},{"type":"mouseup","time":10934,"x":226,"y":573},{"time":10935,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":10994,"x":226,"y":573},{"type":"mousemove","time":11205,"x":229,"y":579},{"type":"mousemove","time":11428,"x":237,"y":599},{"type":"mousemove","time":11739,"x":254,"y":599},{"type":"mousemove","time":11942,"x":264,"y":587},{"type":"mousemove","time":12149,"x":270,"y":580},{"type":"mousedown","time":12483,"x":270,"y":580},{"type":"mousemove","time":12523,"x":270,"y":580},{"type":"mousemove","time":12795,"x":271,"y":580},{"type":"mousemove","time":13001,"x":310,"y":581},{"type":"mousemove","time":13206,"x":334,"y":583},{"type":"mousemove","time":13406,"x":349,"y":583},{"type":"mousemove","time":13608,"x":361,"y":583},{"type":"mousemove","time":13817,"x":373,"y":584},{"type":"mousemove","time":14273,"x":373,"y":584},{"type":"mousemove","time":14473,"x":392,"y":587},{"type":"mousemove","time":14673,"x":405,"y":588},{"type":"mouseup","time":15610,"x":405,"y":588},{"time":15611,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":15823,"x":405,"y":589},{"type":"mousemove","time":16023,"x":403,"y":597},{"type":"mousemove","time":16223,"x":401,"y":599}],"scrollY":2597,"scrollX":0,"timestamp":1568193149286}] \ No newline at end of file From ea2c006f4c3c5e11e85f2d3e540063cca7dcb5a4 Mon Sep 17 00:00:00 2001 From: pissang Date: Wed, 11 Sep 2019 20:16:04 +0800 Subject: [PATCH 092/127] test: fix some running status issue in visual regression testing tool --- package-lock.json | 359 +++++++++++++++++---------------- package.json | 17 +- test/runTest/cli.js | 4 +- test/runTest/client/client.js | 10 +- test/runTest/client/index.html | 4 +- test/runTest/server.js | 56 +++-- test/runTest/store.js | 8 +- 7 files changed, 257 insertions(+), 201 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8b995ed2cb..58127e31b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", "dev": true, "requires": { - "@babel/highlight": "7.5.0" + "@babel/highlight": "^7.0.0" } }, "@babel/core": { @@ -19,20 +19,20 @@ "integrity": "sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==", "dev": true, "requires": { - "@babel/code-frame": "7.5.5", - "@babel/generator": "7.6.0", - "@babel/helpers": "7.6.0", - "@babel/parser": "7.5.5", - "@babel/template": "7.6.0", - "@babel/traverse": "7.6.0", - "@babel/types": "7.6.1", - "convert-source-map": "1.6.0", - "debug": "4.1.1", - "json5": "2.1.0", - "lodash": "4.17.15", - "resolve": "1.12.0", - "semver": "5.7.1", - "source-map": "0.5.7" + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.3.4", + "@babel/helpers": "^7.2.0", + "@babel/parser": "^7.3.4", + "@babel/template": "^7.2.2", + "@babel/traverse": "^7.3.4", + "@babel/types": "^7.3.4", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" }, "dependencies": { "@babel/template": { @@ -41,9 +41,9 @@ "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", "dev": true, "requires": { - "@babel/code-frame": "7.5.5", - "@babel/parser": "7.6.0", - "@babel/types": "7.6.1" + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0" }, "dependencies": { "@babel/parser": { @@ -60,9 +60,9 @@ "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", "dev": true, "requires": { - "esutils": "2.0.3", - "lodash": "4.17.15", - "to-fast-properties": "2.0.0" + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" } }, "semver": { @@ -79,11 +79,11 @@ "integrity": "sha512-Ms8Mo7YBdMMn1BYuNtKuP/z0TgEIhbcyB8HVR6PPNYp4P61lMsABiS4A3VG1qznjXVCf3r+fVHhm4efTYVsySA==", "dev": true, "requires": { - "@babel/types": "7.6.1", - "jsesc": "2.5.2", - "lodash": "4.17.15", - "source-map": "0.5.7", - "trim-right": "1.0.1" + "@babel/types": "^7.6.0", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" }, "dependencies": { "@babel/types": { @@ -92,9 +92,9 @@ "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", "dev": true, "requires": { - "esutils": "2.0.3", - "lodash": "4.17.15", - "to-fast-properties": "2.0.0" + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" } } } @@ -105,9 +105,9 @@ "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "7.0.0", - "@babel/template": "7.6.0", - "@babel/types": "7.6.1" + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" }, "dependencies": { "@babel/parser": { @@ -122,9 +122,9 @@ "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", "dev": true, "requires": { - "@babel/code-frame": "7.5.5", - "@babel/parser": "7.6.0", - "@babel/types": "7.6.1" + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0" } }, "@babel/types": { @@ -133,9 +133,9 @@ "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", "dev": true, "requires": { - "esutils": "2.0.3", - "lodash": "4.17.15", - "to-fast-properties": "2.0.0" + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" } } } @@ -146,7 +146,7 @@ "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", "dev": true, "requires": { - "@babel/types": "7.6.1" + "@babel/types": "^7.0.0" }, "dependencies": { "@babel/types": { @@ -155,9 +155,9 @@ "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", "dev": true, "requires": { - "esutils": "2.0.3", - "lodash": "4.17.15", - "to-fast-properties": "2.0.0" + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" } } } @@ -169,7 +169,7 @@ "dev": true, "requires": { "@babel/types": "7.0.0-beta.31", - "lodash": "4.17.15" + "lodash": "^4.2.0" } }, "@babel/helper-module-transforms": { @@ -182,7 +182,7 @@ "@babel/helper-simple-access": "7.0.0-beta.31", "@babel/template": "7.0.0-beta.31", "@babel/types": "7.0.0-beta.31", - "lodash": "4.17.15" + "lodash": "^4.2.0" } }, "@babel/helper-simple-access": { @@ -193,7 +193,7 @@ "requires": { "@babel/template": "7.0.0-beta.31", "@babel/types": "7.0.0-beta.31", - "lodash": "4.17.15" + "lodash": "^4.2.0" } }, "@babel/helper-split-export-declaration": { @@ -202,7 +202,7 @@ "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", "dev": true, "requires": { - "@babel/types": "7.6.1" + "@babel/types": "^7.4.4" }, "dependencies": { "@babel/types": { @@ -211,9 +211,9 @@ "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", "dev": true, "requires": { - "esutils": "2.0.3", - "lodash": "4.17.15", - "to-fast-properties": "2.0.0" + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" } } } @@ -224,9 +224,9 @@ "integrity": "sha512-W9kao7OBleOjfXtFGgArGRX6eCP0UEcA2ZWEWNkJdRZnHhW4eEbeswbG3EwaRsnQUAEGWYgMq1HsIXuNNNy2eQ==", "dev": true, "requires": { - "@babel/template": "7.6.0", - "@babel/traverse": "7.6.0", - "@babel/types": "7.6.1" + "@babel/template": "^7.6.0", + "@babel/traverse": "^7.6.0", + "@babel/types": "^7.6.0" }, "dependencies": { "@babel/parser": { @@ -241,9 +241,9 @@ "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", "dev": true, "requires": { - "@babel/code-frame": "7.5.5", - "@babel/parser": "7.6.0", - "@babel/types": "7.6.1" + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0" } }, "@babel/types": { @@ -252,9 +252,9 @@ "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", "dev": true, "requires": { - "esutils": "2.0.3", - "lodash": "4.17.15", - "to-fast-properties": "2.0.0" + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" } } } @@ -265,9 +265,9 @@ "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", "dev": true, "requires": { - "chalk": "2.4.2", - "esutils": "2.0.3", - "js-tokens": "4.0.0" + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" } }, "@babel/parser": { @@ -285,7 +285,7 @@ "@babel/code-frame": "7.0.0-beta.31", "@babel/types": "7.0.0-beta.31", "babylon": "7.0.0-beta.31", - "lodash": "4.17.15" + "lodash": "^4.2.0" }, "dependencies": { "@babel/code-frame": { @@ -294,9 +294,9 @@ "integrity": "sha512-yd7CkUughvHQoEahQqcMdrZw6o/6PwUxiRkfZuVDVHCDe77mysD/suoNyk5mK6phTnRW1kyIbPHyCJgxw++LXg==", "dev": true, "requires": { - "chalk": "2.4.2", - "esutils": "2.0.3", - "js-tokens": "3.0.2" + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" } }, "js-tokens": { @@ -313,15 +313,15 @@ "integrity": "sha512-93t52SaOBgml/xY74lsmt7xOR4ufYvhb5c5qiM6lu4J/dWGMAfAh6eKw4PjLes6DI6nQgearoxnFJk60YchpvQ==", "dev": true, "requires": { - "@babel/code-frame": "7.5.5", - "@babel/generator": "7.6.0", - "@babel/helper-function-name": "7.1.0", - "@babel/helper-split-export-declaration": "7.4.4", - "@babel/parser": "7.6.0", - "@babel/types": "7.6.1", - "debug": "4.1.1", - "globals": "11.12.0", - "lodash": "4.17.15" + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.6.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" }, "dependencies": { "@babel/parser": { @@ -336,9 +336,9 @@ "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", "dev": true, "requires": { - "esutils": "2.0.3", - "lodash": "4.17.15", - "to-fast-properties": "2.0.0" + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" } } } @@ -349,9 +349,9 @@ "integrity": "sha512-exAHB+NeFGxkfQ5dSUD03xl3zYGneeSk2Mw2ldTt/nTvYxuDiuSp3DlxgUBgzbdTFG4fbwPk0WtKWOoTXCmNGg==", "dev": true, "requires": { - "esutils": "2.0.3", - "lodash": "4.17.15", - "to-fast-properties": "2.0.0" + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^2.0.0" } }, "accepts": { @@ -360,7 +360,7 @@ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "dev": true, "requires": { - "mime-types": "2.1.24", + "mime-types": "~2.1.24", "negotiator": "0.6.2" }, "dependencies": { @@ -406,7 +406,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.3" + "color-convert": "^1.9.0" } }, "arraybuffer.slice": { @@ -481,7 +481,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -526,9 +526,9 @@ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "color-convert": { @@ -588,7 +588,7 @@ "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", "dev": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.1" } }, "cookie": { @@ -609,7 +609,7 @@ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "ms": "2.1.2" + "ms": "^2.1.1" } }, "deep-is": { @@ -624,12 +624,12 @@ "integrity": "sha512-AsaA9KG7cWPXWHp5FvHdDWY3AMWeZ8x+2pUVLcn71qE5AtAzgGbxuclOytygskw8XGmiQafTmnI9Bix3uihu2w==", "dev": true, "requires": { - "accepts": "1.3.7", + "accepts": "~1.3.4", "base64id": "1.0.0", "cookie": "0.3.1", - "debug": "3.1.0", - "engine.io-parser": "2.1.3", - "ws": "6.1.4" + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~6.1.0" }, "dependencies": { "debug": { @@ -657,14 +657,14 @@ "requires": { "component-emitter": "1.2.1", "component-inherit": "0.0.3", - "debug": "3.1.0", - "engine.io-parser": "2.1.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", "has-cors": "1.1.0", "indexof": "0.0.1", "parseqs": "0.0.5", "parseuri": "0.0.5", - "ws": "6.1.4", - "xmlhttprequest-ssl": "1.5.5", + "ws": "~6.1.0", + "xmlhttprequest-ssl": "~1.5.4", "yeast": "0.1.2" }, "dependencies": { @@ -692,10 +692,10 @@ "dev": true, "requires": { "after": "0.8.2", - "arraybuffer.slice": "0.0.7", + "arraybuffer.slice": "~0.0.7", "base64-arraybuffer": "0.1.5", "blob": "0.0.5", - "has-binary2": "1.0.3" + "has-binary2": "~1.0.2" } }, "escape-string-regexp": { @@ -710,11 +710,11 @@ "integrity": "sha1-skaq6CnOc9WeLFVyc1nt0cEwqBs=", "dev": true, "requires": { - "esprima": "2.7.2", - "estraverse": "1.9.3", - "esutils": "2.0.3", - "optionator": "0.8.2", - "source-map": "0.2.0" + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" }, "dependencies": { "estraverse": { @@ -730,7 +730,7 @@ "dev": true, "optional": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -771,7 +771,7 @@ "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=", "dev": true, "requires": { - "punycode": "1.4.1" + "punycode": "^1.3.2" } }, "fs-extra": { @@ -780,11 +780,11 @@ "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", "dev": true, "requires": { - "graceful-fs": "4.2.2", - "jsonfile": "2.4.0", - "klaw": "1.3.1", - "path-is-absolute": "1.0.1", - "rimraf": "2.7.1" + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" } }, "fs.realpath": { @@ -799,11 +799,11 @@ "integrity": "sha1-OyCjV//89GuzhK7W+K6aZH/basQ=", "dev": true, "requires": { - "inflight": "1.0.6", - "inherits": "2.0.1", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "globals": { @@ -851,8 +851,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -867,6 +867,12 @@ "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", "dev": true }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, "isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", @@ -891,7 +897,7 @@ "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", "dev": true, "requires": { - "minimist": "1.2.0" + "minimist": "^1.2.0" } }, "jsonfile": { @@ -900,7 +906,7 @@ "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { - "graceful-fs": "4.2.2" + "graceful-fs": "^4.1.6" } }, "klaw": { @@ -909,7 +915,7 @@ "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", "dev": true, "requires": { - "graceful-fs": "4.2.2" + "graceful-fs": "^4.1.9" } }, "levn": { @@ -918,8 +924,8 @@ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, "lodash": { @@ -934,7 +940,7 @@ "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", "dev": true, "requires": { - "vlq": "0.2.3" + "vlq": "^0.2.2" } }, "mime-db": { @@ -949,7 +955,7 @@ "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "dev": true, "requires": { - "mime-db": "1.33.0" + "mime-db": "~1.33.0" } }, "minimatch": { @@ -958,7 +964,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -991,7 +997,16 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" + } + }, + "open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" } }, "optionator": { @@ -1000,12 +1015,12 @@ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" } }, "parseqs": { @@ -1014,7 +1029,7 @@ "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", "dev": true, "requires": { - "better-assert": "1.0.2" + "better-assert": "~1.0.0" } }, "parseuri": { @@ -1023,7 +1038,7 @@ "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", "dev": true, "requires": { - "better-assert": "1.0.2" + "better-assert": "~1.0.0" } }, "path-is-absolute": { @@ -1056,7 +1071,7 @@ "integrity": "sha512-b65UpTI40rGFY8QwN6IYuCbpmwAOL6M8d6voX4F3zR99UmDqh7r2QWLxoeHOazBRgEmDUdqNVESDREqFxQS7rQ==", "dev": true, "requires": { - "pngjs": "3.4.0" + "pngjs": "^3.4.0" } }, "pngjs": { @@ -1089,7 +1104,7 @@ "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", "dev": true, "requires": { - "path-parse": "1.0.6" + "path-parse": "^1.0.6" } }, "rimraf": { @@ -1098,7 +1113,7 @@ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "requires": { - "glob": "7.1.4" + "glob": "^7.1.3" }, "dependencies": { "glob": { @@ -1107,12 +1122,12 @@ "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.1", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } @@ -1129,11 +1144,11 @@ "integrity": "sha512-mg+WuD+jlwoo8bJtW3Mvx7Tz6TsIdMsdhuvCnDMoyjh0oxsVgsjB/N0X984RJCWwc5IIiqNVJhXeeITcc73++A==", "dev": true, "requires": { - "acorn": "5.7.3", - "estree-walker": "0.5.2", - "magic-string": "0.22.5", - "resolve": "1.12.0", - "rollup-pluginutils": "2.8.1" + "acorn": "^5.2.1", + "estree-walker": "^0.5.0", + "magic-string": "^0.22.4", + "resolve": "^1.4.0", + "rollup-pluginutils": "^2.0.1" } }, "rollup-plugin-node-resolve": { @@ -1142,10 +1157,10 @@ "integrity": "sha1-i4l8TDAw1QASd7BRSyXSygloPuA=", "dev": true, "requires": { - "browser-resolve": "1.11.3", - "builtin-modules": "1.1.1", - "is-module": "1.0.0", - "resolve": "1.12.0" + "browser-resolve": "^1.11.0", + "builtin-modules": "^1.1.0", + "is-module": "^1.0.0", + "resolve": "^1.1.6" } }, "rollup-plugin-uglify": { @@ -1154,7 +1169,7 @@ "integrity": "sha1-Z7N60e/a+9g69MNrQMGJ7khmyWk=", "dev": true, "requires": { - "uglify-js": "3.6.0" + "uglify-js": "^3.0.9" } }, "rollup-pluginutils": { @@ -1163,7 +1178,7 @@ "integrity": "sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg==", "dev": true, "requires": { - "estree-walker": "0.6.1" + "estree-walker": "^0.6.1" }, "dependencies": { "estree-walker": { @@ -1209,9 +1224,9 @@ } }, "slugify": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.5.tgz", - "integrity": "sha512-5VCnH7aS13b0UqWOs7Ef3E5rkhFe8Od+cp7wybFv5mv/sYSRkucZlJX0bamAJky7b2TTtGvrJBWVdpdEicsSrA==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.4.tgz", + "integrity": "sha512-KP0ZYk5hJNBS8/eIjGkFDCzGQIoZ1mnfQRYS5WM3273z+fxGWXeN0fkwf2ebEweydv9tioZIHGZKoF21U07/nw==", "dev": true }, "socket.io": { @@ -1220,12 +1235,12 @@ "integrity": "sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w==", "dev": true, "requires": { - "debug": "4.1.1", - "engine.io": "3.3.2", - "has-binary2": "1.0.3", - "socket.io-adapter": "1.1.1", + "debug": "~4.1.0", + "engine.io": "~3.3.1", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", "socket.io-client": "2.2.0", - "socket.io-parser": "3.3.0" + "socket.io-parser": "~3.3.0" } }, "socket.io-adapter": { @@ -1244,15 +1259,15 @@ "base64-arraybuffer": "0.1.5", "component-bind": "1.0.0", "component-emitter": "1.2.1", - "debug": "3.1.0", - "engine.io-client": "3.3.2", - "has-binary2": "1.0.3", + "debug": "~3.1.0", + "engine.io-client": "~3.3.1", + "has-binary2": "~1.0.2", "has-cors": "1.1.0", "indexof": "0.0.1", "object-component": "0.0.3", "parseqs": "0.0.5", "parseuri": "0.0.5", - "socket.io-parser": "3.3.0", + "socket.io-parser": "~3.3.0", "to-array": "0.1.4" }, "dependencies": { @@ -1280,7 +1295,7 @@ "dev": true, "requires": { "component-emitter": "1.2.1", - "debug": "3.1.0", + "debug": "~3.1.0", "isarray": "2.0.1" }, "dependencies": { @@ -1313,7 +1328,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "to-array": { @@ -1340,7 +1355,7 @@ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "prelude-ls": "~1.1.2" } }, "uglify-js": { @@ -1349,8 +1364,8 @@ "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", "dev": true, "requires": { - "commander": "2.20.0", - "source-map": "0.6.1" + "commander": "~2.20.0", + "source-map": "~0.6.1" }, "dependencies": { "commander": { @@ -1400,7 +1415,7 @@ "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", "dev": true, "requires": { - "async-limiter": "1.0.1" + "async-limiter": "~1.0.0" } }, "xmlhttprequest-ssl": { diff --git a/package.json b/package.json index 9b61471db8..3efacc5f28 100644 --- a/package.json +++ b/package.json @@ -34,16 +34,17 @@ "estraverse": "4.1.1", "fs-extra": "0.26.7", "glob": "7.0.0", - "pixelmatch": "^5.0.2", - "pngjs": "^3.4.0", + "open": "6.4.0", + "pixelmatch": "5.0.2", + "pngjs": "3.4.0", "rollup": "0.50.0", - "rollup-plugin-commonjs": "^8.4.1", + "rollup-plugin-commonjs": "8.4.1", "rollup-plugin-node-resolve": "3.0.0", "rollup-plugin-uglify": "2.0.1", - "seedrandom": "^3.0.3", - "semver": "^6.3.0", - "serve-handler": "^6.1.1", - "slugify": "^1.3.4", - "socket.io": "^2.2.0" + "seedrandom": "3.0.3", + "semver": "6.3.0", + "serve-handler": "6.1.1", + "slugify": "1.3.4", + "socket.io": "2.2.0" } } diff --git a/test/runTest/cli.js b/test/runTest/cli.js index ffd133dcaa..1bda32358c 100644 --- a/test/runTest/cli.js +++ b/test/runTest/cli.js @@ -63,7 +63,7 @@ function getClientRelativePath(absPath) { function replaceEChartsVersion(interceptedRequest, version) { // TODO Extensions and maps if (interceptedRequest.url().endsWith('dist/echarts.js')) { - console.log(getVersionDir(version)); + console.log('Use echarts version: ' + getVersionDir(version)); interceptedRequest.continue({ url: `${origin}/test/runTest/${getVersionDir(version)}/echarts.js` }); @@ -269,6 +269,6 @@ runTests(program.tests.split(',').map(testName => { fileUrl: fileNameFromTest(testName), name: testName, results: [], - status: 'unsettled' + status: 'pending' }; })); \ No newline at end of file diff --git a/test/runTest/client/client.js b/test/runTest/client/client.js index 7f644eda2f..463b78876a 100644 --- a/test/runTest/client/client.js +++ b/test/runTest/client/client.js @@ -258,7 +258,7 @@ socket.on('update', msg => { }).catch(() => {}); } // TODO - // app.running = !!msg.running; + app.running = !!msg.running; app.fullTests = processTestsData(msg.tests, app.fullTests); firstUpdate = false; @@ -274,6 +274,14 @@ socket.on('finish', res => { console.log(`${res.count} test complete, Cost: ${(res.time / 1000).toFixed(1)} s. Threads: ${res.threads}`); app.running = false; }); +socket.on('abort', res => { + app.$notify({ + type: 'info', + title: `Aborted`, + duration: 4000 + }); + app.running = false; +}); socket.on('versions', versions => { app.versions = versions.filter(version => { return !version.startsWith('2.') diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html index 4b1f8d0a98..2b7fcee384 100644 --- a/test/runTest/client/index.html +++ b/test/runTest/client/index.html @@ -24,6 +24,8 @@ + + Visual Regression Testing Tool
- Version + Version Expected Visual Regression Testing Tool
+
+ Renderer + + + + +
diff --git a/test/runTest/server.js b/test/runTest/server.js index 2a35c8e028..554f591de8 100644 --- a/test/runTest/server.js +++ b/test/runTest/server.js @@ -77,17 +77,11 @@ class Thread { this.onUpdate; } - fork(noHeadless, replaySpeed, actualVersion, expectedVersion) { + fork(extraArgs) { let p = fork(path.join(__dirname, 'cli.js'), [ '--tests', this.tests.map(testOpt => testOpt.name).join(','), - '--speed', - replaySpeed || 5, - '--actual', - actualVersion, - '--expected', - expectedVersion, - ...(noHeadless ? ['--no-headless'] : []) + ...extraArgs ]); this.p = p; @@ -116,7 +110,8 @@ function startTests(testsNameList, socket, { threadsCount, replaySpeed, actualVersion, - expectedVersion + expectedVersion, + renderer }) { console.log('Received: ', testsNameList.join(',')); @@ -160,7 +155,13 @@ function startTests(testsNameList, socket, { for (let i = 0; i < threadsCount; i++) { runningThreads[i].onExit = onExit; runningThreads[i].onUpdate = onUpdate; - runningThreads[i].fork(noHeadless, replaySpeed, actualVersion, expectedVersion); + runningThreads[i].fork([ + '--speed', replaySpeed || 5, + '--actual', actualVersion, + '--expected', expectedVersion, + '--renderer', renderer, + ...(noHeadless ? ['--no-headless'] : []) + ]); runningCount++; } // If something bad happens and no proccess are started successfully @@ -228,7 +229,8 @@ async function start() { threadsCount: data.threads, replaySpeed: data.replaySpeed, actualVersion: data.actualVersion, - expectedVersion: data.expectedVersion + expectedVersion: data.expectedVersion, + renderer: data.renderer } ); } @@ -289,7 +291,8 @@ async function start() { threadsCount: 1, replaySpeed: 2, actualVersion: data.actualVersion, - expectedVersion: data.expectedVersion + expectedVersion: data.expectedVersion, + renderer: data.renderer }); } catch (e) { console.error(e); } diff --git a/test/runTest/store.js b/test/runTest/store.js index 406a3c6374..93e78567da 100644 --- a/test/runTest/store.js +++ b/test/runTest/store.js @@ -23,11 +23,41 @@ const fs = require('fs'); const glob = require('glob'); const {testNameFromFile} = require('./util'); const util = require('util'); -const blacklist = require('./blacklist'); +const {blacklist, SVGBlacklist} = require('./blacklist'); let _tests = []; let _testsMap = {}; +class Test { + constructor(fileUrl) { + this.fileUrl = fileUrl; + this.name = testNameFromFile(fileUrl); + + // If this test case ignore svg testing. + this.ignoreSVG = false; + + this.status = 'unsettled'; + + // Run results + this.results = []; // Screenshots + + this.actualLogs = []; + this.expectedLogs = []; + this.actualErrors = []; + this.expectedErrors = []; + + // Use echarts versions. + this.actualVersion = null; + this.expectedVersion = null; + + // Last timestamp + this.lastRun = 0; + + // Use SVG + this.useSVG = false; + } +} + function getCacheFilePath() { return path.join(__dirname, 'tmp/__cache__.json');; } @@ -72,13 +102,8 @@ module.exports.updateTestsList = async function (setPendingTestToUnsettled) { return; } - let test = { - fileUrl, - name: testNameFromFile(fileUrl), - // Default status should be unkown - // status: 'pending', - results: [] - }; + let test = new Test(fileUrl); + test.ignoreSVG = SVGBlacklist.includes(fileUrl); _tests.push(test); _testsMap[fileUrl] = test; From 04eefd52a7e5e80061d182b8320f72824b071a9e Mon Sep 17 00:00:00 2001 From: pissang Date: Wed, 11 Sep 2019 22:48:42 +0800 Subject: [PATCH 095/127] test: add test preview for screenshot. --- test/lib/config.js | 24 +++++++++++++------ test/runTest/blacklist.js | 3 +++ test/runTest/cli.js | 2 +- test/runTest/client/client.css | 13 ++++++++++ test/runTest/client/client.js | 23 ++++++++++++++++++ test/runTest/client/index.html | 44 ++++++++++++++-------------------- 6 files changed, 75 insertions(+), 34 deletions(-) diff --git a/test/lib/config.js b/test/lib/config.js index 5409c4ad2a..9b04aa0c44 100644 --- a/test/lib/config.js +++ b/test/lib/config.js @@ -25,22 +25,32 @@ // `true` by default for debugging. sourceMap == null && (sourceMap = true); + var params = {}; + location.search.slice(1).split('&').forEach(item => { + var kv = item.split('='); + params[kv[0]] = kv[1]; + }); // Set default renderer in dev mode from hash. - var matchResult = location.href.match(/[?&]__RENDERER__=(canvas|svg)(&|$)/); - if (matchResult) { - window.__ECHARTS__DEFAULT__RENDERER__ = matchResult[1]; + if (params.__RENDERER__) { + window.__ECHARTS__DEFAULT__RENDERER__ = params.__RENDERER__; } // Set echarts source code. - var matchResult = location.href.match(/[?&]__ECDIST__=(webpack-req-ec|webpack-req-eclibec|webpackold-req-ec|webpackold-req-eclibec)(&|$)/); - var ecDistPath = 'dist/echarts'; - if (matchResult) { + var ecDistPath; + if (params.__ECDIST__) { ecDistPath = ({ 'webpack-req-ec': '../echarts-boilerplate/echarts-webpack/dist/webpack-req-ec', 'webpack-req-eclibec': '../echarts-boilerplate/echarts-webpack/dist/webpack-req-eclibec', 'webpackold-req-ec': '../echarts-boilerplate/echarts-webpackold/dist/webpackold-req-ec', 'webpackold-req-eclibec': '../echarts-boilerplate/echarts-webpackold/dist/webpackold-req-eclibec', - })[matchResult[1]]; + })[params.__ECDIST__]; + if (!ecDistPath && params.__ECDIST__.match(/[0-9.]/)) { + // Version number + ecDistPath = 'test/runTest/tmp/__version__/' + params.__ECDIST__ + '/echarts'; + } + } + if (!ecDistPath) { + ecDistPath = 'dist/echarts'; } if (typeof require !== 'undefined') { diff --git a/test/runTest/blacklist.js b/test/runTest/blacklist.js index a405b0b5a4..86da51abcc 100644 --- a/test/runTest/blacklist.js +++ b/test/runTest/blacklist.js @@ -31,6 +31,9 @@ module.exports.blacklist = [ 'scatter-gps.html', 'webkit-dep.html', + // Image size not match + 'symbol2.html', + // This case will have timeout 'visualMap-performance1.html', 'lines-bus.html', diff --git a/test/runTest/cli.js b/test/runTest/cli.js index d027e0c168..a0940d4914 100644 --- a/test/runTest/cli.js +++ b/test/runTest/cli.js @@ -162,7 +162,7 @@ async function runTestPage(browser, testOpt, version, runtimeCode, isExpected) { timeout: 10000 }); - await waitTime(200); // Wait for animation or something else. Pending + await waitTime(500); // Wait for animation or something else. Pending // Final shot. await page.mouse.move(0, 0); let desc = 'Full Shot'; diff --git a/test/runTest/client/client.css b/test/runTest/client/client.css index 1dc5484820..8a2c5984cf 100644 --- a/test/runTest/client/client.css +++ b/test/runTest/client/client.css @@ -170,6 +170,14 @@ margin-top: 60px; } +.test-screenshots .preview { + cursor: pointer; + color: #409eff; +} +.test-screenshots .preview:hover { + text-decoration: underline; +} + .test-screenshots img { /* height: 200px; */ width: 100%; @@ -196,6 +204,11 @@ color: #f56c6c } +iframe { + border: none; + overflow: overlay; +} + ::-webkit-scrollbar { height: 8px; diff --git a/test/runTest/client/client.js b/test/runTest/client/client.js index 9ad2d3976f..d57457430f 100644 --- a/test/runTest/client/client.js +++ b/test/runTest/client/client.js @@ -70,6 +70,10 @@ const app = new Vue({ versions: [], + showIframeDialog: false, + previewIframeSrc: '', + previewTitle: '', + runConfig: { noHeadless: false, replaySpeed: 5, @@ -207,6 +211,25 @@ const app = new Vue({ stopTests() { this.running = false; socket.emit('stop'); + }, + + preview(test, version) { + let searches = []; + + let ecVersion = test[version + 'Version']; + if (ecVersion !== 'local') { + searches.push('__ECDIST__=' + ecVersion); + } + if (test.useSVG) { + searches.push('__RENDERER__=svg'); + } + let src = test.fileUrl; + if (searches.length) { + src = src + '?' + searches.join('&'); + } + this.previewIframeSrc = `../../${src}`; + this.previewTitle = src; + this.showIframeDialog = true; } } }); diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html index 51573fc16a..b0770702ad 100644 --- a/test/runTest/client/index.html +++ b/test/runTest/client/index.html @@ -175,8 +175,9 @@

Expected - {{currentTest.expectedVersion || ''}} +
- + @@ -184,8 +185,9 @@

Actual - {{currentTest.actualVersion || ''}} +
- + @@ -194,7 +196,7 @@

Diff - {{result.diffRatio.toFixed(4)}}

- + @@ -203,19 +205,11 @@

- - +
{{error}}
- - +
{{error}}
@@ -224,28 +218,26 @@

- - +
{{log}}
- +
{{log}}
- -
- -
+ + + + From 1e3a730f5d252d8db014a52c8818bf727b475e0e Mon Sep 17 00:00:00 2001 From: pissang Date: Thu, 12 Sep 2019 17:05:02 +0800 Subject: [PATCH 096/127] test: add --no-save in the puppeteer install hint. add preview dialog. --- .github/CONTRIBUTING.md | 2 +- test/runTest/client/index.html | 5 ++++- test/runTest/server.js | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index f8912b8299..f22526bf75 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -107,7 +107,7 @@ Then, open the test cases under `~/workspace/echarts/test` in Web browser. You c ```bash # puppeteer is not in the devDependencies and needs to be installed manually -npm install puppeteer +npm install puppeteer --no-save npm run test:visual ``` diff --git a/test/runTest/client/index.html b/test/runTest/client/index.html index b0770702ad..2d94b979c4 100644 --- a/test/runTest/client/index.html +++ b/test/runTest/client/index.html @@ -233,9 +233,12 @@

+
+ {{previewTitle}} + Open in New Window +
diff --git a/test/runTest/server.js b/test/runTest/server.js index 554f591de8..565cb2195e 100644 --- a/test/runTest/server.js +++ b/test/runTest/server.js @@ -184,7 +184,7 @@ function checkPuppeteer() { async function start() { if (!checkPuppeteer()) { // TODO Check version. - console.error(`Can't find puppeteer >= 1.19.0, use 'npm install puppeteer' to install or update`); + console.error(`Can't find puppeteer >= 1.19.0, use 'npm install puppeteer --no-save' to install or update`); return; } From 1cdcb87db21bbd1aac5a99a2885eb478eb2dd713 Mon Sep 17 00:00:00 2001 From: sushuang Date: Thu, 12 Sep 2019 21:55:04 +0800 Subject: [PATCH 097/127] fix(build): add more instructions about "how to build source code". --- README.md | 29 +++++++++++++++++++++++++++-- package.json | 3 +++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ebcb9fd320..bb2fddd4e8 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,33 @@ ECharts-GL is an extension pack of ECharts, which provides 3D plots, globe visua ## Build -Check this tutorial [Create Custom Build of ECharts](https://echarts.apache.org/en/tutorial.html#Create%20Custom%20Build%20of%20ECharts) - please. +Build echarts source code: + +Execute the instructions in the root directory of the echarts: +([Node.js](https://nodejs.org) is required) + +```shell +# Install the dependencies from NPM: +npm install + +# If intending to build and get all types of the "production" files: +node build/build.js --release + +# If only intending to get `dist/echarts.js`, which is usually +# enough in dev or running the tests: +node build/build.js + +# Get the same "production" files as `node build/build.js`, while +# watching the editing of the source code. Usually used in dev. +node build/build.js -w + +# Check the manual: +node build/build.js --help +``` + +Then the "production" files are generated in `dist` directory. + +More custom build approaches can be checked in this tutorial: [Create Custom Build of ECharts](https://echarts.apache.org/en/tutorial.html#Create%20Custom%20Build%20of%20ECharts) please. ## Contribution diff --git a/package.json b/package.json index 3efacc5f28..acd9c4b92a 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,9 @@ "url": "https://github.com/apache/incubator-echarts.git" }, "scripts": { + "build": "node build/build.js", + "build:watch": "node build/build.js -w", + "build:release": "node build/build.js --release", "prepublish": "node build/build.js --prepublish", "test:visual": "node test/runTest/server.js", "test": "node build/build.js" From 4f21665571802196c5000ea8989b55d67b99f15e Mon Sep 17 00:00:00 2001 From: sushuang Date: Thu, 12 Sep 2019 23:16:10 +0800 Subject: [PATCH 098/127] fix(build): tweak the npm run instructions and readme --- .github/CONTRIBUTING.md | 14 +- README.md | 12 +- package-lock.json | 888 +++++++++++++++++++++++++++++++++++++--- package.json | 13 +- 4 files changed, 866 insertions(+), 61 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index f22526bf75..ec6b8837ca 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -113,7 +113,19 @@ npm run test:visual It will run all the test cases under `~/workspace/echarts/test` automatically to compare with the previous version. You can use this to check if your code bring some breaking change. -### 5. Make a pull request +### 5. Check the code style + +The code style should follow the [Code Standard](https://echarts.apache.org/en/coding-standard.html). + +It is recommanded to install [eslint](https://eslint.org) plugin to in your IDE to find the invalid code style. +Otherwise, we can also use +```bash +npm run lint +``` +to check the the code style. + + +### 6. Make a pull request Fork ECharts project into your own project. Checkout a branch from master branch named `fix-xxxx`, where xxxx is the issue id related. If there's no related issue, you need to create one in most cases to describe what's wrong or what new feature is required. diff --git a/README.md b/README.md index bb2fddd4e8..e140c91863 100644 --- a/README.md +++ b/README.md @@ -62,18 +62,22 @@ Execute the instructions in the root directory of the echarts: npm install # If intending to build and get all types of the "production" files: -node build/build.js --release +npm run release +# The same as `node build/build.js --release` # If only intending to get `dist/echarts.js`, which is usually # enough in dev or running the tests: -node build/build.js +npm run build +# The same as `node build/build.js` # Get the same "production" files as `node build/build.js`, while # watching the editing of the source code. Usually used in dev. -node build/build.js -w +npm run watch +# The same as `node build/build.js -w` # Check the manual: -node build/build.js --help +npm run help +# The same as `node build/build.js --help` ``` Then the "production" files are generated in `dist` directory. diff --git a/package-lock.json b/package-lock.json index 58127e31b3..a8174d5f4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,6 @@ "version": "7.5.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", - "dev": true, "requires": { "@babel/highlight": "^7.0.0" } @@ -263,7 +262,6 @@ "version": "7.5.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", - "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", @@ -387,12 +385,28 @@ "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", "dev": true }, + "acorn-jsx": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz", + "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==" + }, "after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", "dev": true }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", @@ -400,15 +414,32 @@ "dev": true, "optional": true }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", @@ -424,6 +455,11 @@ "util": "0.10.3" } }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" + }, "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", @@ -445,8 +481,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "base64-arraybuffer": { "version": "0.1.5", @@ -479,7 +514,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -520,22 +554,69 @@ "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", "dev": true }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, + "cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "dev": true, + "requires": { + "exit": "0.1.2", + "glob": "^7.1.1" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -543,8 +624,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "commander": { "version": "2.11.0", @@ -573,8 +653,16 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } }, "content-disposition": { "version": "0.5.2", @@ -603,11 +691,41 @@ "integrity": "sha1-Cptp0SEA7Jf2+TgaJL5RBNNOnvk=", "dev": true }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, "requires": { "ms": "^2.1.1" } @@ -615,9 +733,70 @@ "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-serializer": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.1.tgz", + "integrity": "sha512-sK3ujri04WyjwQXVoK4PU3y8ula1stq10GJZpqHIUgoGZdsGzAGu65BnU3d08aTVSvO7mGPZUc0wTEDL+qGE0Q==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", + "dev": true + }, + "entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", + "dev": true + } + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", "dev": true }, + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, "engine.io": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.3.2.tgz", @@ -698,11 +877,16 @@ "has-binary2": "~1.0.2" } }, + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { "version": "1.8.0", @@ -735,17 +919,122 @@ } } }, + "eslint": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.3.0.tgz", + "integrity": "sha512-ZvZTKaqDue+N8Y9g0kp6UPZtS4FSY3qARxBs7p4f0H0iof381XHduqVerFWtK8DPtKmemqbqCFENWSQgPR/Gow==", + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.2", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.4.1", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "strip-json-comments": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==" + } + } + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", + "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", + "requires": { + "eslint-visitor-keys": "^1.0.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==" + }, + "espree": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz", + "integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==", + "requires": { + "acorn": "^7.0.0", + "acorn-jsx": "^5.0.2", + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "acorn": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.0.0.tgz", + "integrity": "sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ==" + } + } + }, "esprima": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz", "integrity": "sha1-9DvlQ2CZhOrkTJM6xjNSpq818zk=", "dev": true }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "requires": { + "estraverse": "^4.1.0" + } + }, "estraverse": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz", - "integrity": "sha1-9srKcokzqFDvkGYdDheYK6RxEaI=", - "dev": true + "integrity": "sha1-9srKcokzqFDvkGYdDheYK6RxEaI=" }, "estree-walker": { "version": "0.5.2", @@ -756,14 +1045,38 @@ "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, "fast-url-parser": { "version": "1.1.3", @@ -774,6 +1087,60 @@ "punycode": "^1.3.2" } }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==" + }, "fs-extra": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", @@ -790,8 +1157,12 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" }, "glob": { "version": "7.0.0", @@ -806,11 +1177,18 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", + "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "requires": { + "is-glob": "^4.0.1" + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, "graceful-fs": { "version": "4.2.2", @@ -836,8 +1214,47 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "dev": true, + "requires": { + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + }, + "import-fresh": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", + "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, "indexof": { "version": "0.0.1", @@ -849,7 +1266,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -858,8 +1274,45 @@ "inherits": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } }, "is-module": { "version": "1.0.0", @@ -867,6 +1320,11 @@ "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", "dev": true }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, "is-wsl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", @@ -879,11 +1337,31 @@ "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", "dev": true }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + } + } }, "jsesc": { "version": "2.5.2", @@ -891,6 +1369,32 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "jshint": { + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.10.2.tgz", + "integrity": "sha512-e7KZgCSXMJxznE/4WULzybCMNXNAd/bf5TSrvVEq78Q/K8ZwFpmBqQeDtNiHc3l49nV4E/+YeHU/JZjSUIrLAA==", + "dev": true, + "requires": { + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "~4.17.11", + "minimatch": "~3.0.2", + "shelljs": "0.3.x", + "strip-json-comments": "1.0.x" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, "json5": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", @@ -922,7 +1426,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, "requires": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" @@ -931,8 +1434,7 @@ "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, "magic-string": { "version": "0.22.5", @@ -958,11 +1460,15 @@ "mime-db": "~1.33.0" } }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -973,11 +1479,35 @@ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" }, "negotiator": { "version": "0.6.2", @@ -985,6 +1515,11 @@ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", "dev": true }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, "object-component": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", @@ -995,11 +1530,18 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "^1.0.0" + } + }, "open": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", @@ -1013,7 +1555,6 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, "requires": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.4", @@ -1023,6 +1564,19 @@ "wordwrap": "~1.0.0" } }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, "parseqs": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", @@ -1044,8 +1598,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", @@ -1053,6 +1606,11 @@ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", @@ -1083,8 +1641,12 @@ "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" }, "punycode": { "version": "1.4.1", @@ -1098,6 +1660,31 @@ "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", "dev": true }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + } + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==" + }, "resolve": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", @@ -1107,6 +1694,20 @@ "path-parse": "^1.0.6" } }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -1189,12 +1790,33 @@ } } }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "requires": { + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "seedrandom": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.3.tgz", @@ -1204,8 +1826,7 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, "serve-handler": { "version": "6.1.1", @@ -1223,6 +1844,40 @@ "range-parser": "1.2.0" } }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + } + }, "slugify": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.4.tgz", @@ -1322,15 +1977,106 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + } + } + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", @@ -1349,11 +2095,15 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "dev": true }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, "requires": { "prelude-ls": "~1.1.2" } @@ -1382,6 +2132,21 @@ } } }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } + } + }, "util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", @@ -1391,23 +2156,42 @@ "inherits": "2.0.1" } }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==" + }, "vlq": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", "dev": true }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "requires": { + "mkdirp": "^0.5.1" + } }, "ws": { "version": "6.1.4", diff --git a/package.json b/package.json index acd9c4b92a..3b180de526 100644 --- a/package.json +++ b/package.json @@ -13,12 +13,15 @@ "url": "https://github.com/apache/incubator-echarts.git" }, "scripts": { + "release": "node build/build.js --release", "build": "node build/build.js", - "build:watch": "node build/build.js -w", - "build:release": "node build/build.js --release", + "watch": "node build/build.js -w", + "help": "node build/build.js --help", "prepublish": "node build/build.js --prepublish", "test:visual": "node test/runTest/server.js", - "test": "node build/build.js" + "test": "node build/build.js", + "lint": "./node_modules/.bin/eslint src extension-src", + "lint:dist": "echo 'It might take a while. Please wait ...' && ./node_modules/.bin/jshint --config .jshintrc-dist dist/echarts.js" }, "dependencies": { "zrender": "4.0.7" @@ -48,6 +51,8 @@ "semver": "6.3.0", "serve-handler": "6.1.1", "slugify": "1.3.4", - "socket.io": "2.2.0" + "socket.io": "2.2.0", + "jshint": "2.10.2", + "eslint": "6.3.0" } } From b9fbe74b9fc6db1fa84a590da750b4cd2fc7d6bb Mon Sep 17 00:00:00 2001 From: pissang Date: Mon, 16 Sep 2019 15:30:25 +0800 Subject: [PATCH 099/127] chore: move contributing.md to the root. --- .github/CONTRIBUTING.md => CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/CONTRIBUTING.md => CONTRIBUTING.md (96%) diff --git a/.github/CONTRIBUTING.md b/CONTRIBUTING.md similarity index 96% rename from .github/CONTRIBUTING.md rename to CONTRIBUTING.md index ec6b8837ca..af1a1f7762 100644 --- a/.github/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,7 +20,7 @@ We will start the discussion about the bugs to fix and features of each release About our release plan, we will release a mior version at the end of every month. Here is some detail. -1. Assume our current stable release is 4.3.0. We will start the discussion of milestone of the release two ahead, which is 4.5.0 at the beginning of each month. At this time we should also kickoff the developing of the next release, which is 4.4.0. +1. Assume our current stable release is 4.3.0. We will start the discussion of milestone of the release two versions ahead, which is 4.5.0 at the beginning of each month. At this time we should also kickoff the developing of the next release, which is 4.4.0. 2. Finish 4.4.0 developing at about 22th of this month and start the testing. And the 4.5.0 milestone discussion is frozen and published on the [GitHub](https://github.com/apache/incubator-echarts/milestone/14) 3. Vote in the mailing list for the 4.4.0 release at the end of this month. From 0b2b5e65b9d7b56a8bcac80a4d795aef8d097fa7 Mon Sep 17 00:00:00 2001 From: pissang Date: Tue, 17 Sep 2019 00:10:03 +0800 Subject: [PATCH 100/127] feat: add clip option on scatter series --- src/chart/line/LineView.js | 53 +++------ src/chart/scatter/ScatterSeries.js | 6 +- src/chart/scatter/ScatterView.js | 11 +- src/coord/cartesian/Cartesian2D.js | 31 +++++ src/coord/polar/Polar.js | 33 ++++++ test/clip.html | 177 +++++++++++++++++++++++++++++ 6 files changed, 272 insertions(+), 39 deletions(-) create mode 100644 test/clip.html diff --git a/src/chart/line/LineView.js b/src/chart/line/LineView.js index 501f026a14..725e21a1a6 100644 --- a/src/chart/line/LineView.js +++ b/src/chart/line/LineView.js @@ -49,18 +49,6 @@ function getSmooth(smooth) { return typeof (smooth) === 'number' ? smooth : (smooth ? 0.5 : 0); } -function getAxisExtentWithGap(axis) { - var extent = axis.getGlobalExtent(); - if (axis.onBand) { - // Remove extra 1px to avoid line miter in clipped edge - var halfBandWidth = axis.getBandWidth() / 2 - 1; - var dir = extent[1] > extent[0] ? 1 : -1; - extent[0] += dir * halfBandWidth; - extent[1] -= dir * halfBandWidth; - } - return extent; -} - /** * @param {module:echarts/coord/cartesian/Cartesian2D|module:echarts/coord/polar/Polar} coordSys * @param {module:echarts/data/List} data @@ -81,14 +69,13 @@ function getStackedOnPoints(coordSys, data, dataCoordInfo) { } function createGridClipShape(cartesian, hasAnimation, forSymbol, seriesModel) { - var xExtent = getAxisExtentWithGap(cartesian.getAxis('x')); - var yExtent = getAxisExtentWithGap(cartesian.getAxis('y')); + var rect = cartesian.getArea(); var isHorizontal = cartesian.getBaseAxis().isHorizontal(); - var x = Math.min(xExtent[0], xExtent[1]); - var y = Math.min(yExtent[0], yExtent[1]); - var width = Math.max(xExtent[0], xExtent[1]) - x; - var height = Math.max(yExtent[0], yExtent[1]) - y; + var x = rect.x; + var y = rect.y; + var width = rect.width; + var height = rect.height; // Avoid float number rounding error for symbol on the edge of axis extent. // See #7913 and `test/dataZoom-clip.html`. @@ -135,38 +122,30 @@ function createGridClipShape(cartesian, hasAnimation, forSymbol, seriesModel) { } function createPolarClipShape(polar, hasAnimation, forSymbol, seriesModel) { - var angleAxis = polar.getAngleAxis(); - var radiusAxis = polar.getRadiusAxis(); - - var radiusExtent = radiusAxis.getExtent().slice(); - radiusExtent[0] > radiusExtent[1] && radiusExtent.reverse(); - var angleExtent = angleAxis.getExtent(); - - var RADIAN = Math.PI / 180; - + var sectorArea = polar.getArea(); // Avoid float number rounding error for symbol on the edge of axis extent. if (forSymbol) { - radiusExtent[0] -= 0.5; - radiusExtent[1] += 0.5; + sectorArea.r0 -= 0.5; + sectorArea.r1 += 0.5; } var clipPath = new graphic.Sector({ shape: { cx: round(polar.cx, 1), cy: round(polar.cy, 1), - r0: round(radiusExtent[0], 1), - r: round(radiusExtent[1], 1), - startAngle: -angleExtent[0] * RADIAN, - endAngle: -angleExtent[1] * RADIAN, - clockwise: angleAxis.inverse + r0: round(sectorArea.r0, 1), + r: round(sectorArea.r1, 1), + startAngle: sectorArea.startAngle, + endAngle: sectorArea.endAngle, + clockwise: sectorArea.clockwise } }); if (hasAnimation) { - clipPath.shape.endAngle = -angleExtent[0] * RADIAN; + clipPath.shape.endAngle = sectorArea.startAngle; graphic.initProps(clipPath, { shape: { - endAngle: -angleExtent[1] * RADIAN + endAngle: sectorArea.endAngle } }, seriesModel); } @@ -446,7 +425,7 @@ export default ChartView.extend({ ) { showSymbol && symbolDraw.updateData(data, { isIgnore: isIgnoreFunc, - clipShape: createClipShape(coordSys, false, true, seriesModel) + clipShape: coordSys.getArea() }); if (step) { diff --git a/src/chart/scatter/ScatterSeries.js b/src/chart/scatter/ScatterSeries.js index c04e7d802b..395f00a431 100644 --- a/src/chart/scatter/ScatterSeries.js +++ b/src/chart/scatter/ScatterSeries.js @@ -87,7 +87,11 @@ export default SeriesModel.extend({ itemStyle: { opacity: 0.8 // color: 各异 - } + }, + + // If clip the overflow graphics + // Works on cartesian / polar series + clip: true // progressive: null } diff --git a/src/chart/scatter/ScatterView.js b/src/chart/scatter/ScatterView.js index 2ec0b101ac..6c24bf2970 100644 --- a/src/chart/scatter/ScatterView.js +++ b/src/chart/scatter/ScatterView.js @@ -29,9 +29,18 @@ echarts.extendChartView({ render: function (seriesModel, ecModel, api) { var data = seriesModel.getData(); + var coordSys = seriesModel.coordinateSystem; + var clipArea = coordSys && coordSys.getArea && coordSys.getArea(); var symbolDraw = this._updateSymbolDraw(data, seriesModel); - symbolDraw.updateData(data); + + symbolDraw.updateData(data, { + // TODO + // If this parameter should be a shape or a bounding volume + // shape will be more general. + // But bounding volume like bounding rect will be much faster in the contain calculation + clipShape: seriesModel.get('clip') ? clipArea : null + }); this._finished = true; }, diff --git a/src/coord/cartesian/Cartesian2D.js b/src/coord/cartesian/Cartesian2D.js index 186b6039fd..74eb442528 100644 --- a/src/coord/cartesian/Cartesian2D.js +++ b/src/coord/cartesian/Cartesian2D.js @@ -19,8 +19,22 @@ import * as zrUtil from 'zrender/src/core/util'; +import BoundingRect from 'zrender/src/core/BoundingRect'; import Cartesian from './Cartesian'; +// A helper function to calculate extent of axis. +function getAxisExtentWithGap(axis) { + var extent = axis.getGlobalExtent(); + if (axis.onBand) { + // Remove extra 1px to avoid line miter in clipped edge + var halfBandWidth = axis.getBandWidth() / 2 - 1; + var dir = extent[1] > extent[0] ? 1 : -1; + extent[0] += dir * halfBandWidth; + extent[1] -= dir * halfBandWidth; + } + return extent; +} + function Cartesian2D(name) { Cartesian.call(this, name); @@ -130,6 +144,23 @@ Cartesian2D.prototype = { */ getOtherAxis: function (axis) { return this.getAxis(axis.dim === 'x' ? 'y' : 'x'); + }, + + /** + * Get rect area of cartesian. + * Area will have a contain function to determine if a point is in the coordinate system. + * @return {BoundingRect} + */ + getArea: function () { + var xExtent = getAxisExtentWithGap(this.getAxis('x')); + var yExtent = getAxisExtentWithGap(this.getAxis('y')); + var x = Math.min(xExtent[0], xExtent[1]); + var y = Math.min(yExtent[0], yExtent[1]); + var width = Math.max(xExtent[0], xExtent[1]) - x; + var height = Math.max(yExtent[0], yExtent[1]) - y; + + let rect = new BoundingRect(x, y, width, height); + return rect; } }; diff --git a/src/coord/polar/Polar.js b/src/coord/polar/Polar.js index e5391da10d..0f11e583a3 100644 --- a/src/coord/polar/Polar.js +++ b/src/coord/polar/Polar.js @@ -254,6 +254,39 @@ Polar.prototype = { var y = -Math.sin(radian) * radius + this.cy; return [x, y]; + }, + + /** + * Get sector area of cartesian. + * Area will have a contain function to determine if a point is in the coordinate system. + * @return {Sector} + */ + getArea: function () { + + var angleAxis = this.getAngleAxis(); + var radiusAxis = this.getRadiusAxis(); + + var radiusExtent = radiusAxis.getExtent().slice(); + radiusExtent[0] > radiusExtent[1] && radiusExtent.reverse(); + var angleExtent = angleAxis.getExtent(); + + var RADIAN = Math.PI / 180; + + var pt = [0, 0]; + return { + cx: this.cx, + cy: this.cy, + r0: radiusExtent[0], + r: radiusExtent[1], + startAngle: -angleExtent[0] * RADIAN, + endAngle: -angleExtent[1] * RADIAN, + clockwise: angleAxis.inverse, + contain: function (x, y) { + pt[0] = x; + pt[1] = y; + return this.containPoint(pt); + } + }; } }; diff --git a/test/clip.html b/test/clip.html new file mode 100644 index 0000000000..062662fd0c --- /dev/null +++ b/test/clip.html @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + +

Scatter Clip on Cartesian

+
+

Scatter Clip on Polar

+
+

Large Scatter Clip

+
+

Scatter Clip on Cartesian with DataZoom

+
+

Scatter Clip on Polar with DataZoom

+
+ +

Lines

+
+

Bar

+
+ + + + + + + + + + + + + + + + \ No newline at end of file From 755787f72f8d342736c156b86c93f9c2787446a7 Mon Sep 17 00:00:00 2001 From: pissang Date: Tue, 17 Sep 2019 13:05:03 +0800 Subject: [PATCH 101/127] fix: fix scatter clipping on polar --- src/chart/helper/LargeSymbolDraw.js | 22 +++-- src/chart/scatter/ScatterView.js | 14 +++- src/coord/polar/Polar.js | 27 +++--- test/clip.html | 122 +++++++++++++++++++++------- 4 files changed, 138 insertions(+), 47 deletions(-) diff --git a/src/chart/helper/LargeSymbolDraw.js b/src/chart/helper/LargeSymbolDraw.js index a5ad19461b..8db5332813 100644 --- a/src/chart/helper/LargeSymbolDraw.js +++ b/src/chart/helper/LargeSymbolDraw.js @@ -35,6 +35,8 @@ var LargeSymbolPath = graphic.extendShape({ symbolProxy: null, + softClipShape: null, + buildPath: function (path, shape) { var points = shape.points; var size = shape.size; @@ -56,6 +58,9 @@ var LargeSymbolPath = graphic.extendShape({ if (isNaN(x) || isNaN(y)) { continue; } + if (this.softClipShape && !this.softClipShape.contain(x, y)) { + continue; + } symbolProxyShape.x = x - size[0] / 2; symbolProxyShape.y = y - size[1] / 2; @@ -84,6 +89,9 @@ var LargeSymbolPath = graphic.extendShape({ if (isNaN(x) || isNaN(y)) { continue; } + if (this.softClipShape && !this.softClipShape.contain(x, y)) { + continue; + } // fillRect is faster than building a rect path and draw. // And it support light globalCompositeOperation. ctx.fillRect( @@ -135,8 +143,10 @@ largeSymbolProto.isPersistent = function () { /** * Update symbols draw by new data * @param {module:echarts/data/List} data + * @param {Object} opt + * @param {Object} [opt.clipShape] */ -largeSymbolProto.updateData = function (data) { +largeSymbolProto.updateData = function (data, opt) { this.group.removeAll(); var symbolEl = new LargeSymbolPath({ rectHover: true, @@ -146,7 +156,7 @@ largeSymbolProto.updateData = function (data) { symbolEl.setShape({ points: data.getLayout('symbolPoints') }); - this._setCommon(symbolEl, data); + this._setCommon(symbolEl, data, false, opt); this.group.add(symbolEl); this._incremental = null; @@ -187,7 +197,7 @@ largeSymbolProto.incrementalPrepareUpdate = function (data) { } }; -largeSymbolProto.incrementalUpdate = function (taskParams, data) { +largeSymbolProto.incrementalUpdate = function (taskParams, data, opt) { var symbolEl; if (this._incremental) { symbolEl = new LargeSymbolPath(); @@ -207,12 +217,13 @@ largeSymbolProto.incrementalUpdate = function (taskParams, data) { symbolEl.setShape({ points: data.getLayout('symbolPoints') }); - this._setCommon(symbolEl, data, !!this._incremental); + this._setCommon(symbolEl, data, !!this._incremental, opt); }; -largeSymbolProto._setCommon = function (symbolEl, data, isIncremental) { +largeSymbolProto._setCommon = function (symbolEl, data, isIncremental, opt) { var hostModel = data.hostModel; + opt = opt || {}; // TODO // if (data.hasItemVisual.symbolSize) { // // TODO typed array? @@ -228,6 +239,7 @@ largeSymbolProto._setCommon = function (symbolEl, data, isIncremental) { symbolEl.setShape('size', (size instanceof Array) ? size : [size, size]); // } + symbolEl.softClipShape = opt.clipShape || null; // Create symbolProxy to build path for each data symbolEl.symbolProxy = createSymbol( data.getVisual('symbol'), 0, 0, 0, 0 diff --git a/src/chart/scatter/ScatterView.js b/src/chart/scatter/ScatterView.js index 6c24bf2970..0dd16a1b3c 100644 --- a/src/chart/scatter/ScatterView.js +++ b/src/chart/scatter/ScatterView.js @@ -29,8 +29,6 @@ echarts.extendChartView({ render: function (seriesModel, ecModel, api) { var data = seriesModel.getData(); - var coordSys = seriesModel.coordinateSystem; - var clipArea = coordSys && coordSys.getArea && coordSys.getArea(); var symbolDraw = this._updateSymbolDraw(data, seriesModel); @@ -39,7 +37,7 @@ echarts.extendChartView({ // If this parameter should be a shape or a bounding volume // shape will be more general. // But bounding volume like bounding rect will be much faster in the contain calculation - clipShape: seriesModel.get('clip') ? clipArea : null + clipShape: this._getClipShape(seriesModel) }); this._finished = true; @@ -55,7 +53,9 @@ echarts.extendChartView({ }, incrementalRender: function (taskParams, seriesModel, ecModel) { - this._symbolDraw.incrementalUpdate(taskParams, seriesModel.getData()); + this._symbolDraw.incrementalUpdate(taskParams, seriesModel.getData(), { + clipShape: this._getClipShape(seriesModel) + }); this._finished = taskParams.end === seriesModel.getData().count(); }, @@ -81,6 +81,12 @@ echarts.extendChartView({ } }, + _getClipShape: function (seriesModel) { + var coordSys = seriesModel.coordinateSystem; + var clipArea = coordSys && coordSys.getArea && coordSys.getArea(); + return seriesModel.get('clip') ? clipArea : null; + }, + _updateSymbolDraw: function (data, seriesModel) { var symbolDraw = this._symbolDraw; var pipelineContext = seriesModel.pipelineContext; diff --git a/src/coord/polar/Polar.js b/src/coord/polar/Polar.js index 0f11e583a3..7185b0f9bf 100644 --- a/src/coord/polar/Polar.js +++ b/src/coord/polar/Polar.js @@ -257,9 +257,9 @@ Polar.prototype = { }, /** - * Get sector area of cartesian. + * Get ring area of cartesian. * Area will have a contain function to determine if a point is in the coordinate system. - * @return {Sector} + * @return {Ring} */ getArea: function () { @@ -272,19 +272,26 @@ Polar.prototype = { var RADIAN = Math.PI / 180; - var pt = [0, 0]; + var cx = this.cx; + var cy = this.cy; + var r = radiusExtent[1]; + var r0 = radiusExtent[0]; return { - cx: this.cx, - cy: this.cy, - r0: radiusExtent[0], - r: radiusExtent[1], + cx: cx, + cy: cy, + r0: r0, + r: r, startAngle: -angleExtent[0] * RADIAN, endAngle: -angleExtent[1] * RADIAN, clockwise: angleAxis.inverse, contain: function (x, y) { - pt[0] = x; - pt[1] = y; - return this.containPoint(pt); + // It's a ring shape. + // Start angle and end angle don't matter + var dx = x - cx; + var dy = y - cy; + var d2 = dx * dx + dy * dy; + + return d2 <= r * r && d2 >= r0 * r0; } }; } diff --git a/test/clip.html b/test/clip.html index 062662fd0c..a0fb68b412 100644 --- a/test/clip.html +++ b/test/clip.html @@ -43,15 +43,11 @@ } -

Scatter Clip on Cartesian

-

Scatter Clip on Polar

-

Large Scatter Clip

+
-

Scatter Clip on Cartesian with DataZoom

-
-

Scatter Clip on Polar with DataZoom

Lines

@@ -104,6 +100,7 @@

Bar

}] }; var chart = testHelper.create(echarts, 'scatter-clip-cartesian', { + title: 'Scatter Clip on Cartesian', option: option, height: 400, buttons: makeToggleChartButtons(function (clip) { @@ -125,31 +122,34 @@

Bar

require([ 'echarts' ], function (echarts) { + var data1 = []; + + for (var i = 0; i < 100; i++) { + data1.push([Math.random() * 10, Math.random() * 360]); + } + var option = { - xAxis: {}, - yAxis: { - min: 5, - max: 10 + polar: {}, + angleAxis: { + type: 'value', + min: 50, + max: 180 + }, + radiusAxis: { + axisAngle: 0, + min: 0, + max: 5 }, series: [{ - symbolSize: 20, - data: [ - [10.0, 8.04], - [8.0, 6.95], - [13.0, 7.58], - [9.0, 8.81], - [11.0, 8.33], - [14.0, 9.96], - [6.0, 7.24], - [4.0, 4.26], - [12.0, 10.84], - [7.0, 4.82], - [5.0, 5.68] - ], - type: 'scatter' + coordinateSystem: 'polar', + name: 'scatter', + type: 'scatter', + symbolSize: 10, + data: data1 }] }; - var chart = testHelper.create(echarts, 'scatter-clip-cartesian', { + var chart = testHelper.create(echarts, 'scatter-clip-polar', { + title: 'Scatter Clip on Polar', option: option, height: 400, buttons: makeToggleChartButtons(function (clip) { @@ -168,8 +168,74 @@

Bar

require([ 'echarts' ], function (echarts) { - - // testHelper.createChart(echarts, 'zoom-shift', option); + // Standard Normal variate using Box-Muller transform. + function rand() { + var u = 0, v = 0; + while(u === 0) u = Math.random(); //Converting [0,1) to (0,1) + while(v === 0) v = Math.random(); + return Math.sqrt(-2.0 * Math.log( u )) * Math.cos(2.0 * Math.PI * v); + } + + var data = []; + + for (let i = 0; i < 1e4; i++) { + data.push([ + rand(), + rand() + ]); + } + var option = { + xAxis: { + type: 'value', + min: -2, + max: 2 + }, + yAxis: { + type: 'value', + min: -2, + max: 2 + }, + series: [{ + symbolSize: 2, + large: true, + data: data, + symbol: 'rect', + type: 'scatter' + }] + }; + var chart = testHelper.create(echarts, 'large-scatter-clip', { + title: 'Large Scatter Clip', + option: option, + height: 400, + buttons: makeToggleChartButtons(function (clip) { + chart.setOption({ + series: [{ + clip: clip + }] + }) + }).concat([{ + text: 'Set Large', + onclick: function () { + chart.setOption({ + series: [{ + large: true, + progressive: 0 + }] + }) + } + }, { + text: 'Set Stream', + onclick: function () { + chart.setOption({ + series: [{ + large: false, + progressive: 2000 + }] + }) + } + + }]) + }); }) From dc7aadef65cbcca1cae66745029260ed4d006003 Mon Sep 17 00:00:00 2001 From: pissang Date: Tue, 17 Sep 2019 15:09:41 +0800 Subject: [PATCH 102/127] WIP(clip): Rename clipOverflow to clip in line series --- src/chart/line/LineSeries.js | 2 +- src/chart/line/LineView.js | 64 +++++++++++++++--------------- src/chart/lines/LinesSeries.js | 4 ++ src/coord/polar/Polar.js | 18 ++++----- src/preprocessor/backwardCompat.js | 9 ++++- 5 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/chart/line/LineSeries.js b/src/chart/line/LineSeries.js index c8abf58c59..0441d139de 100644 --- a/src/chart/line/LineSeries.js +++ b/src/chart/line/LineSeries.js @@ -51,7 +51,7 @@ export default SeriesModel.extend({ // polarIndex: 0, // If clip the overflow value - clipOverflow: true, + clip: true, // cursor: null, label: { diff --git a/src/chart/line/LineView.js b/src/chart/line/LineView.js index 725e21a1a6..de172c0f64 100644 --- a/src/chart/line/LineView.js +++ b/src/chart/line/LineView.js @@ -68,7 +68,7 @@ function getStackedOnPoints(coordSys, data, dataCoordInfo) { return points; } -function createGridClipShape(cartesian, hasAnimation, forSymbol, seriesModel) { +function createGridClipShape(cartesian, hasAnimation, seriesModel) { var rect = cartesian.getArea(); var isHorizontal = cartesian.getBaseAxis().isHorizontal(); @@ -77,26 +77,16 @@ function createGridClipShape(cartesian, hasAnimation, forSymbol, seriesModel) { var width = rect.width; var height = rect.height; - // Avoid float number rounding error for symbol on the edge of axis extent. - // See #7913 and `test/dataZoom-clip.html`. - if (forSymbol) { - x -= 0.5; - width += 0.5; - y -= 0.5; - height += 0.5; + var lineWidth = seriesModel.get('lineStyle.width') || 2; + // Expand clip shape to avoid clipping when line value exceeds axis + var expandSize = seriesModel.get('clip') ? lineWidth / 2 : Math.max(width, height); + if (isHorizontal) { + y -= expandSize; + height += expandSize * 2; } else { - var lineWidth = seriesModel.get('lineStyle.width') || 2; - // Expand clip shape to avoid clipping when line value exceeds axis - var expandSize = seriesModel.get('clipOverflow') ? lineWidth / 2 : Math.max(width, height); - if (isHorizontal) { - y -= expandSize; - height += expandSize * 2; - } - else { - x -= expandSize; - width += expandSize * 2; - } + x -= expandSize; + width += expandSize * 2; } var clipPath = new graphic.Rect({ @@ -121,13 +111,9 @@ function createGridClipShape(cartesian, hasAnimation, forSymbol, seriesModel) { return clipPath; } -function createPolarClipShape(polar, hasAnimation, forSymbol, seriesModel) { +function createPolarClipShape(polar, hasAnimation, seriesModel) { var sectorArea = polar.getArea(); // Avoid float number rounding error for symbol on the edge of axis extent. - if (forSymbol) { - sectorArea.r0 -= 0.5; - sectorArea.r1 += 0.5; - } var clipPath = new graphic.Sector({ shape: { @@ -153,10 +139,10 @@ function createPolarClipShape(polar, hasAnimation, forSymbol, seriesModel) { return clipPath; } -function createClipShape(coordSys, hasAnimation, forSymbol, seriesModel) { +function createClipShape(coordSys, hasAnimation, seriesModel) { return coordSys.type === 'polar' - ? createPolarClipShape(coordSys, hasAnimation, forSymbol, seriesModel) - : createGridClipShape(coordSys, hasAnimation, forSymbol, seriesModel); + ? createPolarClipShape(coordSys, hasAnimation, seriesModel) + : createGridClipShape(coordSys, hasAnimation, seriesModel); } function turnPointsIntoStep(points, coordSys, stepTurnAt) { @@ -419,13 +405,29 @@ export default ChartView.extend({ // FIXME step not support polar var step = !isCoordSysPolar && seriesModel.get('step'); + var clipShapeForSymbol; + if (coordSys && coordSys.getArea) { + clipShapeForSymbol = coordSys.getArea(); + // Avoid float number rounding error for symbol on the edge of axis extent. + // See #7913 and `test/dataZoom-clip.html`. + if (clipShapeForSymbol.width != null) { + clipShapeForSymbol.x -= 0.1; + clipShapeForSymbol.y -= 0.1; + clipShapeForSymbol.width += 0.2; + clipShapeForSymbol.height += 0.2; + } + else if (clipShapeForSymbol.r0) { + clipShapeForSymbol.r0 -= 0.5; + clipShapeForSymbol.r1 += 0.5; + } + } // Initialization animation or coordinate system changed if ( !(polyline && prevCoordSys.type === coordSys.type && step === this._step) ) { showSymbol && symbolDraw.updateData(data, { isIgnore: isIgnoreFunc, - clipShape: coordSys.getArea() + clipShape: clipShapeForSymbol }); if (step) { @@ -441,7 +443,7 @@ export default ChartView.extend({ coordSys, hasAnimation ); } - lineGroup.setClipPath(createClipShape(coordSys, true, false, seriesModel)); + lineGroup.setClipPath(createClipShape(coordSys, true, seriesModel)); } else { if (isAreaChart && !polygon) { @@ -458,13 +460,13 @@ export default ChartView.extend({ } // Update clipPath - lineGroup.setClipPath(createClipShape(coordSys, false, false, seriesModel)); + lineGroup.setClipPath(createClipShape(coordSys, false, seriesModel)); // Always update, or it is wrong in the case turning on legend // because points are not changed showSymbol && symbolDraw.updateData(data, { isIgnore: isIgnoreFunc, - clipShape: createClipShape(coordSys, false, true, seriesModel) + clipShape: clipShapeForSymbol }); // Stop symbol animation and sync with line points diff --git a/src/chart/lines/LinesSeries.js b/src/chart/lines/LinesSeries.js index 59747bec38..047f0b6c17 100644 --- a/src/chart/lines/LinesSeries.js +++ b/src/chart/lines/LinesSeries.js @@ -316,6 +316,10 @@ var LinesSeries = SeriesModel.extend({ // polyline not support curveness, label, animation polyline: false, + // If clip the overflow. + // Available when coordinateSystem is cartesian or polar. + clip: true, + label: { show: false, position: 'end' diff --git a/src/coord/polar/Polar.js b/src/coord/polar/Polar.js index 7185b0f9bf..5e21ac7545 100644 --- a/src/coord/polar/Polar.js +++ b/src/coord/polar/Polar.js @@ -272,24 +272,22 @@ Polar.prototype = { var RADIAN = Math.PI / 180; - var cx = this.cx; - var cy = this.cy; - var r = radiusExtent[1]; - var r0 = radiusExtent[0]; return { - cx: cx, - cy: cy, - r0: r0, - r: r, + cx: this.cx, + cy: this.cy, + r0: radiusExtent[0], + r: radiusExtent[1], startAngle: -angleExtent[0] * RADIAN, endAngle: -angleExtent[1] * RADIAN, clockwise: angleAxis.inverse, contain: function (x, y) { // It's a ring shape. // Start angle and end angle don't matter - var dx = x - cx; - var dy = y - cy; + var dx = x - this.cx; + var dy = y - this.cy; var d2 = dx * dx + dy * dy; + var r = this.r; + var r0 = this.r0; return d2 <= r * r && d2 >= r0 * r0; } diff --git a/src/preprocessor/backwardCompat.js b/src/preprocessor/backwardCompat.js index 249c0f340f..50f09e8ee0 100644 --- a/src/preprocessor/backwardCompat.js +++ b/src/preprocessor/backwardCompat.js @@ -80,12 +80,17 @@ export default function (option, isTheme) { var seriesType = seriesOpt.type; - if (seriesType === 'pie' || seriesType === 'gauge') { + if (seriesType === 'line') { + if (seriesOpt.clipOverflow != null) { + seriesOpt.clip = seriesOpt.clipOverflow; + } + } + else if (seriesType === 'pie' || seriesType === 'gauge') { if (seriesOpt.clockWise != null) { seriesOpt.clockwise = seriesOpt.clockWise; } } - if (seriesType === 'gauge') { + else if (seriesType === 'gauge') { var pointerColor = get(seriesOpt, 'pointer.color'); pointerColor != null && set(seriesOpt, 'itemStyle.color', pointerColor); From 94dfc9284f12cba56b7524dcf60776d0c39dbe79 Mon Sep 17 00:00:00 2001 From: pissang Date: Tue, 17 Sep 2019 16:22:33 +0800 Subject: [PATCH 103/127] WIP(clip): support clip in lines series --- .../helper/createClipPathFromCoordSys.js | 101 ++++++++++++++ src/chart/line/LineView.js | 107 ++++----------- src/chart/lines/LinesView.js | 11 ++ src/coord/cartesian/Cartesian2D.js | 2 +- test/clip.html | 125 +++++++++++++++++- 5 files changed, 261 insertions(+), 85 deletions(-) create mode 100644 src/chart/helper/createClipPathFromCoordSys.js diff --git a/src/chart/helper/createClipPathFromCoordSys.js b/src/chart/helper/createClipPathFromCoordSys.js new file mode 100644 index 0000000000..9759ca2f7c --- /dev/null +++ b/src/chart/helper/createClipPathFromCoordSys.js @@ -0,0 +1,101 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ +import * as graphic from '../../util/graphic'; +import {round} from '../../util/number'; + +function createGridClipPath(cartesian, hasAnimation, seriesModel) { + var rect = cartesian.getArea(); + var isHorizontal = cartesian.getBaseAxis().isHorizontal(); + + var x = rect.x; + var y = rect.y; + var width = rect.width; + var height = rect.height; + + var lineWidth = seriesModel.get('lineStyle.width') || 2; + // Expand the clip path a bit to avoid the border is clipped and looks thinner + x -= lineWidth / 2; + y -= lineWidth / 2; + width += lineWidth; + height += lineWidth; + + var clipPath = new graphic.Rect({ + shape: { + x: x, + y: y, + width: width, + height: height + } + }); + + if (hasAnimation) { + clipPath.shape[isHorizontal ? 'width' : 'height'] = 0; + graphic.initProps(clipPath, { + shape: { + width: width, + height: height + } + }, seriesModel); + } + + return clipPath; +} + +function createPolarClipPath(polar, hasAnimation, seriesModel) { + var sectorArea = polar.getArea(); + // Avoid float number rounding error for symbol on the edge of axis extent. + + var clipPath = new graphic.Sector({ + shape: { + cx: round(polar.cx, 1), + cy: round(polar.cy, 1), + r0: round(sectorArea.r0, 1), + r: round(sectorArea.r1, 1), + startAngle: sectorArea.startAngle, + endAngle: sectorArea.endAngle, + clockwise: sectorArea.clockwise + } + }); + + if (hasAnimation) { + clipPath.shape.endAngle = sectorArea.startAngle; + graphic.initProps(clipPath, { + shape: { + endAngle: sectorArea.endAngle + } + }, seriesModel); + } + + return clipPath; +} + +function createClipPath(coordSys, hasAnimation, seriesModel) { + if (!coordSys) { + return null; + } + else if (coordSys.type === 'polar') { + return createPolarClipPath(coordSys, hasAnimation, seriesModel); + } + else if (coordSys.type === 'cartesian2d') { + return createGridClipPath(coordSys, hasAnimation, seriesModel); + } + return null; +} + +export {createGridClipPath, createPolarClipPath, createClipPath}; \ No newline at end of file diff --git a/src/chart/line/LineView.js b/src/chart/line/LineView.js index de172c0f64..ea7fd3f582 100644 --- a/src/chart/line/LineView.js +++ b/src/chart/line/LineView.js @@ -28,8 +28,8 @@ import * as graphic from '../../util/graphic'; import * as modelUtil from '../../util/model'; import {Polyline, Polygon} from './poly'; import ChartView from '../../view/Chart'; -import {round} from '../../util/number'; import {prepareDataCoordInfo, getStackedOnPoint} from './helper'; +import {createGridClipPath, createPolarClipPath} from '../helper/createClipPathFromCoordSys'; function isPointsSame(points1, points2) { if (points1.length !== points2.length) { @@ -68,83 +68,6 @@ function getStackedOnPoints(coordSys, data, dataCoordInfo) { return points; } -function createGridClipShape(cartesian, hasAnimation, seriesModel) { - var rect = cartesian.getArea(); - var isHorizontal = cartesian.getBaseAxis().isHorizontal(); - - var x = rect.x; - var y = rect.y; - var width = rect.width; - var height = rect.height; - - var lineWidth = seriesModel.get('lineStyle.width') || 2; - // Expand clip shape to avoid clipping when line value exceeds axis - var expandSize = seriesModel.get('clip') ? lineWidth / 2 : Math.max(width, height); - if (isHorizontal) { - y -= expandSize; - height += expandSize * 2; - } - else { - x -= expandSize; - width += expandSize * 2; - } - - var clipPath = new graphic.Rect({ - shape: { - x: x, - y: y, - width: width, - height: height - } - }); - - if (hasAnimation) { - clipPath.shape[isHorizontal ? 'width' : 'height'] = 0; - graphic.initProps(clipPath, { - shape: { - width: width, - height: height - } - }, seriesModel); - } - - return clipPath; -} - -function createPolarClipShape(polar, hasAnimation, seriesModel) { - var sectorArea = polar.getArea(); - // Avoid float number rounding error for symbol on the edge of axis extent. - - var clipPath = new graphic.Sector({ - shape: { - cx: round(polar.cx, 1), - cy: round(polar.cy, 1), - r0: round(sectorArea.r0, 1), - r: round(sectorArea.r1, 1), - startAngle: sectorArea.startAngle, - endAngle: sectorArea.endAngle, - clockwise: sectorArea.clockwise - } - }); - - if (hasAnimation) { - clipPath.shape.endAngle = sectorArea.startAngle; - graphic.initProps(clipPath, { - shape: { - endAngle: sectorArea.endAngle - } - }, seriesModel); - } - - return clipPath; -} - -function createClipShape(coordSys, hasAnimation, seriesModel) { - return coordSys.type === 'polar' - ? createPolarClipShape(coordSys, hasAnimation, seriesModel) - : createGridClipShape(coordSys, hasAnimation, seriesModel); -} - function turnPointsIntoStep(points, coordSys, stepTurnAt) { var baseAxis = coordSys.getBaseAxis(); var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1; @@ -341,6 +264,30 @@ function canShowAllSymbolForCategory(categoryAxis, data) { return true; } +function createLineClipPath(coordSys, hasAnimation, seriesModel) { + if (coordSys.type === 'cartesian2d') { + var isHorizontal = coordSys.getBaseAxis().isHorizontal(); + var clipPath = createGridClipPath(coordSys, hasAnimation, seriesModel); + // Expand clip shape to avoid clipping when line value exceeds axis + if (!seriesModel.get('clip')) { + var rectShape = clipPath.shape; + var expandSize = Math.max(rectShape.width, rectShape.height); + if (isHorizontal) { + rectShape.y -= expandSize; + rectShape.height += expandSize * 2; + } + else { + rectShape.x -= expandSize; + rectShape.width += expandSize * 2; + } + } + } + else { + return createPolarClipPath(coordSys, hasAnimation, seriesModel); + } + +} + export default ChartView.extend({ type: 'line', @@ -443,7 +390,7 @@ export default ChartView.extend({ coordSys, hasAnimation ); } - lineGroup.setClipPath(createClipShape(coordSys, true, seriesModel)); + lineGroup.setClipPath(createLineClipPath(coordSys, true, seriesModel)); } else { if (isAreaChart && !polygon) { @@ -460,7 +407,7 @@ export default ChartView.extend({ } // Update clipPath - lineGroup.setClipPath(createClipShape(coordSys, false, seriesModel)); + lineGroup.setClipPath(createLineClipPath(coordSys, false, seriesModel)); // Always update, or it is wrong in the case turning on legend // because points are not changed diff --git a/src/chart/lines/LinesView.js b/src/chart/lines/LinesView.js index e742d013e0..02b5c83401 100644 --- a/src/chart/lines/LinesView.js +++ b/src/chart/lines/LinesView.js @@ -26,6 +26,7 @@ import Polyline from '../helper/Polyline'; import EffectPolyline from '../helper/EffectPolyline'; import LargeLineDraw from '../helper/LargeLineDraw'; import linesLayout from './linesLayout'; +import {createClipPath} from '../helper/createClipPathFromCoordSys'; export default echarts.extendChartView({ @@ -76,6 +77,16 @@ export default echarts.extendChartView({ lineDraw.updateData(data); + var clipPath = seriesModel.get('clip') && createClipPath( + seriesModel.coordinateSystem, false, seriesModel + ); + if (clipPath) { + this.group.setClipPath(clipPath); + } + else { + this.group.removeClipPath(); + } + this._lastZlevel = zlevel; this._finished = true; diff --git a/src/coord/cartesian/Cartesian2D.js b/src/coord/cartesian/Cartesian2D.js index 74eb442528..511ddf1bb2 100644 --- a/src/coord/cartesian/Cartesian2D.js +++ b/src/coord/cartesian/Cartesian2D.js @@ -159,7 +159,7 @@ Cartesian2D.prototype = { var width = Math.max(xExtent[0], xExtent[1]) - x; var height = Math.max(yExtent[0], yExtent[1]) - y; - let rect = new BoundingRect(x, y, width, height); + var rect = new BoundingRect(x, y, width, height); return rect; } diff --git a/test/clip.html b/test/clip.html index a0fb68b412..9fcb0bbc90 100644 --- a/test/clip.html +++ b/test/clip.html @@ -48,12 +48,10 @@
-
- -

Lines

-

Bar

+
+
+ + \ No newline at end of file From d80db8e577a80efaed0c84ff96a424e0e37ad8de Mon Sep 17 00:00:00 2001 From: pissang Date: Tue, 17 Sep 2019 20:00:43 +0800 Subject: [PATCH 104/127] feat(dataZoom): Add filterMode in the toolbox dataZoom feature. --- src/chart/line/LineView.js | 1 + src/component/dataZoom/DataZoomModel.js | 10 ++ src/component/dataZoom/dataZoomAction.js | 5 + src/component/toolbox/feature/DataZoom.js | 6 +- test/clip.html | 159 +++++++++++++++++++++- 5 files changed, 176 insertions(+), 5 deletions(-) diff --git a/src/chart/line/LineView.js b/src/chart/line/LineView.js index ea7fd3f582..5879308b95 100644 --- a/src/chart/line/LineView.js +++ b/src/chart/line/LineView.js @@ -281,6 +281,7 @@ function createLineClipPath(coordSys, hasAnimation, seriesModel) { rectShape.width += expandSize * 2; } } + return clipPath; } else { return createPolarClipPath(coordSys, hasAnimation, seriesModel); diff --git a/src/component/dataZoom/DataZoomModel.js b/src/component/dataZoom/DataZoomModel.js index 9c5f6a52fe..9da7bf03ee 100644 --- a/src/component/dataZoom/DataZoomModel.js +++ b/src/component/dataZoom/DataZoomModel.js @@ -469,6 +469,16 @@ var DataZoomModel = echarts.extendComponentModel({ !ignoreUpdateRangeUsg && updateRangeUse(this, opt); }, + /** + * Set filter mode. + * This will be set in the action dispatched from toolbox. + * + * @param {string} filterMode Values can be 'filter', 'weakFilter', 'empty' ,'none' + */ + setFilterMode: function (filterMode) { + this.option.filterMode = filterMode; + }, + /** * @public * @return {Array.} [startPercent, endPercent] diff --git a/src/component/dataZoom/dataZoomAction.js b/src/component/dataZoom/dataZoomAction.js index b227e110c5..d6795794f3 100644 --- a/src/component/dataZoom/dataZoomAction.js +++ b/src/component/dataZoom/dataZoomAction.js @@ -50,6 +50,11 @@ echarts.registerAction('dataZoom', function (payload, ecModel) { startValue: payload.startValue, endValue: payload.endValue }); + // Update filterMode if it's needs to be changed. + // This action is mainly dispatched from dataZoom toolbox. + if (payload.filterMode != null) { + dataZoomModel.setFilterMode(payload.filterMode); + } }); }); diff --git a/src/component/toolbox/feature/DataZoom.js b/src/component/toolbox/feature/DataZoom.js index 84a9170178..fde5669a7d 100644 --- a/src/component/toolbox/feature/DataZoom.js +++ b/src/component/toolbox/feature/DataZoom.js @@ -54,6 +54,7 @@ function DataZoom(model, ecModel, api) { DataZoom.defaultOption = { show: true, + filterMode: 'filter', // Icon group icon: { zoom: 'M0,13.5h26.9 M13.5,26.9V0 M32.1,13.5H58V58H13.5 V32.1', @@ -115,6 +116,7 @@ proto._onBrush = function (areas, opt) { } var snapshot = {}; var ecModel = this.ecModel; + var filterMode = this.model.get('filterMode'); this._brushController.updateCovers([]); // remove cover @@ -157,7 +159,9 @@ proto._onBrush = function (areas, opt) { dataZoomModel && (snapshot[dataZoomModel.id] = { dataZoomId: dataZoomModel.id, startValue: minMax[0], - endValue: minMax[1] + endValue: minMax[1], + // Set filterMode + filterMode: filterMode }); } diff --git a/test/clip.html b/test/clip.html index 9fcb0bbc90..5802b9a88a 100644 --- a/test/clip.html +++ b/test/clip.html @@ -49,6 +49,7 @@
-->
+
@@ -162,6 +163,9 @@ + + + + + + + + + + + \ No newline at end of file From 47116e71188e7773b28a08dd0ecbcacd04b919eb Mon Sep 17 00:00:00 2001 From: pissang Date: Tue, 17 Sep 2019 21:03:23 +0800 Subject: [PATCH 105/127] fix(dataZoom): set filterMode from toolbox dataZoom in preprocessor --- src/component/dataZoom/DataZoomModel.js | 10 -------- src/component/dataZoom/dataZoomAction.js | 5 ---- src/component/toolbox/feature/DataZoom.js | 7 +++--- test/clip.html | 28 +++++++++++++++++++++-- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/component/dataZoom/DataZoomModel.js b/src/component/dataZoom/DataZoomModel.js index 9da7bf03ee..9c5f6a52fe 100644 --- a/src/component/dataZoom/DataZoomModel.js +++ b/src/component/dataZoom/DataZoomModel.js @@ -469,16 +469,6 @@ var DataZoomModel = echarts.extendComponentModel({ !ignoreUpdateRangeUsg && updateRangeUse(this, opt); }, - /** - * Set filter mode. - * This will be set in the action dispatched from toolbox. - * - * @param {string} filterMode Values can be 'filter', 'weakFilter', 'empty' ,'none' - */ - setFilterMode: function (filterMode) { - this.option.filterMode = filterMode; - }, - /** * @public * @return {Array.} [startPercent, endPercent] diff --git a/src/component/dataZoom/dataZoomAction.js b/src/component/dataZoom/dataZoomAction.js index d6795794f3..b227e110c5 100644 --- a/src/component/dataZoom/dataZoomAction.js +++ b/src/component/dataZoom/dataZoomAction.js @@ -50,11 +50,6 @@ echarts.registerAction('dataZoom', function (payload, ecModel) { startValue: payload.startValue, endValue: payload.endValue }); - // Update filterMode if it's needs to be changed. - // This action is mainly dispatched from dataZoom toolbox. - if (payload.filterMode != null) { - dataZoomModel.setFilterMode(payload.filterMode); - } }); }); diff --git a/src/component/toolbox/feature/DataZoom.js b/src/component/toolbox/feature/DataZoom.js index fde5669a7d..2ef98f87dc 100644 --- a/src/component/toolbox/feature/DataZoom.js +++ b/src/component/toolbox/feature/DataZoom.js @@ -116,7 +116,6 @@ proto._onBrush = function (areas, opt) { } var snapshot = {}; var ecModel = this.ecModel; - var filterMode = this.model.get('filterMode'); this._brushController.updateCovers([]); // remove cover @@ -159,9 +158,7 @@ proto._onBrush = function (areas, opt) { dataZoomModel && (snapshot[dataZoomModel.id] = { dataZoomId: dataZoomModel.id, startValue: minMax[0], - endValue: minMax[1], - // Set filterMode - filterMode: filterMode + endValue: minMax[1] }); } @@ -306,6 +303,8 @@ echarts.registerPreprocessor(function (option) { var newOpt = { type: 'select', $fromToolbox: true, + // Default to be filter + filterMode: dataZoomOpt.filterMode || 'filter', // Id for merge mapping. id: DATA_ZOOM_ID_BASE + axisName + axisIndex }; diff --git a/test/clip.html b/test/clip.html index 5802b9a88a..d08e89dd70 100644 --- a/test/clip.html +++ b/test/clip.html @@ -406,7 +406,7 @@ feature: { dataZoom: { // Not filter the data. - filterMode: 'none', + // filterMode: 'none', yAxisIndex: 'none' }, restore: {} @@ -440,6 +440,7 @@ }, dataZoom: [{ type: 'inside', + filterMode: 'none', throttle: 50 }], series: [ @@ -499,10 +500,33 @@ ] }; + function setFilterMode(mode) { + chart.setOption({ + toolbox: { + feature: { + dataZoom: { + filterMode: mode + } + } + } + }); + } + var chart = testHelper.create(echarts, 'line-dataZoom', { title: 'Line with dataZoom,(#10224). Should not be blank when selected a small area', option: option, - height: 400 + height: 400, + buttons: [{ + text: 'Set filter all', + onclick: function () { + setFilterMode('filter'); + } + }, { + text: 'Set filter none', + onclick: function () { + setFilterMode('none') + } + }] }); }) From 105bde535060b8f4f723859e66c6ad30d978fbb5 Mon Sep 17 00:00:00 2001 From: Yi Shen Date: Wed, 18 Sep 2019 14:37:53 +0800 Subject: [PATCH 106/127] doc: fix image link in contributing doc (#11270) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee994d1811..53c2552ef8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -101,7 +101,7 @@ node build/build.js Then, open the test cases under `~/workspace/echarts/test` in Web browser. You can add breakpoints under `src` directory. For example, in Chrome Inspect, it looks like: -![Chrome inspect](../asset/contributing-inspect.png) +![Chrome inspect](./asset/contributing-inspect.png) ### 4. Run test From 004dfecfeafd050b51ebf7629bbefdbcf277bce8 Mon Sep 17 00:00:00 2001 From: sushuang Date: Wed, 18 Sep 2019 01:25:06 +0800 Subject: [PATCH 107/127] feat(test): support `npm run mktest some-test-file`. --- package.json | 1 + test/build/mktest-tpl.html | 80 +++++++++++++++++++ test/build/mktest.js | 154 +++++++++++++++++++++++++++++++++++++ 3 files changed, 235 insertions(+) create mode 100644 test/build/mktest-tpl.html create mode 100755 test/build/mktest.js diff --git a/package.json b/package.json index 2dbadbacc1..10fb6f603e 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "prepublish": "node build/build.js --prepublish", "test:visual": "node test/runTest/server.js", "test": "node build/build.js", + "mktest": "node test/build/mktest.js", "lint": "./node_modules/.bin/eslint src extension-src", "lint:dist": "echo 'It might take a while. Please wait ...' && ./node_modules/.bin/jshint --config .jshintrc-dist dist/echarts.js" }, diff --git a/test/build/mktest-tpl.html b/test/build/mktest-tpl.html new file mode 100644 index 0000000000..15836ef53a --- /dev/null +++ b/test/build/mktest-tpl.html @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + diff --git a/test/build/mktest.js b/test/build/mktest.js new file mode 100755 index 0000000000..c71403a24e --- /dev/null +++ b/test/build/mktest.js @@ -0,0 +1,154 @@ +#!/usr/bin/env node + +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + + +const nodeFS = require('fs'); +const assert = require('assert'); +const nodePath = require('path'); +const commander = require('commander'); +const {color} = require('zrender/build/helper'); + +const colorFgCyanDim = color('fgCyan', 'dim'); +const colorFgGreen = color('fgGreen'); +const colorFgRed = color('fgRed'); + +const testDir = nodePath.resolve(__dirname, '..'); +const testTplPath = nodePath.resolve(__dirname, 'mktest-tpl.html'); +const tplSegmentDelimiter = ''; +const tagDomId = /{{TPL_DOM_ID}}/g; +const tagDomPlace = ''; +const tagJSPlace = ''; + +const manualText = ` + ${colorFgCyanDim('Usage:')} + + # Make a file named "bar-action.html" in directory "echarts/test" with 1 initial chart. + ${colorFgGreen('npm run mktest bar-action')} + # or + ${colorFgGreen('npm run mktest bar-action.html')} + # or + ${colorFgGreen('node ./test/build/mktest bar-action')} + + # Make a file named "bar-action.html" in directory "echarts/test" with 5 initial charts. + ${colorFgGreen('npm run mktest bar-action 5')} + # or + ${colorFgGreen('node ./test/build/mktest bar-action 5')} +`; + +function run() { + let opt = prepareOpt(); + + if (!opt) { + return; + } + + if (nodeFS.existsSync(opt.testFilePath)) { + printError(`The file ${opt.testFilePath} exists! Please chose another name.`); + printError('Please chose another name.'); + return; + } + + const testTplContent = nodeFS.readFileSync(testTplPath, {encoding: 'utf8'}); + + const testFileContent = makeTestFileContent(opt, testTplContent); + + nodeFS.writeFileSync(opt.testFilePath, testFileContent, {encoding: 'utf8'}); + + console.log(`A test file has been added in: \n${colorFgGreen(opt.testFilePath)}`); + console.log(); +} + +function prepareOpt() { + commander + .usage('test-file-name [chart-number]') + .description(manualText) + .parse(process.argv); + + let args = commander.args || []; + + let testFileName = args[0]; + let testCaseNumber = args[1]; + if (isNaN(testCaseNumber)) { + testCaseNumber = 1; + } + + if (!testFileName) { + printError('Must input a file name!'); + return; + } + + testFileName = normalizeInputExt(testFileName); + let testFilePath = nodePath.resolve(testDir, testFileName); + + return { + testFileName: testFileName, + testFilePath: testFilePath, + testCaseNumber: testCaseNumber + }; +} + +function makeTestFileContent(opt, testTplContent) { + const testTplSegments = testTplContent.split(tplSegmentDelimiter); + + const tplSegMain = testTplSegments[0]; + const tplSegDom = testTplSegments[1]; + const tplSegJS = testTplSegments[2]; + + assert(tplSegMain && tplSegDom && tplSegJS); + + let segDomList = []; + let segJSList = []; + + for (let i = 0; i < opt.testCaseNumber; i++) { + let domId = 'main' + i; + segDomList.push(tplSegDom.replace(tagDomId, domId)); + segJSList.push(tplSegJS.replace(tagDomId, domId)); + } + + let htmlContent = tplSegMain + .replace(tagDomPlace, segDomList.join('\n')) + .replace(tagJSPlace, segJSList.join('\n')); + + return htmlContent; +} + +function normalizeInputExt(testFileName) { + if (hasExt(testFileName, '.html')) { + return testFileName; + } + else if (hasExt(testFileName, '.htm')) { + return testFileName + 'l'; + } + else { + return testFileName + '.html'; + } + + function hasExt(fileName, ext) { + let idx = fileName.lastIndexOf(ext); + return idx >= 0 && idx === fileName.length - ext.length; + } +} + +function printError(msg) { + console.error(colorFgRed('[ERROR]: ' + msg)); +} + +run(); From ae7fbad774149899502b613847858d7a823e1a91 Mon Sep 17 00:00:00 2001 From: sushuang Date: Wed, 18 Sep 2019 02:23:24 +0800 Subject: [PATCH 108/127] feat(test): Add instructions for adding a test case and tweak `mktest`. --- CONTRIBUTING.md | 63 +++++++++++++++++++++++++++++++++++++++++--- package.json | 1 + test/build/mktest.js | 2 ++ 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 53c2552ef8..504eef838d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,10 +44,12 @@ Please follow the [coding standard](https://echarts.apache.org/en/coding-standar If you wish to fix a bug or add new features but don't know how, please discuss it with us in the [mailing list](dev@echarts.apache.org). + ## How to Debug ECharts The following steps help you to set up a developing environment for ECharts. + ### 1. Clone ECharts project If you wish to make pull requests, you should **fork the ECharts project** first. Otherwise, just clone it locally. @@ -64,6 +66,7 @@ git clone git@github.com:ecomfe/zrender.git We assume these projects are downloaded at `~/workspace/echarts` and `~/workspace/zrender`. But their locations can be arbitrary. + ### 2. Install dependencies ```bash @@ -84,6 +87,7 @@ npm link zrender With this, you can see that `~/workspace/echarts/node_modules/zrender` is a link to `~/workspace/zrender`. + ### 3. Run and debug To build the ECharts project and watch source file changes (including ZRender project) to rebuild: @@ -103,7 +107,59 @@ Then, open the test cases under `~/workspace/echarts/test` in Web browser. You c ![Chrome inspect](./asset/contributing-inspect.png) -### 4. Run test + +### 4. Add test cases + +In most cases, one or more test cases should be added when developing a feature or fixing a bug. +All of the existing test cases are in directory `~/workspace/echarts/test`. +Check the file `~/workspace/echarts/test/dataZoom-action.html` as an example. + +**Organize test cases:** +Each file can be regard as a **test suite** and each chart in the file can be regard as a **test case**, +which contains one or multiple expected results (check points). +If a feature or bug is related to a chart type or a component type, probably it should belongs to +a test file named `chartOrComponentType-someSubCategory.html`. Or some common feature is related +to multiple chart or component or has nothing to do with chart and component, probably it should +belongs a test file named `featureName-someSubCateogory.html`. + +**The naming of a test file:** +Generally speaking, the name of the test file should start with a chart type or component type +or a common feature name (like "hoverStyle", "clip"). + +**Add a test case:** +If intending to add a test case, firstly try to find in the existing test files which file this +new test case might belongs to. +If an existing file found, add the test case to the file. +Otherwise, add a new test file by commands as follows: + +```shell +# Make a file named "bar-action.html" in directory "echarts/test" with 1 initial chart. +npm run mktest bar-action +# or `npm run mktest bar-action.html` + +# Make a file named "bar-action.html" in directory "echarts/test" with 5 initial charts. +npm run mktest bar-action 5 +``` + +**The expected results and the instructions of user interaction:** +Although we have auto-visual-test tool to run tests, we should better write the expected result +(check points) for each test cases for manual checking. +Some cases need user interactions involved. The instructions should be written clearly. +The expected results and the user instructions should be written in the `title` filed when +creating a test by `testHelper.create` as follows: + +```js +var chart = testHelper.create(echarts, 'main0', { + title: [ + 'Hover on the red circle', + '**A blue label** should appear on the **top of red circle**.' + ], + option: option +}); +``` + + +### 5. Run test cases ```bash # puppeteer is not in the devDependencies and needs to be installed manually @@ -113,7 +169,8 @@ npm run test:visual It will run all the test cases under `~/workspace/echarts/test` automatically to compare with the previous version. You can use this to check if your code bring some breaking change. -### 5. Check the code style + +### 6. Check the code style The code style should follow the [Code Standard](https://echarts.apache.org/en/coding-standard.html). @@ -125,7 +182,7 @@ npm run lint to check the the code style. -### 6. Make a pull request +### 7. Make a pull request Fork ECharts project into your own project. Checkout a branch from master branch named `fix-xxxx`, where xxxx is the issue id related. If there's no related issue, you need to create one in most cases to describe what's wrong or what new feature is required. diff --git a/package.json b/package.json index 10fb6f603e..8fdeb54849 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "test:visual": "node test/runTest/server.js", "test": "node build/build.js", "mktest": "node test/build/mktest.js", + "mktest:help": "node test/build/mktest.js -h", "lint": "./node_modules/.bin/eslint src extension-src", "lint:dist": "echo 'It might take a while. Please wait ...' && ./node_modules/.bin/jshint --config .jshintrc-dist dist/echarts.js" }, diff --git a/test/build/mktest.js b/test/build/mktest.js index c71403a24e..9734e9ccf6 100755 --- a/test/build/mktest.js +++ b/test/build/mktest.js @@ -63,6 +63,7 @@ function run() { if (nodeFS.existsSync(opt.testFilePath)) { printError(`The file ${opt.testFilePath} exists! Please chose another name.`); printError('Please chose another name.'); + console.log(manualText); return; } @@ -92,6 +93,7 @@ function prepareOpt() { if (!testFileName) { printError('Must input a file name!'); + console.log(manualText); return; } From fcf80fef1727101947b49a5f722fd4f494f6212b Mon Sep 17 00:00:00 2001 From: sushuang Date: Wed, 18 Sep 2019 16:14:19 +0800 Subject: [PATCH 109/127] fix(lint): fix code style by eslint. --- extension-src/.eslintrc.yaml | 3 ++- extension-src/bmap/BMapView.js | 2 +- extension-src/dataTool/gexf.js | 17 +++++++++-------- src/.eslintrc.yaml | 3 ++- src/chart/funnel/funnelLayout.js | 12 ++++++------ src/chart/line/LineView.js | 12 ++++++------ src/chart/pie/PieView.js | 3 ++- src/chart/sunburst/SunburstPiece.js | 3 ++- src/chart/sunburst/sunburstLayout.js | 14 +++++++------- src/component/axisPointer.js | 4 ++-- src/component/axisPointer/BaseAxisPointer.js | 4 ++-- src/component/dataZoom/DataZoomModel.js | 6 +++--- src/component/graphic.js | 2 +- src/component/toolbox/ToolboxView.js | 3 ++- src/coord/single/singleAxisHelper.js | 5 ++--- src/data/helper/completeDimensions.js | 4 ++-- src/layout/barPolar.js | 3 +-- src/model/mixin/lineStyle.js | 16 ++++++++-------- src/view/Component.js | 8 ++++---- 19 files changed, 64 insertions(+), 60 deletions(-) diff --git a/extension-src/.eslintrc.yaml b/extension-src/.eslintrc.yaml index 3c0e1c30a4..76be321ba7 100644 --- a/extension-src/.eslintrc.yaml +++ b/extension-src/.eslintrc.yaml @@ -1,5 +1,6 @@ parserOptions: - ecmaVersion: 3 + # If using ES Module, ecmaVersion have to be set as `2015`. + ecmaVersion: 2015 sourceType: "module" env: browser: true diff --git a/extension-src/bmap/BMapView.js b/extension-src/bmap/BMapView.js index b6ee812d1e..b69149e48c 100644 --- a/extension-src/bmap/BMapView.js +++ b/extension-src/bmap/BMapView.js @@ -104,7 +104,7 @@ export default echarts.extendComponentView({ /* map 3.0 */ var originalStyle2 = bMapModel.__mapStyle2; - var newMapStyle2 = bMapModel.get('mapStyleV2') || {}; + var newMapStyle2 = bMapModel.get('mapStyleV2') || {}; // FIXME, Not use JSON methods var mapStyleStr2 = JSON.stringify(newMapStyle2); if (JSON.stringify(originalStyle2) !== mapStyleStr2) { diff --git a/extension-src/dataTool/gexf.js b/extension-src/dataTool/gexf.js index ef3d0a6b86..8883e1aa1a 100644 --- a/extension-src/dataTool/gexf.js +++ b/extension-src/dataTool/gexf.js @@ -99,7 +99,7 @@ function parseNodes(parent, attributesMap) { // z } if (vizColorDom) { - node.itemStyle.normal.color = 'rgb(' +[ + node.itemStyle.normal.color = 'rgb(' + [ getAttr(vizColorDom, 'r') | 0, getAttr(vizColorDom, 'g') | 0, getAttr(vizColorDom, 'b') | 0 @@ -130,7 +130,7 @@ function parseNodes(parent, attributesMap) { attValue = parseFloat(attValue); break; case 'boolean': - attValue = attValue.toLowerCase() == 'true'; + attValue = attValue.toLowerCase() === 'true'; break; default: } @@ -189,16 +189,17 @@ function getAttr(el, attrName) { return el.getAttribute(attrName); } -function getChildByTagName (parent, tagName) { +function getChildByTagName(parent, tagName) { var node = parent.firstChild; while (node) { if ( - node.nodeType != 1 || - node.nodeName.toLowerCase() != tagName.toLowerCase() + node.nodeType !== 1 + || node.nodeName.toLowerCase() !== tagName.toLowerCase() ) { node = node.nextSibling; - } else { + } + else { return node; } } @@ -206,11 +207,11 @@ function getChildByTagName (parent, tagName) { return null; } -function getChildrenByTagName (parent, tagName) { +function getChildrenByTagName(parent, tagName) { var node = parent.firstChild; var children = []; while (node) { - if (node.nodeName.toLowerCase() == tagName.toLowerCase()) { + if (node.nodeName.toLowerCase() === tagName.toLowerCase()) { children.push(node); } node = node.nextSibling; diff --git a/src/.eslintrc.yaml b/src/.eslintrc.yaml index 3c0e1c30a4..76be321ba7 100644 --- a/src/.eslintrc.yaml +++ b/src/.eslintrc.yaml @@ -1,5 +1,6 @@ parserOptions: - ecmaVersion: 3 + # If using ES Module, ecmaVersion have to be set as `2015`. + ecmaVersion: 2015 sourceType: "module" env: browser: true diff --git a/src/chart/funnel/funnelLayout.js b/src/chart/funnel/funnelLayout.js index 1d6743629b..9922a6b47f 100644 --- a/src/chart/funnel/funnelLayout.js +++ b/src/chart/funnel/funnelLayout.js @@ -104,7 +104,7 @@ function labelLayout(data) { x2 = x1 - labelLineLen; textX = x2 - 5; textAlign = 'right'; - } + } else if (labelPosition === 'right') { // Right side x1 = (points[1][0] + points[2][0]) / 2; @@ -112,7 +112,7 @@ function labelLayout(data) { x2 = x1 + labelLineLen; textX = x2 + 5; textAlign = 'left'; - } + } else if (labelPosition === 'rightTop') { // RightTop side x1 = points[1][0]; @@ -120,7 +120,7 @@ function labelLayout(data) { x2 = x1 + labelLineLen; textX = x2 + 5; textAlign = 'top'; - } + } else if (labelPosition === 'rightBottom') { // RightBottom side x1 = points[2][0]; @@ -128,7 +128,7 @@ function labelLayout(data) { x2 = x1 + labelLineLen; textX = x2 + 5; textAlign = 'bottom'; - } + } else if (labelPosition === 'leftTop') { // LeftTop side x1 = points[0][0]; @@ -136,7 +136,7 @@ function labelLayout(data) { x2 = x1 - labelLineLen; textX = x2 - 5; textAlign = 'right'; - } + } else if (labelPosition === 'leftBottom') { // LeftBottom side x1 = points[3][0]; @@ -144,7 +144,7 @@ function labelLayout(data) { x2 = x1 - labelLineLen; textX = x2 - 5; textAlign = 'right'; - } + } else { // Right side x1 = (points[1][0] + points[2][0]) / 2; diff --git a/src/chart/line/LineView.js b/src/chart/line/LineView.js index 501f026a14..fb81921557 100644 --- a/src/chart/line/LineView.js +++ b/src/chart/line/LineView.js @@ -787,11 +787,11 @@ export default ChartView.extend({ } }); - this._polyline - = this._polygon - = this._coordSys - = this._points - = this._stackedOnPoints - = this._data = null; + this._polyline = + this._polygon = + this._coordSys = + this._points = + this._stackedOnPoints = + this._data = null; } }); \ No newline at end of file diff --git a/src/chart/pie/PieView.js b/src/chart/pie/PieView.js index b766c3d398..69e69036a0 100644 --- a/src/chart/pie/PieView.js +++ b/src/chart/pie/PieView.js @@ -141,7 +141,8 @@ piePieceProto.updateData = function (data, idx, firstCreate) { if (animationTypeUpdate === 'expansion') { // Sectors are set to be target shape and an overlaying clipPath is used for animation sector.setShape(sectorShape); - } else { + } + else { // Transition animation from the old shape graphic.updateProps(sector, { shape: sectorShape diff --git a/src/chart/sunburst/SunburstPiece.js b/src/chart/sunburst/SunburstPiece.js index 4c920c100c..79ca4c3559 100644 --- a/src/chart/sunburst/SunburstPiece.js +++ b/src/chart/sunburst/SunburstPiece.js @@ -292,7 +292,8 @@ SunburstPieceProto._updateLabel = function (seriesModel, visualColor, state) { else if (rotate < -Math.PI / 2) { rotate += Math.PI; } - } else if (typeof rotateType === 'number') { + } + else if (typeof rotateType === 'number') { rotate = rotateType * Math.PI / 180; } label.attr('rotation', rotate); diff --git a/src/chart/sunburst/sunburstLayout.js b/src/chart/sunburst/sunburstLayout.js index 7b9be2c5c2..ae390735bc 100644 --- a/src/chart/sunburst/sunburstLayout.js +++ b/src/chart/sunburst/sunburstLayout.js @@ -21,7 +21,7 @@ import { parsePercent } from '../../util/number'; import * as zrUtil from 'zrender/src/core/util'; -var PI2 = Math.PI * 2; +// var PI2 = Math.PI * 2; var RADIAN = Math.PI / 180; export default function (seriesType, ecModel, api, payload) { @@ -74,8 +74,8 @@ export default function (seriesType, ecModel, api, payload) { var stillShowZeroSum = seriesModel.get('stillShowZeroSum'); // In the case some sector angle is smaller than minAngle - var restAngle = PI2; - var valueSumLargerThanMinAngle = 0; + // var restAngle = PI2; + // var valueSumLargerThanMinAngle = 0; var dir = clockwise ? 1 : -1; @@ -99,11 +99,11 @@ export default function (seriesType, ecModel, api, payload) { ? unitRadian : (value * unitRadian); if (angle < minAngle) { angle = minAngle; - restAngle -= minAngle; - } - else { - valueSumLargerThanMinAngle += value; + // restAngle -= minAngle; } + // else { + // valueSumLargerThanMinAngle += value; + // } endAngle = startAngle + dir * angle; diff --git a/src/component/axisPointer.js b/src/component/axisPointer.js index 27ad9817cd..7877103f8c 100644 --- a/src/component/axisPointer.js +++ b/src/component/axisPointer.js @@ -51,8 +51,8 @@ echarts.registerPreprocessor(function (option) { echarts.registerProcessor(echarts.PRIORITY.PROCESSOR.STATISTIC, function (ecModel, api) { // Build axisPointerModel, mergin tooltip.axisPointer model for each axis. // allAxesInfo should be updated when setOption performed. - ecModel.getComponent('axisPointer').coordSysAxesInfo - = axisPointerModelHelper.collect(ecModel, api); + ecModel.getComponent('axisPointer').coordSysAxesInfo = + axisPointerModelHelper.collect(ecModel, api); }); // Broadcast to all views. diff --git a/src/component/axisPointer/BaseAxisPointer.js b/src/component/axisPointer/BaseAxisPointer.js index 6b206bbdfe..f97ee57562 100644 --- a/src/component/axisPointer/BaseAxisPointer.js +++ b/src/component/axisPointer/BaseAxisPointer.js @@ -128,8 +128,8 @@ BaseAxisPointer.prototype = { } this._lastGraphicKey = graphicKey; - var moveAnimation = this._moveAnimation - = this.determineAnimation(axisModel, axisPointerModel); + var moveAnimation = this._moveAnimation = + this.determineAnimation(axisModel, axisPointerModel); if (!group) { group = this._group = new graphic.Group(); diff --git a/src/component/dataZoom/DataZoomModel.js b/src/component/dataZoom/DataZoomModel.js index 9c5f6a52fe..99f5b1c4e8 100644 --- a/src/component/dataZoom/DataZoomModel.js +++ b/src/component/dataZoom/DataZoomModel.js @@ -382,9 +382,9 @@ var DataZoomModel = echarts.extendComponentModel({ } if (this._autoThrottle) { var globalOption = this.ecModel.option; - this.option.throttle - = (globalOption.animation && globalOption.animationDurationUpdate > 0) - ? 100 : 20; + this.option.throttle = ( + globalOption.animation && globalOption.animationDurationUpdate > 0 + ) ? 100 : 20; } }, diff --git a/src/component/graphic.js b/src/component/graphic.js index 457cc4c4f5..92674a70ed 100644 --- a/src/component/graphic.js +++ b/src/component/graphic.js @@ -402,7 +402,7 @@ echarts.extendComponentView({ }; // PENDING - // Currently, when `bounding: 'all'`, the union bounding rect of the group + // Currently, when `bounding: 'all'`, the union bounding rect of the group // does not include the rect of [0, 0, group.width, group.height], which // is probably weird for users. Should we make a break change for it? layoutUtil.positionElement( diff --git a/src/component/toolbox/ToolboxView.js b/src/component/toolbox/ToolboxView.js index 78d21395ad..35c3fc388f 100644 --- a/src/component/toolbox/ToolboxView.js +++ b/src/component/toolbox/ToolboxView.js @@ -185,7 +185,8 @@ export default echarts.extendComponentView({ path.setStyle({ text: titles[iconName], textPosition: iconStyleEmphasisModel.get('textPosition') || 'bottom', - textFill: iconStyleEmphasisModel.get('textFill') || hoverStyle.fill || hoverStyle.stroke || '#000', + textFill: iconStyleEmphasisModel.get('textFill') + || hoverStyle.fill || hoverStyle.stroke || '#000', textAlign: iconStyleEmphasisModel.get('textAlign') || 'center', textBackgroundColor: iconStyleEmphasisModel.get('textBackgroundColor'), textBorderRadius: iconStyleEmphasisModel.get('textBorderRadius'), diff --git a/src/coord/single/singleAxisHelper.js b/src/coord/single/singleAxisHelper.js index 60ac90b484..fa44fda8f5 100644 --- a/src/coord/single/singleAxisHelper.js +++ b/src/coord/single/singleAxisHelper.js @@ -57,9 +57,8 @@ export function layout(axisModel, opt) { var directionMap = {top: -1, bottom: 1, right: 1, left: -1}; - layout.labelDirection = layout.tickDirection - = layout.nameDirection - = directionMap[axisPosition]; + layout.labelDirection = layout.tickDirection = + layout.nameDirection = directionMap[axisPosition]; if (axisModel.get('axisTick.inside')) { layout.tickDirection = -layout.tickDirection; diff --git a/src/data/helper/completeDimensions.js b/src/data/helper/completeDimensions.js index 0034094f81..7bdddd95f3 100644 --- a/src/data/helper/completeDimensions.js +++ b/src/data/helper/completeDimensions.js @@ -153,8 +153,8 @@ function completeDimensions(sysDims, source, opt) { // `coordDimIndex` should not be set directly. sysDimItemDimsDef = sysDimItem.dimsDef; sysDimItemOtherDims = sysDimItem.otherDims; - sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex - = sysDimItem.dimsDef = sysDimItem.otherDims = null; + sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex = + sysDimItem.dimsDef = sysDimItem.otherDims = null; } var dataDims = encodeDef.get(coordDim); diff --git a/src/layout/barPolar.js b/src/layout/barPolar.js index a5536ee6aa..88d7641a97 100644 --- a/src/layout/barPolar.js +++ b/src/layout/barPolar.js @@ -63,8 +63,7 @@ function barLayoutPolar(seriesType, ecModel, api) { var axisKey = getAxisKey(polar, baseAxis); var stackId = getSeriesStackId(seriesModel); - var columnLayoutInfo - = barWidthAndOffset[axisKey][stackId]; + var columnLayoutInfo = barWidthAndOffset[axisKey][stackId]; var columnOffset = columnLayoutInfo.offset; var columnWidth = columnLayoutInfo.width; var valueAxis = polar.getOtherAxis(baseAxis); diff --git a/src/model/mixin/lineStyle.js b/src/model/mixin/lineStyle.js index 1889875554..99b3f7cf0f 100644 --- a/src/model/mixin/lineStyle.js +++ b/src/model/mixin/lineStyle.js @@ -34,7 +34,7 @@ var getLineStyle = makeStyleMapper( export default { getLineStyle: function (excludes) { var style = getLineStyle(this, excludes); - // Always set lineDash whether dashed, otherwise we can not + // Always set lineDash whether dashed, otherwise we can not // erase the previous style when assigning to el.style. style.lineDash = this.getLineDash(style.lineWidth); return style; @@ -47,15 +47,15 @@ export default { var lineType = this.get('type'); var dotSize = Math.max(lineWidth, 2); var dashSize = lineWidth * 4; - return (lineType === 'solid' || lineType == null) - // Use `false` but not `null` for the solid line here, because `null` might be - // ignored when assigning to `el.style`. e.g., when setting `lineStyle.type` as - // `'dashed'` and `emphasis.lineStyle.type` as `'solid'` in graph series, the - // `lineDash` gotten form the latter one is not able to erase that from the former + return (lineType === 'solid' || lineType == null) + // Use `false` but not `null` for the solid line here, because `null` might be + // ignored when assigning to `el.style`. e.g., when setting `lineStyle.type` as + // `'dashed'` and `emphasis.lineStyle.type` as `'solid'` in graph series, the + // `lineDash` gotten form the latter one is not able to erase that from the former // one if using `null` here according to the emhpsis strategy in `util/graphic.js`. ? false - : lineType === 'dashed' - ? [dashSize, dashSize] + : lineType === 'dashed' + ? [dashSize, dashSize] : [dotSize, dotSize]; } }; \ No newline at end of file diff --git a/src/view/Component.js b/src/view/Component.js index 180c5028ad..c5bfc77cef 100644 --- a/src/view/Component.js +++ b/src/view/Component.js @@ -57,10 +57,10 @@ Component.prototype = { }; var componentProto = Component.prototype; -componentProto.updateView - = componentProto.updateLayout - = componentProto.updateVisual - = function (seriesModel, ecModel, api, payload) { +componentProto.updateView = + componentProto.updateLayout = + componentProto.updateVisual = + function (seriesModel, ecModel, api, payload) { // Do nothing; }; // Enable Component.extend. From 9cfe402330065ac79df96829a0d8f43e3416d72f Mon Sep 17 00:00:00 2001 From: pissang Date: Wed, 18 Sep 2019 21:20:54 +0800 Subject: [PATCH 110/127] test: fix random in the echarts caused random in demo inconsistent between versions. --- test/runTest/cli.js | 40 +++++++++++++++++++++--------------- test/runTest/config.js | 1 + test/runTest/runtime/main.js | 11 +++++++++- test/runTest/util.js | 23 ++++++++++++++++----- 4 files changed, 53 insertions(+), 22 deletions(-) diff --git a/test/runTest/cli.js b/test/runTest/cli.js index a0940d4914..39f85b9906 100644 --- a/test/runTest/cli.js +++ b/test/runTest/cli.js @@ -24,7 +24,7 @@ const fs = require('fs'); const path = require('path'); const program = require('commander'); const compareScreenshot = require('./compareScreenshot'); -const {testNameFromFile, fileNameFromTest, getVersionDir, buildRuntimeCode, waitTime} = require('./util'); +const {testNameFromFile, fileNameFromTest, getVersionDir, buildRuntimeCode, waitTime, getEChartsTestFileName} = require('./util'); const {origin} = require('./config'); const Timeline = require('./Timeline'); @@ -65,9 +65,9 @@ function getClientRelativePath(absPath) { function replaceEChartsVersion(interceptedRequest, version) { // TODO Extensions and maps if (interceptedRequest.url().endsWith('dist/echarts.js')) { - console.log('Use echarts version: ' + getVersionDir(version)); + console.log('Use echarts version: ' + version); interceptedRequest.continue({ - url: `${origin}/test/runTest/${getVersionDir(version)}/echarts.js` + url: `${origin}/test/runTest/${getVersionDir(version)}/${getEChartsTestFileName()}` }); } else { @@ -210,22 +210,30 @@ async function runTest(browser, testOpt, runtimeCode, expectedVersion, actualVer for (let shot of expectedResult.screenshots) { let expected = shot; let actual = actualResult.screenshots[idx++]; - let {diffRatio, diffPNG} = await compareScreenshot( - expected.screenshotPath, - actual.screenshotPath - ); - - let diffPath = `${path.resolve(__dirname, getScreenshotDir())}/${shot.screenshotName}-diff.png`; - await writePNG(diffPNG, diffPath); - - screenshots.push({ + let result = { actual: getClientRelativePath(actual.screenshotPath), expected: getClientRelativePath(expected.screenshotPath), - diff: getClientRelativePath(diffPath), name: actual.screenshotName, - desc: actual.desc, - diffRatio - }); + desc: actual.desc + }; + try { + let {diffRatio, diffPNG} = await compareScreenshot( + expected.screenshotPath, + actual.screenshotPath + ); + + let diffPath = `${path.resolve(__dirname, getScreenshotDir())}/${shot.screenshotName}-diff.png`; + await writePNG(diffPNG, diffPath); + + result.diff = getClientRelativePath(diffPath); + result.diffRatio = diffRatio; + } + catch(e) { + result.diff = ''; + result.diffRatio = 1; + console.log(e); + } + screenshots.push(result); } testOpt.results = screenshots; diff --git a/test/runTest/config.js b/test/runTest/config.js index dc4ddb68e9..71de615798 100644 --- a/test/runTest/config.js +++ b/test/runTest/config.js @@ -18,6 +18,7 @@ */ module.exports = { + testVersion: 'test-v0.1', port: 8866, origin: 'http://localhost:8866' }; \ No newline at end of file diff --git a/test/runTest/runtime/main.js b/test/runTest/runtime/main.js index d78d6391a5..50af6248bf 100644 --- a/test/runTest/runtime/main.js +++ b/test/runTest/runtime/main.js @@ -24,13 +24,22 @@ if (typeof __TEST_PLAYBACK_SPEED__ === 'undefined') { window.__TEST_PLAYBACK_SPEED__ = 1; } -let myRandom = new seedrandom('echarts-test'); +let myRandom = new seedrandom('echarts-random'); +// Random for echarts code. +// In case different echarts version called random different times. +// It will cause following random number all wrong. +let myRandom2 = new seedrandom('echarts-random-inner'); // Fixed random generator Math.random = function () { const val = myRandom(); return val; }; +window.__random__inner__ = function () { + const val = myRandom2(); + return val; +}; + window.addEventListener('DOMContentLoaded', () => { let style = document.createElement('style'); // Disable all css animation since it will cause screenshot inconsistent. diff --git a/test/runTest/util.js b/test/runTest/util.js index 2e551e3bf6..9bac45e4b6 100644 --- a/test/runTest/util.js +++ b/test/runTest/util.js @@ -24,6 +24,12 @@ const fs = require('fs'); const rollup = require('rollup'); const resolve = require('rollup-plugin-node-resolve'); const commonjs = require('rollup-plugin-commonjs'); +const util = require('util'); +const config = require('./config'); + +function modifyEChartsCode(code) { + return code.replace(/Math.random/g, '__random__inner__'); +} module.exports.testNameFromFile = function(fileName) { return path.basename(fileName, '.html'); @@ -43,19 +49,24 @@ module.exports.getActionsFullPath = function (testName) { return path.join(__dirname, 'actions', testName + '.json'); }; +module.exports.getEChartsTestFileName = function () { + return `echarts.test-${config.testVersion}.js`; +}; module.exports.prepareEChartsLib = function (version) { let versionFolder = path.join(__dirname, getVersionDir(version)); fse.ensureDirSync(versionFolder); if (!version || version === 'local') { // Developing version, make sure it's new build - return fse.copy( - path.join(__dirname, '../../dist/echarts.js'), - `${versionFolder}/echarts.js` - ); + fse.copySync(path.join(__dirname, '../../dist/echarts.js'), `${versionFolder}/echarts.js`); + let code = modifyEChartsCode(fs.readFileSync(`${versionFolder}/echarts.js`, 'utf-8')); + fs.writeFileSync(`${versionFolder}/${module.exports.getEChartsTestFileName()}`, code, 'utf-8'); + return Promise.resolve(); + } return new Promise(resolve => { - if (!fs.existsSync(`${versionFolder}/echarts.js`)) { + let testLibPath = `${versionFolder}/${module.exports.getEChartsTestFileName()}`; + if (!fs.existsSync(testLibPath)) { const file = fs.createWriteStream(`${versionFolder}/echarts.js`); console.log(`Downloading echarts@${version} from `, `https://cdn.jsdelivr.net/npm/echarts@${version}/dist/echarts.js`); @@ -63,6 +74,8 @@ module.exports.prepareEChartsLib = function (version) { response.pipe(file); file.on('finish', () => { + let code = modifyEChartsCode(fs.readFileSync(`${versionFolder}/echarts.js`, 'utf-8')); + fs.writeFileSync(testLibPath, code, 'utf-8'); resolve(); }); }); From de98ef690ddfc0e608c7a0e9af4d6f7b30beb0fd Mon Sep 17 00:00:00 2001 From: pissang Date: Thu, 19 Sep 2019 00:35:57 +0800 Subject: [PATCH 111/127] feat(clip): clip bar on grid. --- src/chart/bar/BarView.js | 70 ++++++++ src/chart/bar/BaseBarSeries.js | 3 + src/coord/cartesian/Cartesian2D.js | 4 +- src/layout/barGrid.js | 18 +-- test/clip.html | 250 ++++++++++++++++++++++++++++- 5 files changed, 319 insertions(+), 26 deletions(-) diff --git a/src/chart/bar/BarView.js b/src/chart/bar/BarView.js index 3d9db418fe..5cbcf86668 100644 --- a/src/chart/bar/BarView.js +++ b/src/chart/bar/BarView.js @@ -93,6 +93,10 @@ export default echarts.extendChartView({ var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null; + var coordSysClipArea = coord.getArea && coord.getArea(); + + var needsClip = seriesModel.get('clip'); + data.diff(oldData) .add(function (dataIndex) { if (!data.hasValue(dataIndex)) { @@ -101,6 +105,17 @@ export default echarts.extendChartView({ var itemModel = data.getItemModel(dataIndex); var layout = getLayout[coord.type](data, dataIndex, itemModel); + + if (needsClip) { + // Clip will modify the layout params. + // And return a boolean to determine if the shape are fully clipped. + var isClipped = clip[coord.type](coordSysClipArea, layout); + if (isClipped) { + group.remove(el); + return; + } + } + var el = elementCreator[coord.type]( data, dataIndex, itemModel, layout, isHorizontalOrRadial, animationModel ); @@ -123,6 +138,14 @@ export default echarts.extendChartView({ var itemModel = data.getItemModel(newIndex); var layout = getLayout[coord.type](data, newIndex, itemModel); + if (needsClip) { + var isClipped = clip[coord.type](coordSysClipArea, layout); + if (isClipped) { + group.remove(el); + return; + } + } + if (el) { graphic.updateProps(el, {shape: layout}, animationModel, newIndex); } @@ -191,6 +214,53 @@ export default echarts.extendChartView({ }); +var mathMax = Math.max; +var mathMin = Math.min; + +var clip = { + cartesian2d: function (coordSysBoundingRect, layout) { + var signWidth = layout.width < 0 ? -1 : 1; + var signHeight = layout.height < 0 ? -1 : 1; + // Needs positive width and height + if (signWidth < 0) { + layout.x += layout.width; + layout.width = -layout.width; + } + if (signHeight < 0) { + layout.y += layout.height; + layout.height = -layout.height; + } + + var x = mathMax(layout.x, coordSysBoundingRect.x); + var x2 = mathMin(layout.x + layout.width, coordSysBoundingRect.x + coordSysBoundingRect.width); + var y = mathMax(layout.y, coordSysBoundingRect.y); + var y2 = mathMin(layout.y + layout.height, coordSysBoundingRect.y + coordSysBoundingRect.height); + + layout.x = x; + layout.y = y; + layout.width = x2 - x; + layout.height = y2 - y; + + var clipped = layout.width < 0 || layout.height < 0;; + + // Reverse back + if (signWidth < 0) { + layout.x += layout.width; + layout.width = -layout.width; + } + if (signHeight < 0) { + layout.y += layout.height; + layout.height = -layout.height; + } + + return clipped; + }, + + polar: function (coordSysClipArea) { + return false; + } +}; + var elementCreator = { cartesian2d: function ( diff --git a/src/chart/bar/BaseBarSeries.js b/src/chart/bar/BaseBarSeries.js index 7c8b603b60..7916c4cf7b 100644 --- a/src/chart/bar/BaseBarSeries.js +++ b/src/chart/bar/BaseBarSeries.js @@ -65,6 +65,9 @@ export default SeriesModel.extend({ progressive: 3e3, progressiveChunkMode: 'mod', + // If clipped + // Only available on cartesian2d + clip: true, // barMaxWidth: null, // 默认自适应 // barWidth: null, diff --git a/src/coord/cartesian/Cartesian2D.js b/src/coord/cartesian/Cartesian2D.js index 511ddf1bb2..55ae631914 100644 --- a/src/coord/cartesian/Cartesian2D.js +++ b/src/coord/cartesian/Cartesian2D.js @@ -152,8 +152,8 @@ Cartesian2D.prototype = { * @return {BoundingRect} */ getArea: function () { - var xExtent = getAxisExtentWithGap(this.getAxis('x')); - var yExtent = getAxisExtentWithGap(this.getAxis('y')); + var xExtent = this.getAxis('x').getGlobalExtent(); + var yExtent = this.getAxis('y').getGlobalExtent(); var x = Math.min(xExtent[0], xExtent[1]); var y = Math.min(yExtent[0], yExtent[1]); var width = Math.max(xExtent[0], xExtent[1]) - x; diff --git a/src/layout/barGrid.js b/src/layout/barGrid.js index 94d8333029..5d211d814c 100644 --- a/src/layout/barGrid.js +++ b/src/layout/barGrid.js @@ -431,21 +431,5 @@ function isInLargeMode(seriesModel) { // See cases in `test/bar-start.html` and `#7412`, `#8747`. function getValueAxisStart(baseAxis, valueAxis, stacked) { - var extent = valueAxis.getGlobalExtent(); - var min; - var max; - if (extent[0] > extent[1]) { - min = extent[1]; - max = extent[0]; - } - else { - min = extent[0]; - max = extent[1]; - } - - var valueStart = valueAxis.toGlobalCoord(valueAxis.dataToCoord(0)); - valueStart < min && (valueStart = min); - valueStart > max && (valueStart = max); - - return valueStart; + return valueAxis.toGlobalCoord(valueAxis.dataToCoord(0)); } diff --git a/test/clip.html b/test/clip.html index d08e89dd70..f21eefadb5 100644 --- a/test/clip.html +++ b/test/clip.html @@ -49,7 +49,8 @@
-->
-
+
+
@@ -355,7 +356,13 @@ title: 'Lines Clip,(case from #10748). Should not overflow after zoomed in', option: option, height: 400, - buttons: makeToggleChartButtons() + buttons: makeToggleChartButtons(function (clip) { + chart.setOption({ + series: [{ + clip: clip + }] + }) + }) }); }) @@ -389,10 +396,6 @@ option = { animation: false, - legend: { - top: 'bottom', - data:['意向'] - }, tooltip: { triggerOn: 'none', position: function (pt) { @@ -512,7 +515,7 @@ }); } - var chart = testHelper.create(echarts, 'line-dataZoom', { + var chart = testHelper.create(echarts, 'line-dataZoom-time', { title: 'Line with dataZoom,(#10224). Should not be blank when selected a small area', option: option, height: 400, @@ -531,5 +534,238 @@ }) + + + + + + \ No newline at end of file From 3c78e9681e8da1b5402c8f5178f6930808b2961b Mon Sep 17 00:00:00 2001 From: pissang Date: Thu, 19 Sep 2019 16:01:35 +0800 Subject: [PATCH 112/127] feat(clip): support clip in custom series and large bar. --- src/chart/bar/BarSeries.js | 7 +- src/chart/bar/BarView.js | 17 +++ src/chart/bar/BaseBarSeries.js | 3 - src/chart/custom.js | 20 +++- test/clip.html | 213 ++++++++++++++++++++++++++++++--- 5 files changed, 241 insertions(+), 19 deletions(-) diff --git a/src/chart/bar/BarSeries.js b/src/chart/bar/BarSeries.js index 1b717a56dc..477a584b93 100644 --- a/src/chart/bar/BarSeries.js +++ b/src/chart/bar/BarSeries.js @@ -48,6 +48,11 @@ export default BaseBarSeries.extend({ progressiveThreshold = largeThreshold; } return progressiveThreshold; - } + }, + defaultOption: { + // If clipped + // Only available on cartesian2d + clip: true + } }); diff --git a/src/chart/bar/BarView.js b/src/chart/bar/BarView.js index 5cbcf86668..0219ef60a4 100644 --- a/src/chart/bar/BarView.js +++ b/src/chart/bar/BarView.js @@ -26,6 +26,7 @@ import Model from '../../model/Model'; import barItemStyle from './barItemStyle'; import Path from 'zrender/src/graphic/Path'; import {throttle} from '../../util/throttle'; +import {createClipPath} from '../helper/createClipPathFromCoordSys'; var BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'barBorderWidth']; var _eventPos = [0, 0]; @@ -97,6 +98,11 @@ export default echarts.extendChartView({ var needsClip = seriesModel.get('clip'); + // If there is clipPath created in large mode. Remove it. + group.removeClipPath(); + // We don't use clipPath in normal mode because we needs a perfect animation + // And don't want the label are clipped. + data.diff(oldData) .add(function (dataIndex) { if (!data.hasValue(dataIndex)) { @@ -181,6 +187,17 @@ export default echarts.extendChartView({ _renderLarge: function (seriesModel, ecModel, api) { this._clear(); createLarge(seriesModel, this.group); + + // Use clipPath in large mode. + var clipPath = seriesModel.get('clip') + ? createClipPath(seriesModel.coordinateSystem, false, seriesModel) + : null; + if (clipPath) { + this.group.setClipPath(clipPath); + } + else { + this.group.removeClipPath(null); + } }, _incrementalRenderLarge: function (params, seriesModel) { diff --git a/src/chart/bar/BaseBarSeries.js b/src/chart/bar/BaseBarSeries.js index 7916c4cf7b..7c8b603b60 100644 --- a/src/chart/bar/BaseBarSeries.js +++ b/src/chart/bar/BaseBarSeries.js @@ -65,9 +65,6 @@ export default SeriesModel.extend({ progressive: 3e3, progressiveChunkMode: 'mod', - // If clipped - // Only available on cartesian2d - clip: true, // barMaxWidth: null, // 默认自适应 // barWidth: null, diff --git a/src/chart/custom.js b/src/chart/custom.js index a48f187d2f..c279460e06 100644 --- a/src/chart/custom.js +++ b/src/chart/custom.js @@ -27,6 +27,7 @@ import DataDiffer from '../data/DataDiffer'; import SeriesModel from '../model/Series'; import Model from '../model/Model'; import ChartView from '../view/Chart'; +import {createClipPath} from './helper/createClipPathFromCoordSys'; import prepareCartesian2d from '../coord/cartesian/prepareCustom'; import prepareGeo from '../coord/geo/prepareCustom'; @@ -80,7 +81,13 @@ SeriesModel.extend({ z: 2, legendHoverLink: true, - useTransform: true + useTransform: true, + + // Custom series will not clip by default. + // Some case will use custom series to draw label + // For example https://echarts.apache.org/examples/en/editor.html?c=custom-gantt-flight + // Only works on polar and cartesian2d coordinate system. + clip: false // Cartesian coordinate system // xAxisIndex: 0, @@ -159,6 +166,17 @@ ChartView.extend({ }) .execute(); + // Do clipping + var clipPath = customSeries.get('clip') + ? createClipPath(customSeries.coordinateSystem, false, customSeries) + : null; + if (clipPath) { + group.setClipPath(clipPath); + } + else { + group.removeClipPath(); + } + this._data = data; }, diff --git a/test/clip.html b/test/clip.html index f21eefadb5..ecfca8c801 100644 --- a/test/clip.html +++ b/test/clip.html @@ -43,18 +43,6 @@ } -
-
- -
-
-
-
-
-
-
- +
+
+ + +
+ + +
+ + + +
\ No newline at end of file From 2bbb2975f3ae743b4f708c3d42c878e889dba4a5 Mon Sep 17 00:00:00 2001 From: pissang Date: Thu, 19 Sep 2019 17:33:00 +0800 Subject: [PATCH 113/127] test: add recorded action for clip test. not save result when replay in recorder page. --- test/clip.html | 11 ++- test/runTest/actions/__meta__.json | 3 +- test/runTest/actions/clip.json | 1 + test/runTest/cli.js | 113 ++++++++++++++++------------- test/runTest/server.js | 32 ++++---- 5 files changed, 94 insertions(+), 66 deletions(-) create mode 100644 test/runTest/actions/clip.json diff --git a/test/clip.html b/test/clip.html index ecfca8c801..ad7dd3d72b 100644 --- a/test/clip.html +++ b/test/clip.html @@ -315,12 +315,16 @@ dataZoom: [{ type: 'inside', xAxisIndex: 0, - filterMode: 'filter' + filterMode: 'filter', + start: 30, + end: 70 }, { type: 'inside', yAxisIndex: 0, - filterMode: 'weakFilter' + filterMode: 'weakFilter', + start: 30, + end: 70 } ], series: [{ @@ -349,7 +353,8 @@ buttons: makeToggleChartButtons(function (clip) { chart.setOption({ series: [{ - clip: clip + clip: clip, + data: lineData }] }) }) diff --git a/test/runTest/actions/__meta__.json b/test/runTest/actions/__meta__.json index 839a201ae5..b4e3080a2d 100644 --- a/test/runTest/actions/__meta__.json +++ b/test/runTest/actions/__meta__.json @@ -129,5 +129,6 @@ "treemap-option2": 1, "visualMap-categories": 1, "axes": 0, - "stackBar-dataZoom": 7 + "stackBar-dataZoom": 7, + "clip": 9 } \ No newline at end of file diff --git a/test/runTest/actions/clip.json b/test/runTest/actions/clip.json new file mode 100644 index 0000000000..53e9f6ee66 --- /dev/null +++ b/test/runTest/actions/clip.json @@ -0,0 +1 @@ +[{"name":"Action 1","ops":[{"type":"mousedown","time":447,"x":92,"y":75},{"type":"mouseup","time":559,"x":92,"y":75},{"time":560,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":749,"x":90,"y":75},{"type":"mousemove","time":949,"x":43,"y":75},{"type":"mousemove","time":1157,"x":34,"y":75},{"type":"mousedown","time":1225,"x":34,"y":75},{"type":"mouseup","time":1322,"x":34,"y":75},{"time":1323,"delay":400,"type":"screenshot-auto"}],"scrollY":0,"scrollX":0,"timestamp":1568880422331},{"name":"Action 2","ops":[{"type":"mousedown","time":442,"x":114,"y":110},{"type":"mouseup","time":519,"x":114,"y":110},{"time":520,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":562,"x":114,"y":110},{"type":"mousemove","time":763,"x":71,"y":108},{"type":"mousemove","time":971,"x":34,"y":106},{"type":"mousedown","time":1190,"x":34,"y":106},{"type":"mouseup","time":1272,"x":34,"y":106},{"time":1273,"delay":400,"type":"screenshot-auto"}],"scrollY":462,"scrollX":0,"timestamp":1568880431375},{"name":"Action 3","ops":[{"type":"mousedown","time":485,"x":107,"y":166},{"type":"mouseup","time":578,"x":107,"y":166},{"time":579,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":1324,"x":111,"y":165},{"type":"mousemove","time":1523,"x":169,"y":164},{"type":"mousemove","time":1729,"x":171,"y":164},{"type":"mousemove","time":1955,"x":81,"y":159},{"type":"mousemove","time":2156,"x":51,"y":166},{"type":"mousedown","time":2279,"x":41,"y":163},{"type":"mousemove","time":2364,"x":41,"y":163},{"type":"mouseup","time":2382,"x":41,"y":163},{"time":2383,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":3240,"x":52,"y":163},{"type":"mousemove","time":3441,"x":151,"y":165},{"type":"mousemove","time":3648,"x":195,"y":166},{"type":"mousemove","time":3808,"x":195,"y":167},{"type":"mousedown","time":4039,"x":195,"y":167},{"type":"mouseup","time":4163,"x":195,"y":167},{"time":4164,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":4608,"x":198,"y":166},{"type":"mousemove","time":4808,"x":243,"y":163},{"type":"mousemove","time":5017,"x":256,"y":163},{"type":"mousedown","time":5066,"x":256,"y":163},{"type":"mouseup","time":5156,"x":256,"y":163},{"time":5157,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":6210,"x":248,"y":163},{"type":"mousemove","time":6417,"x":204,"y":165},{"type":"mousedown","time":6550,"x":204,"y":165},{"type":"mouseup","time":6668,"x":204,"y":165},{"time":6669,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":7277,"x":204,"y":165},{"type":"mousemove","time":7477,"x":143,"y":165},{"type":"mousemove","time":7683,"x":121,"y":167},{"type":"mousedown","time":7819,"x":121,"y":167},{"type":"mouseup","time":7911,"x":121,"y":167},{"time":7912,"delay":1000,"type":"screenshot-auto"}],"scrollY":902,"scrollX":0,"timestamp":1568880510067},{"name":"Action 4","ops":[{"type":"mousedown","time":609,"x":126,"y":123},{"type":"mouseup","time":686,"x":126,"y":123},{"time":687,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":970,"x":124,"y":123},{"type":"mousemove","time":1171,"x":88,"y":122},{"type":"mousemove","time":1377,"x":7,"y":117},{"type":"mousemove","time":1588,"x":12,"y":118},{"type":"mousedown","time":1653,"x":12,"y":118},{"type":"mouseup","time":1744,"x":12,"y":118},{"time":1745,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":1937,"x":17,"y":121},{"type":"mousemove","time":2138,"x":305,"y":280},{"type":"mousemove","time":2338,"x":380,"y":323},{"type":"mousedown","time":2479,"x":400,"y":329},{"type":"mousemove","time":2538,"x":390,"y":329},{"type":"mousemove","time":2754,"x":212,"y":328},{"type":"mousemove","time":2961,"x":163,"y":325},{"type":"mouseup","time":3130,"x":163,"y":326},{"time":3131,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":3179,"x":163,"y":326},{"type":"mousemove","time":3189,"x":164,"y":325},{"type":"mousemove","time":3389,"x":181,"y":276},{"type":"mousedown","time":3512,"x":177,"y":275},{"type":"mousemove","time":3592,"x":229,"y":304},{"type":"mousemove","time":3810,"x":650,"y":408},{"type":"mousemove","time":4014,"x":719,"y":408},{"type":"mousemove","time":4189,"x":719,"y":407},{"type":"mouseup","time":4421,"x":719,"y":407},{"time":4422,"delay":200,"type":"screenshot-auto"}],"scrollY":1443,"scrollX":0,"timestamp":1568880857563},{"name":"Action 5","ops":[{"type":"mousemove","time":52,"x":401,"y":278},{"type":"mousemove","time":252,"x":375,"y":243},{"type":"mousemove","time":455,"x":365,"y":207},{"type":"mousemove","time":662,"x":365,"y":202},{"type":"mousedown","time":712,"x":365,"y":202},{"type":"mouseup","time":812,"x":365,"y":202},{"time":813,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":955,"x":366,"y":206},{"type":"mousemove","time":1161,"x":380,"y":278},{"type":"mousemove","time":1388,"x":374,"y":283},{"type":"mousedown","time":1578,"x":371,"y":285},{"type":"mousemove","time":1595,"x":371,"y":285},{"type":"mousemove","time":1829,"x":413,"y":287},{"type":"mousemove","time":2079,"x":421,"y":286},{"type":"mouseup","time":2133,"x":421,"y":286},{"time":2134,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":2739,"x":418,"y":282},{"type":"mousemove","time":2940,"x":391,"y":213},{"type":"mousemove","time":3147,"x":398,"y":199},{"type":"mousedown","time":3181,"x":398,"y":199},{"type":"mouseup","time":3280,"x":398,"y":199},{"time":3281,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":3507,"x":398,"y":200},{"type":"mousemove","time":3722,"x":342,"y":257},{"type":"mousemove","time":3948,"x":329,"y":264},{"type":"mousedown","time":4048,"x":329,"y":264},{"type":"mousemove","time":4125,"x":329,"y":264},{"type":"mousemove","time":4332,"x":380,"y":271},{"type":"mousemove","time":4549,"x":388,"y":273},{"type":"mouseup","time":4617,"x":388,"y":273},{"time":4618,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":5025,"x":378,"y":272},{"type":"mousemove","time":5228,"x":215,"y":145},{"type":"mousemove","time":5434,"x":143,"y":88},{"type":"mousemove","time":5751,"x":141,"y":102},{"type":"mousedown","time":5869,"x":141,"y":102},{"type":"mouseup","time":5968,"x":141,"y":102},{"time":5969,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":6843,"x":140,"y":102},{"type":"mousemove","time":7043,"x":119,"y":101},{"type":"mousemove","time":7244,"x":94,"y":100},{"type":"mousedown","time":7452,"x":75,"y":99},{"type":"mousemove","time":7472,"x":75,"y":99},{"type":"mouseup","time":7542,"x":75,"y":99},{"time":7543,"delay":200,"type":"screenshot-auto"}],"scrollY":1961,"scrollX":0,"timestamp":1568880882433},{"name":"Action 6","ops":[{"type":"mousedown","time":312,"x":367,"y":231},{"type":"mouseup","time":395,"x":367,"y":231},{"time":396,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":534,"x":366,"y":236},{"type":"mousemove","time":735,"x":336,"y":315},{"type":"mousemove","time":943,"x":325,"y":330},{"type":"mousedown","time":1010,"x":325,"y":330},{"type":"mousemove","time":1101,"x":327,"y":330},{"type":"mousemove","time":1301,"x":457,"y":340},{"type":"mousemove","time":1501,"x":468,"y":339},{"type":"mousemove","time":1702,"x":472,"y":341},{"type":"mousemove","time":1918,"x":499,"y":340},{"type":"mousemove","time":2126,"x":501,"y":340},{"type":"mousemove","time":2184,"x":498,"y":341},{"type":"mousemove","time":2392,"x":490,"y":343},{"type":"mouseup","time":2509,"x":490,"y":343},{"time":2510,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":2952,"x":488,"y":341},{"type":"mousemove","time":3152,"x":437,"y":241},{"type":"mousemove","time":3359,"x":397,"y":208},{"type":"mousedown","time":3594,"x":397,"y":210},{"type":"mousemove","time":3602,"x":397,"y":210},{"type":"mouseup","time":3693,"x":397,"y":210},{"time":3694,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":3836,"x":397,"y":212},{"type":"mousemove","time":4043,"x":401,"y":271},{"type":"mousemove","time":4253,"x":384,"y":300},{"type":"mousemove","time":4460,"x":382,"y":304},{"type":"mousemove","time":4586,"x":380,"y":305},{"type":"mousemove","time":4787,"x":356,"y":313},{"type":"mousedown","time":4925,"x":367,"y":314},{"type":"mousemove","time":4996,"x":367,"y":314},{"type":"mousemove","time":5212,"x":421,"y":315},{"type":"mousemove","time":5370,"x":421,"y":315},{"type":"mousemove","time":5585,"x":421,"y":314},{"type":"mouseup","time":5698,"x":421,"y":314},{"time":5699,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":5820,"x":421,"y":313},{"type":"mousemove","time":6020,"x":413,"y":276},{"type":"mousemove","time":6228,"x":402,"y":223},{"type":"mousedown","time":6468,"x":402,"y":222},{"type":"mousemove","time":6579,"x":402,"y":222},{"type":"mouseup","time":6897,"x":402,"y":222},{"time":6898,"delay":200,"type":"screenshot-auto"}],"scrollY":2429,"scrollX":0,"timestamp":1568880942095},{"name":"Action 7","ops":[{"type":"mousedown","time":373,"x":117,"y":170},{"type":"mouseup","time":471,"x":117,"y":170},{"time":472,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":696,"x":112,"y":170},{"type":"mousemove","time":896,"x":42,"y":166},{"type":"mousemove","time":1104,"x":40,"y":167},{"type":"mousedown","time":1321,"x":40,"y":167},{"type":"mouseup","time":1404,"x":40,"y":167},{"time":1405,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":1696,"x":45,"y":169},{"type":"mousemove","time":1897,"x":172,"y":177},{"type":"mousemove","time":2098,"x":178,"y":173},{"type":"mousedown","time":2272,"x":178,"y":173},{"type":"mousemove","time":2305,"x":178,"y":173},{"type":"mouseup","time":2359,"x":178,"y":173},{"time":2360,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":3047,"x":177,"y":173},{"type":"mousemove","time":3248,"x":132,"y":170},{"type":"mousedown","time":3372,"x":132,"y":170},{"type":"mouseup","time":3462,"x":132,"y":170},{"time":3463,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":3748,"x":126,"y":170},{"type":"mousemove","time":3949,"x":84,"y":170},{"type":"mousemove","time":4159,"x":65,"y":169},{"type":"mousemove","time":4390,"x":56,"y":171},{"type":"mousedown","time":4400,"x":56,"y":171},{"type":"mouseup","time":4474,"x":56,"y":171},{"time":4475,"delay":200,"type":"screenshot-auto"},{"type":"mousemove","time":4674,"x":56,"y":171}],"scrollY":2881,"scrollX":0,"timestamp":1568880957974},{"name":"Action 8","ops":[{"type":"mousedown","time":703,"x":32,"y":63},{"type":"mouseup","time":950,"x":32,"y":63},{"time":951,"delay":600,"type":"screenshot-auto"},{"type":"mousemove","time":1392,"x":39,"y":63},{"type":"mousemove","time":1600,"x":144,"y":67},{"type":"mousemove","time":1884,"x":103,"y":64},{"type":"mousedown","time":1903,"x":103,"y":64},{"type":"mousemove","time":2001,"x":102,"y":64},{"type":"mouseup","time":2010,"x":102,"y":64},{"time":2011,"delay":600,"type":"screenshot-auto"},{"type":"mousemove","time":2526,"x":115,"y":66},{"type":"mousemove","time":2727,"x":249,"y":64},{"type":"mousemove","time":2927,"x":254,"y":63},{"type":"mousedown","time":3284,"x":254,"y":63},{"type":"mouseup","time":3403,"x":254,"y":63},{"time":3404,"delay":600,"type":"screenshot-auto"},{"type":"mousemove","time":4761,"x":251,"y":63},{"type":"mousemove","time":4962,"x":131,"y":67},{"type":"mousemove","time":5163,"x":68,"y":66},{"type":"mousemove","time":5372,"x":50,"y":67},{"type":"mousedown","time":5383,"x":50,"y":67},{"type":"mouseup","time":5475,"x":50,"y":67},{"time":5476,"delay":600,"type":"screenshot-auto"},{"type":"mousemove","time":5944,"x":62,"y":66},{"type":"mousemove","time":6144,"x":188,"y":60},{"type":"mousemove","time":6356,"x":190,"y":59},{"type":"mousedown","time":6508,"x":190,"y":66},{"type":"mousemove","time":6591,"x":190,"y":66},{"type":"mouseup","time":6613,"x":190,"y":66},{"time":6614,"delay":600,"type":"screenshot-auto"},{"type":"mousemove","time":7182,"x":191,"y":67},{"type":"mousemove","time":7391,"x":193,"y":68}],"scrollY":3481,"scrollX":0,"timestamp":1568881004231},{"name":"Action 9","ops":[{"type":"mousemove","time":82,"x":111,"y":100},{"type":"mousemove","time":283,"x":117,"y":80},{"type":"mousemove","time":483,"x":118,"y":72},{"type":"mousedown","time":626,"x":118,"y":72},{"type":"mouseup","time":708,"x":118,"y":72},{"time":709,"delay":600,"type":"screenshot-auto"},{"type":"mousemove","time":1184,"x":114,"y":72},{"type":"mousemove","time":1384,"x":56,"y":73},{"type":"mousemove","time":1585,"x":46,"y":72},{"type":"mousemove","time":1792,"x":37,"y":70},{"type":"mousedown","time":2261,"x":37,"y":70},{"type":"mouseup","time":2351,"x":37,"y":70},{"time":2352,"delay":600,"type":"screenshot-auto"},{"type":"mousemove","time":2734,"x":38,"y":70},{"type":"mousemove","time":2935,"x":504,"y":304},{"type":"mousemove","time":3136,"x":613,"y":321},{"type":"mousedown","time":3252,"x":657,"y":323},{"type":"mousemove","time":3344,"x":657,"y":323},{"type":"mousemove","time":3553,"x":520,"y":319},{"type":"mousemove","time":3754,"x":415,"y":314},{"type":"mousemove","time":3964,"x":253,"y":312},{"type":"mousemove","time":4180,"x":241,"y":311},{"type":"mousemove","time":4396,"x":237,"y":311},{"type":"mouseup","time":4715,"x":237,"y":311},{"time":4716,"delay":600,"type":"screenshot-auto"},{"type":"mousemove","time":4805,"x":232,"y":307},{"type":"mousemove","time":5008,"x":162,"y":167},{"type":"mousemove","time":5218,"x":142,"y":124},{"type":"mousemove","time":5421,"x":106,"y":70},{"type":"mousedown","time":5570,"x":103,"y":65},{"type":"mousemove","time":5631,"x":103,"y":65},{"type":"mouseup","time":5681,"x":103,"y":65},{"time":5682,"delay":600,"type":"screenshot-auto"},{"type":"mousemove","time":5856,"x":104,"y":65},{"type":"mousemove","time":6155,"x":92,"y":64},{"type":"mousemove","time":6365,"x":13,"y":65},{"type":"mousemove","time":6616,"x":11,"y":65},{"type":"mousemove","time":6739,"x":13,"y":65},{"type":"mousedown","time":6869,"x":21,"y":65},{"type":"mousemove","time":6950,"x":21,"y":65},{"type":"mouseup","time":6992,"x":21,"y":65},{"time":6993,"delay":600,"type":"screenshot-auto"}],"scrollY":3976,"scrollX":0,"timestamp":1568881022338}] \ No newline at end of file diff --git a/test/runTest/cli.js b/test/runTest/cli.js index 39f85b9906..20767102a3 100644 --- a/test/runTest/cli.js +++ b/test/runTest/cli.js @@ -35,7 +35,8 @@ program .option('-s, --speed ', 'Playback speed') .option('--expected ', 'Expected version') .option('--actual ', 'Actual version') - .option('--renderer ', 'svg/canvas renderer'); + .option('--renderer ', 'svg/canvas renderer') + .option('--no-save', 'Don\'t save result'); program.parse(process.argv); @@ -115,6 +116,9 @@ async function runActions(page, testOpt, isExpected, screenshots) { let count = 0; async function _innerTakeScreenshot() { + if (!program.save) { + return; + } const desc = action.desc || action.name; const {screenshotName, screenshotPath} = await takeScreenshot(page, false, testOpt.fileUrl, desc, isExpected, count++); screenshots.push({screenshotName, desc, screenshotPath}); @@ -165,9 +169,11 @@ async function runTestPage(browser, testOpt, version, runtimeCode, isExpected) { await waitTime(500); // Wait for animation or something else. Pending // Final shot. await page.mouse.move(0, 0); - let desc = 'Full Shot'; - const {screenshotName, screenshotPath} = await takeScreenshot(page, true, fileUrl, desc, isExpected); - screenshots.push({screenshotName, desc, screenshotPath}); + if (program.save) { + let desc = 'Full Shot'; + const {screenshotName, screenshotPath} = await takeScreenshot(page, true, fileUrl, desc, isExpected); + screenshots.push({screenshotName, desc, screenshotPath}); + } await runActions(page, testOpt, isExpected, screenshots); } @@ -198,54 +204,61 @@ async function runTest(browser, testOpt, runtimeCode, expectedVersion, actualVer return; } - testOpt.status === 'running'; - const expectedResult = await runTestPage(browser, testOpt, expectedVersion, runtimeCode, true); - const actualResult = await runTestPage(browser, testOpt, actualVersion, runtimeCode, false); + if (program.save) { + testOpt.status === 'running'; + + const expectedResult = await runTestPage(browser, testOpt, expectedVersion, runtimeCode, true); + const actualResult = await runTestPage(browser, testOpt, actualVersion, runtimeCode, false); + + // sortScreenshots(expectedResult.screenshots); + // sortScreenshots(actualResult.screenshots); + + const screenshots = []; + let idx = 0; + for (let shot of expectedResult.screenshots) { + let expected = shot; + let actual = actualResult.screenshots[idx++]; + let result = { + actual: getClientRelativePath(actual.screenshotPath), + expected: getClientRelativePath(expected.screenshotPath), + name: actual.screenshotName, + desc: actual.desc + }; + try { + let {diffRatio, diffPNG} = await compareScreenshot( + expected.screenshotPath, + actual.screenshotPath + ); - // sortScreenshots(expectedResult.screenshots); - // sortScreenshots(actualResult.screenshots); + let diffPath = `${path.resolve(__dirname, getScreenshotDir())}/${shot.screenshotName}-diff.png`; + await writePNG(diffPNG, diffPath); - const screenshots = []; - let idx = 0; - for (let shot of expectedResult.screenshots) { - let expected = shot; - let actual = actualResult.screenshots[idx++]; - let result = { - actual: getClientRelativePath(actual.screenshotPath), - expected: getClientRelativePath(expected.screenshotPath), - name: actual.screenshotName, - desc: actual.desc - }; - try { - let {diffRatio, diffPNG} = await compareScreenshot( - expected.screenshotPath, - actual.screenshotPath - ); - - let diffPath = `${path.resolve(__dirname, getScreenshotDir())}/${shot.screenshotName}-diff.png`; - await writePNG(diffPNG, diffPath); - - result.diff = getClientRelativePath(diffPath); - result.diffRatio = diffRatio; - } - catch(e) { - result.diff = ''; - result.diffRatio = 1; - console.log(e); + result.diff = getClientRelativePath(diffPath); + result.diffRatio = diffRatio; + } + catch(e) { + result.diff = ''; + result.diffRatio = 1; + console.log(e); + } + screenshots.push(result); } - screenshots.push(result); - } - testOpt.results = screenshots; - testOpt.status = 'finished'; - testOpt.actualLogs = actualResult.logs; - testOpt.expectedLogs = expectedResult.logs; - testOpt.actualErrors = actualResult.errors; - testOpt.expectedErrors = expectedResult.errors; - testOpt.actualVersion = actualVersion; - testOpt.expectedVersion = expectedVersion; - testOpt.useSVG = program.renderer === 'svg'; - testOpt.lastRun = Date.now(); + testOpt.results = screenshots; + testOpt.status = 'finished'; + testOpt.actualLogs = actualResult.logs; + testOpt.expectedLogs = expectedResult.logs; + testOpt.actualErrors = actualResult.errors; + testOpt.expectedErrors = expectedResult.errors; + testOpt.actualVersion = actualVersion; + testOpt.expectedVersion = expectedVersion; + testOpt.useSVG = program.renderer === 'svg'; + testOpt.lastRun = Date.now(); + } + else { + // Only run once + await runTestPage(browser, testOpt, 'local', runtimeCode, true); + } } async function runTests(pendingTests) { @@ -270,7 +283,9 @@ async function runTests(pendingTests) { console.log(e); } - process.send(testOpt); + if (program.save) { + process.send(testOpt); + } } } catch(e) { diff --git a/test/runTest/server.js b/test/runTest/server.js index 565cb2195e..04ba560697 100644 --- a/test/runTest/server.js +++ b/test/runTest/server.js @@ -111,7 +111,8 @@ function startTests(testsNameList, socket, { replaySpeed, actualVersion, expectedVersion, - renderer + renderer, + noSave }) { console.log('Received: ', testsNameList.join(',')); @@ -122,16 +123,18 @@ function startTests(testsNameList, socket, { pendingTests = getTestsList().filter(testOpt => { return testsNameList.includes(testOpt.name); }); - pendingTests.forEach(testOpt => { - // Reset all tests results - testOpt.status = 'pending'; - testOpt.results = []; - }); - if (!aborted) { - socket.emit('update', {tests: getTestsList(), running: true}); - } + if (!noSave) { + pendingTests.forEach(testOpt => { + // Reset all tests results + testOpt.status = 'pending'; + testOpt.results = []; + }); + if (!aborted) { + socket.emit('update', {tests: getTestsList(), running: true}); + } + } let runningCount = 0; function onExit() { runningCount--; @@ -142,7 +145,7 @@ function startTests(testsNameList, socket, { } function onUpdate() { // Merge tests. - if (!aborted) { + if (!aborted && !noSave) { socket.emit('update', {tests: getTestsList(), running: true}); } } @@ -160,7 +163,8 @@ function startTests(testsNameList, socket, { '--actual', actualVersion, '--expected', expectedVersion, '--renderer', renderer, - ...(noHeadless ? ['--no-headless'] : []) + ...(noHeadless ? ['--no-headless'] : []), + ...(noSave ? ['--no-save'] : []) ]); runningCount++; } @@ -230,7 +234,8 @@ async function start() { replaySpeed: data.replaySpeed, actualVersion: data.actualVersion, expectedVersion: data.expectedVersion, - renderer: data.renderer + renderer: data.renderer, + noSave: false } ); } @@ -292,7 +297,8 @@ async function start() { replaySpeed: 2, actualVersion: data.actualVersion, expectedVersion: data.expectedVersion, - renderer: data.renderer + renderer: data.renderer, + noSave: true }); } catch (e) { console.error(e); } From 5c2d8cff57bd6ef0fb27527c500a5c2203f53dd2 Mon Sep 17 00:00:00 2001 From: pissang Date: Thu, 19 Sep 2019 18:32:03 +0800 Subject: [PATCH 114/127] fix(clip): only access clip option in series. --- src/chart/bar/BarView.js | 4 ++-- src/chart/custom.js | 2 +- src/chart/line/LineView.js | 2 +- src/chart/lines/LinesView.js | 2 +- src/chart/scatter/ScatterView.js | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/chart/bar/BarView.js b/src/chart/bar/BarView.js index 0219ef60a4..eb9f6c1a35 100644 --- a/src/chart/bar/BarView.js +++ b/src/chart/bar/BarView.js @@ -96,7 +96,7 @@ export default echarts.extendChartView({ var coordSysClipArea = coord.getArea && coord.getArea(); - var needsClip = seriesModel.get('clip'); + var needsClip = seriesModel.get('clip', true); // If there is clipPath created in large mode. Remove it. group.removeClipPath(); @@ -189,7 +189,7 @@ export default echarts.extendChartView({ createLarge(seriesModel, this.group); // Use clipPath in large mode. - var clipPath = seriesModel.get('clip') + var clipPath = seriesModel.get('clip', true) ? createClipPath(seriesModel.coordinateSystem, false, seriesModel) : null; if (clipPath) { diff --git a/src/chart/custom.js b/src/chart/custom.js index c279460e06..7c31bb7bb4 100644 --- a/src/chart/custom.js +++ b/src/chart/custom.js @@ -167,7 +167,7 @@ ChartView.extend({ .execute(); // Do clipping - var clipPath = customSeries.get('clip') + var clipPath = customSeries.get('clip', true) ? createClipPath(customSeries.coordinateSystem, false, customSeries) : null; if (clipPath) { diff --git a/src/chart/line/LineView.js b/src/chart/line/LineView.js index 5879308b95..b4b0bbfa6c 100644 --- a/src/chart/line/LineView.js +++ b/src/chart/line/LineView.js @@ -269,7 +269,7 @@ function createLineClipPath(coordSys, hasAnimation, seriesModel) { var isHorizontal = coordSys.getBaseAxis().isHorizontal(); var clipPath = createGridClipPath(coordSys, hasAnimation, seriesModel); // Expand clip shape to avoid clipping when line value exceeds axis - if (!seriesModel.get('clip')) { + if (!seriesModel.get('clip', true)) { var rectShape = clipPath.shape; var expandSize = Math.max(rectShape.width, rectShape.height); if (isHorizontal) { diff --git a/src/chart/lines/LinesView.js b/src/chart/lines/LinesView.js index 02b5c83401..42a249c7ee 100644 --- a/src/chart/lines/LinesView.js +++ b/src/chart/lines/LinesView.js @@ -77,7 +77,7 @@ export default echarts.extendChartView({ lineDraw.updateData(data); - var clipPath = seriesModel.get('clip') && createClipPath( + var clipPath = seriesModel.get('clip', true) && createClipPath( seriesModel.coordinateSystem, false, seriesModel ); if (clipPath) { diff --git a/src/chart/scatter/ScatterView.js b/src/chart/scatter/ScatterView.js index 0dd16a1b3c..6fc7b84226 100644 --- a/src/chart/scatter/ScatterView.js +++ b/src/chart/scatter/ScatterView.js @@ -84,7 +84,7 @@ echarts.extendChartView({ _getClipShape: function (seriesModel) { var coordSys = seriesModel.coordinateSystem; var clipArea = coordSys && coordSys.getArea && coordSys.getArea(); - return seriesModel.get('clip') ? clipArea : null; + return seriesModel.get('clip', true) ? clipArea : null; }, _updateSymbolDraw: function (data, seriesModel) { From ea111b6e9aae5661e30129dd6e5db5d0fc116dba Mon Sep 17 00:00:00 2001 From: pissang Date: Fri, 20 Sep 2019 15:33:28 +0800 Subject: [PATCH 115/127] test: support mousewheel event record and replay --- src/chart/bar/BarView.js | 4 ++-- test/runTest/Timeline.js | 32 +++++++++++++++++++++++++++++++ test/runTest/recorder/recorder.js | 24 +++++++++++++++++++++-- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/chart/bar/BarView.js b/src/chart/bar/BarView.js index eb9f6c1a35..310ddffd1d 100644 --- a/src/chart/bar/BarView.js +++ b/src/chart/bar/BarView.js @@ -196,7 +196,7 @@ export default echarts.extendChartView({ this.group.setClipPath(clipPath); } else { - this.group.removeClipPath(null); + this.group.removeClipPath(); } }, @@ -258,7 +258,7 @@ var clip = { layout.width = x2 - x; layout.height = y2 - y; - var clipped = layout.width < 0 || layout.height < 0;; + var clipped = layout.width < 0 || layout.height < 0; // Reverse back if (signWidth < 0) { diff --git a/test/runTest/Timeline.js b/test/runTest/Timeline.js index aad083a7e8..f115125f89 100644 --- a/test/runTest/Timeline.js +++ b/test/runTest/Timeline.js @@ -29,6 +29,8 @@ module.exports = class Timeline { this._ops = []; this._currentOpIndex = 0; + + this._client; } _reset() { @@ -39,6 +41,10 @@ module.exports = class Timeline { async runAction(action, takeScreenshot, playbackSpeed) { + if (!this._client) { + this._client = await this._page.target().createCDPSession(); + } + this.stop(); playbackSpeed = playbackSpeed || 1; @@ -108,6 +114,32 @@ module.exports = class Timeline { case 'mousemove': await page.mouse.move(op.x, op.y); break; + case 'mousewheel': + await page.evaluate((x, y, deltaX, deltaY) => { + let element = document.elementFromPoint(x, y); + // Here dispatch mousewheel event because echarts used it. + // TODO Consider upgrade? + let event = new WheelEvent('mousewheel', { + // PENDING + // Needs inverse delta? + deltaY, + clientX: x, clientY: y, + // Needs bubble to parent container + bubbles: true + }); + + element.dispatchEvent(event); + }, op.x, op.y, op.deltaX || 0, op.deltaY); + + // console.log('mousewheel', op.x, op.y, op.deltaX, op.deltaY); + // await this._client.send('Input.dispatchMouseEvent', { + // type: 'mouseWheel', + // x: op.x, + // y: op.y, + // deltaX: op.deltaX, + // deltaY: op.deltaY + // }); + // break; case 'screenshot': await takeScreenshot(); break; diff --git a/test/runTest/recorder/recorder.js b/test/runTest/recorder/recorder.js index 44c6323132..90390a5cb1 100644 --- a/test/runTest/recorder/recorder.js +++ b/test/runTest/recorder/recorder.js @@ -143,6 +143,7 @@ const app = new Vue({ if (action) { action.ops = []; } + saveData(); }).catch(e => {}); }, @@ -240,6 +241,10 @@ function keyboardRecordingHandler(e) { } } +function sign(value) { + return value > 0 ? 1 : -1; +} + function recordIframeEvents(iframe, app) { let innerDocument = iframe.contentWindow.document; @@ -247,12 +252,23 @@ function recordIframeEvents(iframe, app) { function addMouseOp(type, e) { if (app.recordingAction) { let time = getEventTime(); - app.recordingAction.ops.push({ + let op = { type, time: time, x: e.clientX, y: e.clientY - }); + }; + app.recordingAction.ops.push(op); + if (type === 'mousewheel') { + // TODO Sreenshot after mousewheel? + op.deltaY = e.deltaY; + + // In a reversed direction. + // When creating WheelEvent, the sign of wheelData and deltaY are same + if (sign(e.wheelDelta) !== sign(e.deltaY)) { + op.deltaY = -op.deltaY; + } + } if (type === 'mouseup' && app.config.screenshotAfterMouseUp) { // Add a auto screenshot after mouseup app.recordingAction.ops.push({ @@ -288,6 +304,10 @@ function recordIframeEvents(iframe, app) { } preventRecordingFollowingMouseEvents = false; }, true); + iframe.contentWindow.addEventListener('mousewheel', e => { + console.log(e); + addMouseOp('mousewheel', e); + }, true); innerDocument.body.addEventListener('change', e => { From 50b330467116f85b6a1dbca78fe6b04628faa9ca Mon Sep 17 00:00:00 2001 From: pissang Date: Fri, 20 Sep 2019 15:37:28 +0800 Subject: [PATCH 116/127] test: remove unnecessary console.log --- test/runTest/recorder/recorder.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/runTest/recorder/recorder.js b/test/runTest/recorder/recorder.js index 90390a5cb1..eb89d58f5d 100644 --- a/test/runTest/recorder/recorder.js +++ b/test/runTest/recorder/recorder.js @@ -305,7 +305,6 @@ function recordIframeEvents(iframe, app) { preventRecordingFollowingMouseEvents = false; }, true); iframe.contentWindow.addEventListener('mousewheel', e => { - console.log(e); addMouseOp('mousewheel', e); }, true); From ef14099e4eb171e61e5d2e043a85aa3cbd0358c6 Mon Sep 17 00:00:00 2001 From: Ovilia Date: Fri, 20 Sep 2019 16:44:21 +0800 Subject: [PATCH 117/127] fix(map): map path changed from geo coord to screen coord; fix #11055 (#11272) * WIP(map): map path changed from geo coord to screen position * WIP(map): works expect clicking map data * test(map): add test for #11055 * fix(map): use for-loop instead of zrUtil.map * test(map): test fill pattern in map * test(map): update test with mousewheel --- src/component/helper/MapDraw.js | 48 ++++++------ test/geoScatter.html | 114 ++++++++++++++--------------- test/runTest/actions/__meta__.json | 2 +- test/runTest/actions/map.json | 2 +- 4 files changed, 84 insertions(+), 82 deletions(-) diff --git a/src/component/helper/MapDraw.js b/src/component/helper/MapDraw.js index 5f4d5d736f..163d3626a5 100644 --- a/src/component/helper/MapDraw.js +++ b/src/component/helper/MapDraw.js @@ -25,7 +25,7 @@ import * as graphic from '../../util/graphic'; import geoSourceManager from '../../coord/geo/geoSourceManager'; import {getUID} from '../../util/component'; -function getFixedItemStyle(model, scale) { +function getFixedItemStyle(model) { var itemStyle = model.getItemStyle(); var areaColor = model.get('areaColor'); @@ -181,20 +181,14 @@ MapDraw.prototype = { var regionsGroup = this._regionsGroup; var group = this.group; - var scale = geo.scale; - var transform = { - position: geo.position, - scale: scale - }; - - // No animation when first draw or in action - if (!regionsGroup.childAt(0) || payload) { - group.attr(transform); - } - else { - graphic.updateProps(group, transform, mapOrGeoModel); + if (geo._roamTransformable.transform) { + group.transform = geo._roamTransformable.transform.slice(); + group.decomposeTransform(); } + var scale = geo._rawTransformable.scale; + var position = geo._rawTransformable.position; + regionsGroup.removeAll(); var itemStyleAccessPath = ['itemStyle']; @@ -204,7 +198,6 @@ MapDraw.prototype = { var nameMap = zrUtil.createHashMap(); zrUtil.each(geo.regions, function (region) { - // Consider in GeoJson properties.name may be duplicated, for example, // there is multiple region named "United Kindom" or "France" (so many // colonies). And it is not appropriate to merge them in geo, which @@ -225,8 +218,8 @@ MapDraw.prototype = { var itemStyleModel = regionModel.getModel(itemStyleAccessPath); var hoverItemStyleModel = regionModel.getModel(hoverItemStyleAccessPath); - var itemStyle = getFixedItemStyle(itemStyleModel, scale); - var hoverItemStyle = getFixedItemStyle(hoverItemStyleModel, scale); + var itemStyle = getFixedItemStyle(itemStyleModel); + var hoverItemStyle = getFixedItemStyle(hoverItemStyleModel); var labelModel = regionModel.getModel(labelAccessPath); var hoverLabelModel = regionModel.getModel(hoverLabelAccessPath); @@ -245,22 +238,34 @@ MapDraw.prototype = { } } + var transformPoint = function (point) { + return [ + point[0] * scale[0] + position[0], + point[1] * scale[1] + position[1] + ]; + }; + zrUtil.each(region.geometries, function (geometry) { if (geometry.type !== 'polygon') { return; } + var exterior = []; + for (var i = 0; i < geometry.exterior.length; ++i) { + exterior.push(transformPoint(geometry.exterior[i])); + } compoundPath.shape.paths.push(new graphic.Polygon({ segmentIgnoreThreshold: 1, shape: { - points: geometry.exterior + points: exterior } })); for (var i = 0; i < (geometry.interiors ? geometry.interiors.length : 0); i++) { + var interiors = transformPoint(geometry.interiors[i]); compoundPath.shape.paths.push(new graphic.Polygon({ segmentIgnoreThreshold: 1, shape: { - points: geometry.interiors[i] + points: interiors } })); } @@ -269,6 +274,7 @@ MapDraw.prototype = { compoundPath.setStyle(itemStyle); compoundPath.style.strokeNoScale = true; compoundPath.culling = true; + // Label var showLabel = labelModel.get('show'); var hoverShowLabel = hoverLabelModel.get('show'); @@ -292,12 +298,12 @@ MapDraw.prototype = { } var textEl = new graphic.Text({ - position: region.center.slice(), + position: transformPoint(region.center.slice()), // FIXME // label rotation is not support yet in geo or regions of series-map // that has no data. The rotation will be effected by this `scale`. // So needed to change to RectText? - scale: [1 / scale[0], 1 / scale[1]], + scale: [1 / group.scale[0], 1 / group.scale[1]], z2: 10, silent: true }); @@ -433,4 +439,4 @@ MapDraw.prototype = { } }; -export default MapDraw; \ No newline at end of file +export default MapDraw; diff --git a/test/geoScatter.html b/test/geoScatter.html index f42b3637fb..36f9990e29 100644 --- a/test/geoScatter.html +++ b/test/geoScatter.html @@ -33,7 +33,7 @@ margin: 0; } - 新疆 should be yellow + 新疆 should be yellow. The pattern in the right geo should not be blurred.
+ + + + + + + +

The line in legend symble should be default value and the borderWidth of legend symble should be legend.itemSyle.borderWidth

+
+

The style with legend symble should be series[i].itemStyle

+
+

The style with legend symble should be legend.itemStyle

+
+ + + + \ No newline at end of file From 92b2ef2e2ca435f996677279ba9be1fe69dc96e7 Mon Sep 17 00:00:00 2001 From: alex2wong Date: Sat, 21 Sep 2019 22:38:37 +0800 Subject: [PATCH 121/127] Fix contributing doc missing issue contributing doc was moved to root dir --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e140c91863..ee5d328a5f 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ More custom build approaches can be checked in this tutorial: [Create Custom Bui ## Contribution -If you wish to debug locally, or make pull requests, please refer to [contributing](https://github.com/apache/incubator-echarts/blob/master/.github/CONTRIBUTING.md) document. +If you wish to debug locally, or make pull requests, please refer to [contributing](https://github.com/apache/incubator-echarts/blob/master/CONTRIBUTING.md) document. ## Resources From c473639c21a395717db58302512bb1a78c08e8be Mon Sep 17 00:00:00 2001 From: SHUANG SU Date: Mon, 23 Sep 2019 03:16:52 +0800 Subject: [PATCH 122/127] feat: provide `echarts.registerShape` and `echarts.getShapeClass` for custom shape in `custom series` and `graphic component`. --- src/chart/custom.js | 10 ++++++- src/component/graphic.js | 18 +++++++++++- src/export.js | 1 + src/util/graphic.js | 61 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 2 deletions(-) diff --git a/src/chart/custom.js b/src/chart/custom.js index 7c31bb7bb4..784e59c157 100644 --- a/src/chart/custom.js +++ b/src/chart/custom.js @@ -231,6 +231,8 @@ function createEl(elOption) { var graphicType = elOption.type; var el; + // Those graphic elements are not shapes. They should not be + // overwritten by users, so do them first. if (graphicType === 'path') { var shape = elOption.shape; // Using pathRect brings convenience to users sacle svg path. @@ -255,8 +257,14 @@ function createEl(elOption) { el = new graphicUtil.Text({}); el.__customText = elOption.style.text; } + else if (graphicType === 'group') { + el = new graphicUtil.Group(); + } + else if (graphicType === 'compoundPath') { + throw new Error('"compoundPath" is not supported yet.'); + } else { - var Clz = graphicUtil[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)]; + var Clz = graphicUtil.getShapeClass(graphicType); if (__DEV__) { zrUtil.assert(Clz, 'graphic type "' + graphicType + '" can not be found.'); diff --git a/src/component/graphic.js b/src/component/graphic.js index 92674a70ed..e689db1bd2 100644 --- a/src/component/graphic.js +++ b/src/component/graphic.js @@ -26,6 +26,18 @@ import * as graphicUtil from '../util/graphic'; import * as layoutUtil from '../util/layout'; import {parsePercent} from '../util/number'; +var _nonShapeGraphicElements = { + + // Reserved but not supported in graphic component. + path: null, + compoundPath: null, + + // Supported in graphic component. + group: graphicUtil.Group, + image: graphicUtil.Image, + text: graphicUtil.Text +}; + // ------------- // Preprocessor // ------------- @@ -440,7 +452,11 @@ function createEl(id, targetElParent, elOption, elMap) { zrUtil.assert(graphicType, 'graphic type MUST be set'); } - var Clz = graphicUtil[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)]; + var Clz = _nonShapeGraphicElements.hasOwnProperty(graphicType) + // Those graphic elements are not shapes. They should not be + // overwritten by users, so do them first. + ? _nonShapeGraphicElements[graphicType] + : graphicUtil.getShapeClass(graphicType); if (__DEV__) { zrUtil.assert(Clz, 'graphic type can not be found'); diff --git a/src/export.js b/src/export.js index dded75c774..6ddd62eccf 100644 --- a/src/export.js +++ b/src/export.js @@ -71,6 +71,7 @@ zrUtil.each( 'setHoverStyle', 'setLabelStyle', 'setTextStyle', 'setText', 'getFont', 'updateProps', 'initProps', 'getTransform', 'clipPointsByRect', 'clipRectByRect', + 'registerShape', 'getShapeClass', 'Group', 'Image', 'Text', diff --git a/src/util/graphic.js b/src/util/graphic.js index 38b2b854c2..0ca633d3f1 100644 --- a/src/util/graphic.js +++ b/src/util/graphic.js @@ -65,6 +65,8 @@ var NORMAL = 'normal'; var _highlightNextDigit = 1; var _highlightKeyMap = {}; +var _customShapeMap = {}; + /** * Extend shape with parameters @@ -80,6 +82,53 @@ export function extendPath(pathData, opts) { return pathTool.extendFromString(pathData, opts); } +/** + * Register a user defined shape. + * The shape class can be fetched by `getShapeClass` + * This method will not overwrite the built-in shapes. + * The shape can be used in `custom series` and + * `graphic component` by declaring `{type: name}`. + * + * @param {string} name + * @param {Object} ShapeClass Can be generated by `extendShape`. + */ +export function registerShape(name, ShapeClass) { + _customShapeMap[name] = ShapeClass; +} + +/** + * Find shape class registered by `registerShape`. Usually used in + * fetching user defined shape. + * + * [Caution]: + * (1) This method **MUST NOT be used inside echarts !!!**, unless it is prepared + * to use user registered shapes. + * Because the built-in shape (see `getBuiltInShape`) will be registered by + * `registerShape` by default. That enables users to get both built-in + * shapes as well as the shapes belonging to themsleves. But users can overwrite + * the built-in shapes by using names like 'circle', 'rect' via calling + * `registerShape`. So the echarts inner featrues should not fetch shapes from here + * in case that it is overwritten by users, except that some features, like + * `custom series`, `graphic component`, do it deliberately. + * + * (2) In the features like `custom series`, `graphic component`, the user input + * `{tpye: 'xxx'}` does not only specify shapes but also specify other graphic + * elements like `'group'`, `'text'`, `'image'` or event `'path'`. Those names + * are reserved names, that is, if some user register a shape named `'image'`, + * the shape will not be used. If we intending to add some more reserved names + * in feature, that might bring break changes (disable some existing user shape + * names). But that case probably rearly happen. So we dont make more mechanism + * to resolve this issue here. + * + * @param {string} name + * @return {Object} The shape class. If not found, return nothing. + */ +export function getShapeClass(name) { + if (_customShapeMap.hasOwnProperty(name)) { + return _customShapeMap[name]; + } +} + /** * Create a path element from path data string * @param {string} pathData @@ -1377,6 +1426,18 @@ function nearZero(val) { return val <= (1e-6) && val >= -(1e-6); } +// Register built-in shapes. These shapes might be overwirtten +// by users, although we do not recommend that. +registerShape('circle', Circle); +registerShape('sector', Sector); +registerShape('ring', Ring); +registerShape('polygon', Polygon); +registerShape('polyline', Polyline); +registerShape('rect', Rect); +registerShape('line', Line); +registerShape('bezierCurve', BezierCurve); +registerShape('arc', Arc); + export { Group, ZImage as Image, From 0645f84a0c9088ed278483b66ad4560fa4bda5aa Mon Sep 17 00:00:00 2001 From: yufeng04 Date: Mon, 23 Sep 2019 18:09:50 +0800 Subject: [PATCH 123/127] fix bug #7340 --- README.md | 2 +- src/chart/custom.js | 10 +- src/component/graphic.js | 18 +- src/component/legend/LegendModel.js | 10 +- src/component/legend/LegendView.js | 6 +- src/export.js | 1 + src/util/graphic.js | 61 +++ src/visual/dataColor.js | 13 +- src/visual/seriesColor.js | 15 +- test/legend-borderColor.html | 558 ++++++++++++++++++++++++++++ test/lengend-borderColor.html | 402 -------------------- 11 files changed, 661 insertions(+), 435 deletions(-) create mode 100644 test/legend-borderColor.html delete mode 100644 test/lengend-borderColor.html diff --git a/README.md b/README.md index e140c91863..ee5d328a5f 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ More custom build approaches can be checked in this tutorial: [Create Custom Bui ## Contribution -If you wish to debug locally, or make pull requests, please refer to [contributing](https://github.com/apache/incubator-echarts/blob/master/.github/CONTRIBUTING.md) document. +If you wish to debug locally, or make pull requests, please refer to [contributing](https://github.com/apache/incubator-echarts/blob/master/CONTRIBUTING.md) document. ## Resources diff --git a/src/chart/custom.js b/src/chart/custom.js index 7c31bb7bb4..784e59c157 100644 --- a/src/chart/custom.js +++ b/src/chart/custom.js @@ -231,6 +231,8 @@ function createEl(elOption) { var graphicType = elOption.type; var el; + // Those graphic elements are not shapes. They should not be + // overwritten by users, so do them first. if (graphicType === 'path') { var shape = elOption.shape; // Using pathRect brings convenience to users sacle svg path. @@ -255,8 +257,14 @@ function createEl(elOption) { el = new graphicUtil.Text({}); el.__customText = elOption.style.text; } + else if (graphicType === 'group') { + el = new graphicUtil.Group(); + } + else if (graphicType === 'compoundPath') { + throw new Error('"compoundPath" is not supported yet.'); + } else { - var Clz = graphicUtil[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)]; + var Clz = graphicUtil.getShapeClass(graphicType); if (__DEV__) { zrUtil.assert(Clz, 'graphic type "' + graphicType + '" can not be found.'); diff --git a/src/component/graphic.js b/src/component/graphic.js index 92674a70ed..e689db1bd2 100644 --- a/src/component/graphic.js +++ b/src/component/graphic.js @@ -26,6 +26,18 @@ import * as graphicUtil from '../util/graphic'; import * as layoutUtil from '../util/layout'; import {parsePercent} from '../util/number'; +var _nonShapeGraphicElements = { + + // Reserved but not supported in graphic component. + path: null, + compoundPath: null, + + // Supported in graphic component. + group: graphicUtil.Group, + image: graphicUtil.Image, + text: graphicUtil.Text +}; + // ------------- // Preprocessor // ------------- @@ -440,7 +452,11 @@ function createEl(id, targetElParent, elOption, elMap) { zrUtil.assert(graphicType, 'graphic type MUST be set'); } - var Clz = graphicUtil[graphicType.charAt(0).toUpperCase() + graphicType.slice(1)]; + var Clz = _nonShapeGraphicElements.hasOwnProperty(graphicType) + // Those graphic elements are not shapes. They should not be + // overwritten by users, so do them first. + ? _nonShapeGraphicElements[graphicType] + : graphicUtil.getShapeClass(graphicType); if (__DEV__) { zrUtil.assert(Clz, 'graphic type can not be found'); diff --git a/src/component/legend/LegendModel.js b/src/component/legend/LegendModel.js index 5442c302f3..ceeb39b1c6 100644 --- a/src/component/legend/LegendModel.js +++ b/src/component/legend/LegendModel.js @@ -275,19 +275,19 @@ var LegendModel = echarts.extendComponentModel({ // 各个item之间的间隔,单位px,默认为10, // 横向布局时为水平间隔,纵向布局时为纵向间隔 itemGap: 10, - // 图例图形宽度 + // the width of legend symbol itemWidth: 25, - // 图例图形高度 + // the height of legend symbol itemHeight: 14, - // 图例关闭时候的颜色 + // the color of unselected legend symbol inactiveColor: '#ccc', - // 图例关闭时候的颜色 + // the borderColor of unselected legend symbol inactiveBorderColor: '#ccc', itemStyle: { - // 图例默认无边框 + // the default borderWidth of legend symbol borderWidth: 0 }, diff --git a/src/component/legend/LegendView.js b/src/component/legend/LegendView.js index f12f5336ba..c6c059e43c 100644 --- a/src/component/legend/LegendView.js +++ b/src/component/legend/LegendView.js @@ -339,7 +339,7 @@ export default echarts.extendComponentView({ symbolKeepAspect == null ? true : symbolKeepAspect ); itemGroup.add( - setSympleStyle( + setSymbolStyle( legendSymbol, legendSymbolType, itemStyle, borderColor, inactiveBorderColor, isSelected ) @@ -367,7 +367,7 @@ export default echarts.extendComponentView({ ); // Put symbol in the center itemGroup.add( - setSympleStyle( + setSymbolStyle( legendSymbolCenter, symbolType, itemStyle, borderColor, inactiveBorderColor, isSelected ) @@ -503,7 +503,7 @@ export default echarts.extendComponentView({ }); -function setSympleStyle(symbol, symbolType, itemStyle, borderColor, inactiveBorderColor, isSelected) { +function setSymbolStyle(symbol, symbolType, itemStyle, borderColor, inactiveBorderColor, isSelected) { if (symbolType !== 'line' && symbolType.indexOf('empty') < 0) { symbol.style.stroke = borderColor; if (!isSelected) { diff --git a/src/export.js b/src/export.js index dded75c774..6ddd62eccf 100644 --- a/src/export.js +++ b/src/export.js @@ -71,6 +71,7 @@ zrUtil.each( 'setHoverStyle', 'setLabelStyle', 'setTextStyle', 'setText', 'getFont', 'updateProps', 'initProps', 'getTransform', 'clipPointsByRect', 'clipRectByRect', + 'registerShape', 'getShapeClass', 'Group', 'Image', 'Text', diff --git a/src/util/graphic.js b/src/util/graphic.js index 38b2b854c2..0ca633d3f1 100644 --- a/src/util/graphic.js +++ b/src/util/graphic.js @@ -65,6 +65,8 @@ var NORMAL = 'normal'; var _highlightNextDigit = 1; var _highlightKeyMap = {}; +var _customShapeMap = {}; + /** * Extend shape with parameters @@ -80,6 +82,53 @@ export function extendPath(pathData, opts) { return pathTool.extendFromString(pathData, opts); } +/** + * Register a user defined shape. + * The shape class can be fetched by `getShapeClass` + * This method will not overwrite the built-in shapes. + * The shape can be used in `custom series` and + * `graphic component` by declaring `{type: name}`. + * + * @param {string} name + * @param {Object} ShapeClass Can be generated by `extendShape`. + */ +export function registerShape(name, ShapeClass) { + _customShapeMap[name] = ShapeClass; +} + +/** + * Find shape class registered by `registerShape`. Usually used in + * fetching user defined shape. + * + * [Caution]: + * (1) This method **MUST NOT be used inside echarts !!!**, unless it is prepared + * to use user registered shapes. + * Because the built-in shape (see `getBuiltInShape`) will be registered by + * `registerShape` by default. That enables users to get both built-in + * shapes as well as the shapes belonging to themsleves. But users can overwrite + * the built-in shapes by using names like 'circle', 'rect' via calling + * `registerShape`. So the echarts inner featrues should not fetch shapes from here + * in case that it is overwritten by users, except that some features, like + * `custom series`, `graphic component`, do it deliberately. + * + * (2) In the features like `custom series`, `graphic component`, the user input + * `{tpye: 'xxx'}` does not only specify shapes but also specify other graphic + * elements like `'group'`, `'text'`, `'image'` or event `'path'`. Those names + * are reserved names, that is, if some user register a shape named `'image'`, + * the shape will not be used. If we intending to add some more reserved names + * in feature, that might bring break changes (disable some existing user shape + * names). But that case probably rearly happen. So we dont make more mechanism + * to resolve this issue here. + * + * @param {string} name + * @return {Object} The shape class. If not found, return nothing. + */ +export function getShapeClass(name) { + if (_customShapeMap.hasOwnProperty(name)) { + return _customShapeMap[name]; + } +} + /** * Create a path element from path data string * @param {string} pathData @@ -1377,6 +1426,18 @@ function nearZero(val) { return val <= (1e-6) && val >= -(1e-6); } +// Register built-in shapes. These shapes might be overwirtten +// by users, although we do not recommend that. +registerShape('circle', Circle); +registerShape('sector', Sector); +registerShape('ring', Ring); +registerShape('polygon', Polygon); +registerShape('polyline', Polyline); +registerShape('rect', Rect); +registerShape('line', Line); +registerShape('bezierCurve', BezierCurve); +registerShape('arc', Arc); + export { Group, ZImage as Image, diff --git a/src/visual/dataColor.js b/src/visual/dataColor.js index 5d5f1523fe..a408c584cf 100644 --- a/src/visual/dataColor.js +++ b/src/visual/dataColor.js @@ -56,10 +56,9 @@ export default function (seriesType) { var singleDataBorderColor = filteredIdx != null && data.getItemVisual(filteredIdx, 'borderColor', true); - // FIXME Performance - var itemModel = dataAll.getItemModel(rawIdx); - if (!singleDataColor) { + // FIXME Performance + var itemModel = dataAll.getItemModel(rawIdx); var color = itemModel.get('itemStyle.color') || seriesModel.getColorFromPalette( dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope, @@ -79,11 +78,9 @@ export default function (seriesType) { } if (!singleDataBorderColor) { - var borderColor = itemModel.get('itemStyle.borderColor') - || seriesModel.getColorFromPalette( - dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope, - dataAll.count() - ); + // FIXME Performance + var itemModel = dataAll.getItemModel(rawIdx); + var borderColor = itemModel.get('itemStyle.borderColor'); // Legend may use the visual info in data before processed dataAll.setItemVisual(rawIdx, 'borderColor', borderColor); diff --git a/src/visual/seriesColor.js b/src/visual/seriesColor.js index 0cd240ab1c..66e5a60aca 100644 --- a/src/visual/seriesColor.js +++ b/src/visual/seriesColor.js @@ -35,12 +35,7 @@ export default { data.setVisual('color', color); var borderColorAccessPath = (seriesModel.visualBorderColorAccessPath || 'itemStyle.borderColor').split('.'); - var borderColor = seriesModel.get(borderColorAccessPath) // Set in itemStyle - || seriesModel.getColorFromPalette( - // TODO series count changed. - seriesModel.name, null, ecModel.getSeriesCount() - ); // Default borderColor - // FIXME Set borderColor function or use the platte borderColor + var borderColor = seriesModel.get(borderColorAccessPath); data.setVisual('borderColor', borderColor); // Only visible series has each data be visual encoded @@ -53,14 +48,6 @@ export default { }); } - if (typeof borderColor === 'function' && !(borderColor instanceof Gradient)) { - data.each(function (idx) { - data.setItemVisual( - idx, 'borderColor', borderColor(seriesModel.getDataParams(idx)) - ); - }); - } - // itemStyle in each data item var dataEach = function (data, idx) { var itemModel = data.getItemModel(idx); diff --git a/test/legend-borderColor.html b/test/legend-borderColor.html new file mode 100644 index 0000000000..e3e6909c5f --- /dev/null +++ b/test/legend-borderColor.html @@ -0,0 +1,558 @@ + + + + + + + + + + + + + + + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/test/lengend-borderColor.html b/test/lengend-borderColor.html deleted file mode 100644 index d7515332d7..0000000000 --- a/test/lengend-borderColor.html +++ /dev/null @@ -1,402 +0,0 @@ - - - - - - - - - - - - - - -

The line in legend symble should be default value and the borderWidth of legend symble should be legend.itemSyle.borderWidth

-
-

The style with legend symble should be series[i].itemStyle

-
-

The style with legend symble should be legend.itemStyle

-
- - - - \ No newline at end of file From ce034f91718fe4abb7346f8af7ac101427a957f0 Mon Sep 17 00:00:00 2001 From: yufeng04 Date: Mon, 23 Sep 2019 18:53:49 +0800 Subject: [PATCH 124/127] fix typo --- test/legend-borderColor.html | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/legend-borderColor.html b/test/legend-borderColor.html index e3e6909c5f..056f61839e 100644 --- a/test/legend-borderColor.html +++ b/test/legend-borderColor.html @@ -300,12 +300,12 @@ testHelper.create(echarts, 'plain1', { title: [ '(Legend symbol of line)', - 'the borderColor of first legend symble should be black', - 'the borderColor of second legend symble should be blue', + 'the borderColor of first legend symbol should be black', + 'the borderColor of second legend symbol should be blue', 'the bar borderColor of second series should be red, because the legend borderColor is incompatible with barBorderColor', - 'the third legend symble should be unselected', - 'the borderColor of other legend symbles should be the same as color of corresponding series', - 'the borderColor of all legend symbles should be 3' + 'the third legend symbol should be unselected', + 'the borderColor of other legend symbols should be the same as color of corresponding series', + 'the borderColor of all legend symbols should be 3' ], option: option1, height: 300 @@ -424,9 +424,9 @@ testHelper.create(echarts, 'plain2', { title: [ '(Legend symbol of line)', - 'the first legend symble should be unselected', + 'the first legend symbol should be unselected', 'the borderColor of legend symbol should be red', - 'the borderWidth of all legend symbles should be 3' + 'the borderWidth of all legend symbols should be 3' ], option: option2, height: 300 @@ -541,9 +541,9 @@ testHelper.create(echarts, 'plain3', { title: [ '(Legend symbol of scatter)', - 'the legend symble of 1990 should be unselected', + 'the legend symbol of 1990 should be unselected', 'the borderColor of legend symbol should be black', - 'the borderWidth of all legend symbles should be 3' + 'the borderWidth of all legend symbols should be 3' ], option: option3, height: 300 From e8c8e096d275174dbc0899b11a431a66d782bf28 Mon Sep 17 00:00:00 2001 From: yufeng04 Date: Mon, 23 Sep 2019 22:27:50 +0800 Subject: [PATCH 125/127] fix typo & itemModel should not be created twice --- src/visual/dataColor.js | 10 ++++++---- test/legend-borderColor.html | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/visual/dataColor.js b/src/visual/dataColor.js index a408c584cf..63c2b84e9a 100644 --- a/src/visual/dataColor.js +++ b/src/visual/dataColor.js @@ -56,9 +56,13 @@ export default function (seriesType) { var singleDataBorderColor = filteredIdx != null && data.getItemVisual(filteredIdx, 'borderColor', true); - if (!singleDataColor) { + var itemModel; + if (!singleDataColor || !singleDataBorderColor) { // FIXME Performance - var itemModel = dataAll.getItemModel(rawIdx); + itemModel = dataAll.getItemModel(rawIdx); + } + + if (!singleDataColor) { var color = itemModel.get('itemStyle.color') || seriesModel.getColorFromPalette( dataAll.getName(rawIdx) || (rawIdx + ''), seriesModel.__paletteScope, @@ -78,8 +82,6 @@ export default function (seriesType) { } if (!singleDataBorderColor) { - // FIXME Performance - var itemModel = dataAll.getItemModel(rawIdx); var borderColor = itemModel.get('itemStyle.borderColor'); // Legend may use the visual info in data before processed dataAll.setItemVisual(rawIdx, 'borderColor', borderColor); diff --git a/test/legend-borderColor.html b/test/legend-borderColor.html index 056f61839e..7caa9fbd2d 100644 --- a/test/legend-borderColor.html +++ b/test/legend-borderColor.html @@ -299,7 +299,7 @@ // chart1.setOption(option1); testHelper.create(echarts, 'plain1', { title: [ - '(Legend symbol of line)', + '(Legend symbol of bar)', 'the borderColor of first legend symbol should be black', 'the borderColor of second legend symbol should be blue', 'the bar borderColor of second series should be red, because the legend borderColor is incompatible with barBorderColor', @@ -423,7 +423,7 @@ // chart2.setOption(option2); testHelper.create(echarts, 'plain2', { title: [ - '(Legend symbol of line)', + '(Legend symbol of pie)', 'the first legend symbol should be unselected', 'the borderColor of legend symbol should be red', 'the borderWidth of all legend symbols should be 3' From fbad7efec3437dd5fae6fa6b64aca30b5e345bfc Mon Sep 17 00:00:00 2001 From: SHUANG SU Date: Mon, 23 Sep 2019 22:22:59 +0800 Subject: [PATCH 126/127] fix: dataZoom toolbox can not return to the original state. --- src/component/dataZoom/AxisProxy.js | 2 +- src/component/dataZoom/DataZoomModel.js | 101 +++++++++++++++----- src/component/dataZoom/dataZoomProcessor.js | 4 +- test/dataZoom-toolbox.html | 51 ++++++++++ test/runTest/actions/__meta__.json | 2 +- test/runTest/actions/dataZoom-toolbox.json | 2 +- 6 files changed, 132 insertions(+), 30 deletions(-) diff --git a/src/component/dataZoom/AxisProxy.js b/src/component/dataZoom/AxisProxy.js index 3b003053a4..0a2256d177 100644 --- a/src/component/dataZoom/AxisProxy.js +++ b/src/component/dataZoom/AxisProxy.js @@ -298,7 +298,7 @@ AxisProxy.prototype = { // `calculateDataWindow` uses min/maxSpan. setMinMaxSpan(this); - var dataWindow = this.calculateDataWindow(dataZoomModel.option); + var dataWindow = this.calculateDataWindow(dataZoomModel.settledOption); this._valueWindow = dataWindow.valueWindow; this._percentWindow = dataWindow.percentWindow; diff --git a/src/component/dataZoom/DataZoomModel.js b/src/component/dataZoom/DataZoomModel.js index 99f5b1c4e8..4388d600fe 100644 --- a/src/component/dataZoom/DataZoomModel.js +++ b/src/component/dataZoom/DataZoomModel.js @@ -116,29 +116,55 @@ var DataZoomModel = echarts.extendComponentModel({ */ this._rangePropMode = ['percent', 'percent']; - var rawOption = retrieveRaw(option); + var inputRawOption = retrieveRawOption(option); + + /** + * Suppose a "main process" start at the point that model prepared (that is, + * model initialized or merged or method called in `action`). + * We should keep the `main process` idempotent, that is, given a set of values + * on `option`, we get the same result. + * + * But sometimes, values on `option` will be updated for providing users + * a "final calculated value" (`dataZoomProcessor` will do that). Those value + * should not be the base/input of the `main process`. + * + * So in that case we should save and keep the input of the `main process` + * separately, called `settledOption`. + * + * For example, consider the case: + * (Step_1) brush zoom the grid by `toolbox.dataZoom`, + * where the original input `option.startValue`, `option.endValue` are earsed by + * calculated value. + * (Step)2) click the legend to hide and show a series, + * where the new range is calculated by the earsed `startValue` and `endValue`, + * which brings incorrect result. + * + * @readOnly + */ + this.settledOption = inputRawOption; this.mergeDefaultAndTheme(option, ecModel); - this.doInit(rawOption); + this.doInit(inputRawOption); }, /** * @override */ mergeOption: function (newOption) { - var rawOption = retrieveRaw(newOption); + var inputRawOption = retrieveRawOption(newOption); //FIX #2591 zrUtil.merge(this.option, newOption, true); + zrUtil.merge(this.settledOption, inputRawOption, true); - this.doInit(rawOption); + this.doInit(inputRawOption); }, /** * @protected */ - doInit: function (rawOption) { + doInit: function (inputRawOption) { var thisOption = this.option; // Disable realtime view update if canvas is not supported. @@ -146,16 +172,17 @@ var DataZoomModel = echarts.extendComponentModel({ thisOption.realtime = false; } - this._setDefaultThrottle(rawOption); + this._setDefaultThrottle(inputRawOption); - updateRangeUse(this, rawOption); + updateRangeUse(this, inputRawOption); + var settledOption = this.settledOption; each([['start', 'startValue'], ['end', 'endValue']], function (names, index) { // start/end has higher priority over startValue/endValue if they // both set, but we should make chart.setOption({endValue: 1000}) // effective, rather than chart.setOption({endValue: 1000, end: null}). if (this._rangePropMode[index] === 'value') { - thisOption[names[0]] = null; + thisOption[names[0]] = settledOption[names[0]] = null; } // Otherwise do nothing and use the merge result. }, this); @@ -375,9 +402,9 @@ var DataZoomModel = echarts.extendComponentModel({ /** * @private */ - _setDefaultThrottle: function (rawOption) { + _setDefaultThrottle: function (inputRawOption) { // When first time user set throttle, auto throttle ends. - if (rawOption.hasOwnProperty('throttle')) { + if (inputRawOption.hasOwnProperty('throttle')) { this._autoThrottle = false; } if (this._autoThrottle) { @@ -450,23 +477,42 @@ var DataZoomModel = echarts.extendComponentModel({ * @param {number} [opt.end] * @param {number} [opt.startValue] * @param {number} [opt.endValue] - * @param {boolean} [ignoreUpdateRangeUsg=false] */ - setRawRange: function (opt, ignoreUpdateRangeUsg) { - var option = this.option; + setRawRange: function (opt) { + var thisOption = this.option; + var settledOption = this.settledOption; each([['start', 'startValue'], ['end', 'endValue']], function (names) { - // If only one of 'start' and 'startValue' is not null/undefined, the other - // should be cleared, which enable clear the option. - // If both of them are not set, keep option with the original value, which - // enable use only set start but not set end when calling `dispatchAction`. - // The same as 'end' and 'endValue'. + // Consider the pair : + // If one has value and the other one is `null/undefined`, we both set them + // to `settledOption`. This strategy enables the feature to clear the original + // value in `settledOption` to `null/undefined`. + // But if both of them are `null/undefined`, we do not set them to `settledOption` + // and keep `settledOption` with the original value. This strategy enables users to + // only set but not set when calling + // `dispatchAction`. + // The pair is treated in the same way. if (opt[names[0]] != null || opt[names[1]] != null) { - option[names[0]] = opt[names[0]]; - option[names[1]] = opt[names[1]]; + thisOption[names[0]] = settledOption[names[0]] = opt[names[0]]; + thisOption[names[1]] = settledOption[names[1]] = opt[names[1]]; } }, this); - !ignoreUpdateRangeUsg && updateRangeUse(this, opt); + updateRangeUse(this, opt); + }, + + /** + * @public + * @param {Object} opt + * @param {number} [opt.start] + * @param {number} [opt.end] + * @param {number} [opt.startValue] + * @param {number} [opt.endValue] + */ + setCalculatedRange: function (opt) { + var option = this.option; + each(['start', 'startValue', 'end', 'endValue'], function (name) { + option[name] = opt[name]; + }); }, /** @@ -540,7 +586,12 @@ var DataZoomModel = echarts.extendComponentModel({ }); -function retrieveRaw(option) { +/** + * Retrieve the those raw params from option, which will be cached separately. + * becasue they will be overwritten by normalized/calculated values in the main + * process. + */ +function retrieveRawOption(option) { var ret = {}; each( ['start', 'end', 'startValue', 'endValue', 'throttle'], @@ -551,13 +602,13 @@ function retrieveRaw(option) { return ret; } -function updateRangeUse(dataZoomModel, rawOption) { +function updateRangeUse(dataZoomModel, inputRawOption) { var rangePropMode = dataZoomModel._rangePropMode; var rangeModeInOption = dataZoomModel.get('rangeMode'); each([['start', 'startValue'], ['end', 'endValue']], function (names, index) { - var percentSpecified = rawOption[names[0]] != null; - var valueSpecified = rawOption[names[1]] != null; + var percentSpecified = inputRawOption[names[0]] != null; + var valueSpecified = inputRawOption[names[1]] != null; if (percentSpecified && !valueSpecified) { rangePropMode[index] = 'percent'; } diff --git a/src/component/dataZoom/dataZoomProcessor.js b/src/component/dataZoom/dataZoomProcessor.js index c006b03527..cfd14068b3 100644 --- a/src/component/dataZoom/dataZoomProcessor.js +++ b/src/component/dataZoom/dataZoomProcessor.js @@ -81,12 +81,12 @@ echarts.registerProcessor({ var percentRange = axisProxy.getDataPercentWindow(); var valueRange = axisProxy.getDataValueWindow(); - dataZoomModel.setRawRange({ + dataZoomModel.setCalculatedRange({ start: percentRange[0], end: percentRange[1], startValue: valueRange[0], endValue: valueRange[1] - }, true); + }); }); } }); diff --git a/test/dataZoom-toolbox.html b/test/dataZoom-toolbox.html index 6bd96ce8c4..992ab4cdf9 100644 --- a/test/dataZoom-toolbox.html +++ b/test/dataZoom-toolbox.html @@ -26,6 +26,7 @@ + @@ -58,6 +59,8 @@

Specify Y axis (yAxisIndex: [1, 2, 4], xAxisIndex: false, should be 'lineY'

Specify Y axis (yAxisIndex: false, should be 'lineX' brush)

+
+ + + \ No newline at end of file diff --git a/test/runTest/actions/__meta__.json b/test/runTest/actions/__meta__.json index 8879082ed6..723bed1438 100644 --- a/test/runTest/actions/__meta__.json +++ b/test/runTest/actions/__meta__.json @@ -61,7 +61,7 @@ "dataZoom-scatter-hv-polar": 3, "dataZoom-scatter-hv": 1, "dataZoom-sync": 1, - "dataZoom-toolbox": 5, + "dataZoom-toolbox": 6, "dataZoomHighPrecision": 3, "dynamic-splitNumber": 1, "ec-event": 4, diff --git a/test/runTest/actions/dataZoom-toolbox.json b/test/runTest/actions/dataZoom-toolbox.json index 3d8e570bba..ae79937286 100644 --- a/test/runTest/actions/dataZoom-toolbox.json +++ b/test/runTest/actions/dataZoom-toolbox.json @@ -1 +1 @@ -[{"name":"Action 1","ops":[{"type":"mousedown","time":409,"x":770,"y":435},{"type":"mousemove","time":509,"x":770,"y":434},{"type":"mousemove","time":712,"x":770,"y":252},{"type":"mousemove","time":913,"x":768,"y":150},{"type":"mousemove","time":1115,"x":767,"y":139},{"type":"mouseup","time":1480,"x":767,"y":139},{"time":1481,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":2065,"x":766,"y":139},{"type":"mousemove","time":2265,"x":727,"y":130},{"type":"mousemove","time":2478,"x":710,"y":75},{"type":"mousemove","time":2776,"x":709,"y":78},{"type":"mousedown","time":2859,"x":709,"y":78},{"type":"mouseup","time":2935,"x":709,"y":78},{"time":2936,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":2992,"x":709,"y":78},{"type":"mousemove","time":3017,"x":708,"y":79},{"type":"mousemove","time":3222,"x":442,"y":238},{"type":"mousemove","time":3423,"x":325,"y":220},{"type":"mousemove","time":3624,"x":326,"y":224},{"type":"mousemove","time":3857,"x":320,"y":215},{"type":"mousedown","time":3874,"x":320,"y":215},{"type":"mousemove","time":4057,"x":442,"y":311},{"type":"mousemove","time":4257,"x":545,"y":382},{"type":"mousemove","time":4457,"x":554,"y":393},{"type":"mousemove","time":4725,"x":557,"y":396},{"type":"mouseup","time":4732,"x":557,"y":396},{"time":4733,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":4948,"x":557,"y":396},{"type":"mousemove","time":4996,"x":557,"y":396},{"type":"mousemove","time":6022,"x":553,"y":392},{"type":"mousemove","time":6222,"x":406,"y":237},{"type":"mousemove","time":6427,"x":383,"y":198},{"type":"mousemove","time":6627,"x":387,"y":182},{"type":"mousedown","time":6659,"x":404,"y":186},{"type":"mousemove","time":6837,"x":673,"y":299},{"type":"mousemove","time":7038,"x":706,"y":335},{"type":"mouseup","time":7227,"x":706,"y":336},{"time":7228,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":7260,"x":706,"y":336},{"type":"mousemove","time":8179,"x":706,"y":336},{"type":"mousemove","time":8379,"x":690,"y":332},{"type":"mousemove","time":8579,"x":498,"y":284},{"type":"mousemove","time":8783,"x":476,"y":264},{"type":"mousemove","time":8983,"x":474,"y":248},{"type":"mousedown","time":9052,"x":474,"y":248},{"type":"mousemove","time":9196,"x":533,"y":306},{"type":"mousemove","time":9397,"x":553,"y":325},{"type":"mouseup","time":9468,"x":553,"y":325},{"time":9469,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":10044,"x":553,"y":324},{"type":"mousemove","time":10261,"x":553,"y":324},{"type":"mousemove","time":10461,"x":553,"y":324},{"type":"mousemove","time":10661,"x":422,"y":263},{"type":"mousemove","time":10866,"x":413,"y":246},{"type":"mousedown","time":10966,"x":413,"y":246},{"type":"mousemove","time":11066,"x":465,"y":303},{"type":"mousemove","time":11267,"x":518,"y":357},{"type":"mouseup","time":11320,"x":518,"y":357},{"time":11321,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":11508,"x":518,"y":357},{"type":"mousemove","time":11709,"x":518,"y":353},{"type":"mousemove","time":12955,"x":524,"y":345},{"type":"mousemove","time":13156,"x":678,"y":142},{"type":"mousemove","time":13361,"x":716,"y":110},{"type":"mousemove","time":13563,"x":726,"y":87},{"type":"mousedown","time":13735,"x":726,"y":86},{"type":"mousemove","time":13772,"x":726,"y":86},{"type":"mouseup","time":13857,"x":726,"y":86},{"time":13858,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":14608,"x":726,"y":86},{"type":"mouseup","time":14708,"x":726,"y":86},{"time":14709,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":15726,"x":726,"y":86},{"type":"mouseup","time":15812,"x":726,"y":86},{"time":15813,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":17005,"x":726,"y":86},{"type":"mouseup","time":17122,"x":726,"y":86},{"time":17123,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":19668,"x":724,"y":86},{"type":"mousemove","time":19869,"x":662,"y":86}],"scrollY":0,"scrollX":0,"timestamp":1568038153909},{"name":"Action 2","ops":[{"type":"mousedown","time":455,"x":728,"y":71},{"type":"mouseup","time":536,"x":728,"y":71},{"time":537,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":1128,"x":727,"y":72},{"type":"mousemove","time":1328,"x":488,"y":158},{"type":"mousemove","time":1532,"x":166,"y":204},{"type":"mousemove","time":1732,"x":149,"y":208},{"type":"mousedown","time":1780,"x":149,"y":208},{"type":"mousemove","time":1942,"x":204,"y":280},{"type":"mousemove","time":2142,"x":287,"y":360},{"type":"mousemove","time":2343,"x":294,"y":367},{"type":"mousemove","time":2549,"x":304,"y":378},{"type":"mousemove","time":2749,"x":305,"y":380},{"type":"mouseup","time":2852,"x":305,"y":380},{"time":2853,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":5602,"x":307,"y":379},{"type":"mousemove","time":5802,"x":727,"y":100},{"type":"mousemove","time":6020,"x":769,"y":75},{"type":"mousemove","time":6221,"x":737,"y":71},{"type":"mousemove","time":6421,"x":736,"y":71},{"type":"mousedown","time":6546,"x":736,"y":71},{"type":"mouseup","time":6619,"x":736,"y":71},{"time":6620,"delay":1000,"type":"screenshot-auto"}],"scrollY":576,"scrollX":0,"timestamp":1568038203184},{"name":"Action 3","ops":[{"type":"mousedown","time":440,"x":733,"y":88},{"type":"mouseup","time":528,"x":733,"y":88},{"time":529,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":746,"x":732,"y":88},{"type":"mousemove","time":946,"x":270,"y":226},{"type":"mousemove","time":1157,"x":187,"y":231},{"type":"mousemove","time":1357,"x":159,"y":243},{"type":"mousedown","time":1408,"x":159,"y":243},{"type":"mousemove","time":1560,"x":181,"y":287},{"type":"mousemove","time":1761,"x":278,"y":424},{"type":"mousemove","time":1962,"x":320,"y":460},{"type":"mousemove","time":2200,"x":320,"y":460},{"type":"mouseup","time":2275,"x":320,"y":460},{"time":2276,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":3032,"x":320,"y":460},{"type":"mousemove","time":3233,"x":527,"y":325},{"type":"mousemove","time":3443,"x":584,"y":266},{"type":"mousemove","time":3643,"x":595,"y":258},{"type":"mousedown","time":3730,"x":595,"y":258},{"type":"mousemove","time":3845,"x":612,"y":284},{"type":"mousemove","time":4047,"x":711,"y":381},{"type":"mousemove","time":4250,"x":733,"y":391},{"type":"mouseup","time":4368,"x":739,"y":394},{"time":4369,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":4486,"x":739,"y":394},{"type":"mousemove","time":5816,"x":738,"y":393},{"type":"mousemove","time":6023,"x":738,"y":202},{"type":"mousemove","time":6225,"x":753,"y":112},{"type":"mousemove","time":6430,"x":755,"y":96},{"type":"mousedown","time":6587,"x":756,"y":95},{"type":"mousemove","time":6631,"x":756,"y":95},{"type":"mouseup","time":6672,"x":756,"y":95},{"time":6673,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":7406,"x":756,"y":95},{"type":"mouseup","time":7508,"x":756,"y":95},{"time":7509,"delay":1000,"type":"screenshot-auto"}],"scrollY":1123,"scrollX":0,"timestamp":1568038221499},{"name":"Action 4","ops":[{"type":"mousedown","time":932,"x":727,"y":73},{"type":"mouseup","time":1028,"x":727,"y":73},{"time":1029,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":1377,"x":726,"y":73},{"type":"mousemove","time":1578,"x":218,"y":194},{"type":"mousemove","time":1778,"x":198,"y":196},{"type":"mousedown","time":1864,"x":198,"y":196},{"type":"mousemove","time":1980,"x":198,"y":211},{"type":"mousemove","time":2181,"x":202,"y":293},{"type":"mousemove","time":2382,"x":202,"y":378},{"type":"mousemove","time":2582,"x":201,"y":403},{"type":"mouseup","time":2904,"x":201,"y":403},{"time":2905,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":3399,"x":201,"y":403},{"type":"mousemove","time":3599,"x":212,"y":392},{"type":"mousemove","time":3805,"x":218,"y":303},{"type":"mousemove","time":4005,"x":213,"y":276},{"type":"mousedown","time":4037,"x":213,"y":276},{"type":"mousemove","time":4216,"x":217,"y":331},{"type":"mousemove","time":4416,"x":218,"y":356},{"type":"mousemove","time":4617,"x":219,"y":363},{"type":"mouseup","time":4647,"x":219,"y":363},{"time":4648,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":4967,"x":220,"y":363},{"type":"mousemove","time":5168,"x":353,"y":345},{"type":"mousemove","time":5367,"x":581,"y":284},{"type":"mousemove","time":5567,"x":627,"y":231},{"type":"mousedown","time":5657,"x":627,"y":230},{"type":"mousemove","time":5770,"x":629,"y":264},{"type":"mousemove","time":5983,"x":633,"y":328},{"type":"mousemove","time":6183,"x":640,"y":376},{"type":"mouseup","time":6585,"x":640,"y":376},{"time":6586,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":6970,"x":640,"y":375},{"type":"mousemove","time":7179,"x":640,"y":286},{"type":"mousemove","time":7384,"x":642,"y":264},{"type":"mousedown","time":7503,"x":642,"y":263},{"type":"mousemove","time":7588,"x":643,"y":281},{"type":"mousemove","time":7802,"x":647,"y":328},{"type":"mouseup","time":7953,"x":648,"y":331},{"time":7954,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":8023,"x":648,"y":331},{"type":"mousemove","time":8196,"x":648,"y":330},{"type":"mousemove","time":8405,"x":678,"y":197},{"type":"mousemove","time":8614,"x":723,"y":94},{"type":"mousemove","time":8823,"x":753,"y":75},{"type":"mousemove","time":9031,"x":754,"y":73},{"type":"mousedown","time":9049,"x":754,"y":73},{"type":"mouseup","time":9123,"x":754,"y":73},{"time":9124,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":9647,"x":754,"y":73},{"type":"mouseup","time":9725,"x":754,"y":73},{"time":9726,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":10291,"x":754,"y":73},{"type":"mouseup","time":10392,"x":754,"y":73},{"time":10393,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":10866,"x":754,"y":73},{"type":"mouseup","time":10956,"x":754,"y":73},{"time":10957,"delay":1000,"type":"screenshot-auto"}],"scrollY":1708,"scrollX":0,"timestamp":1568038236275},{"name":"Action 5","ops":[{"type":"mousedown","time":607,"x":735,"y":117},{"type":"mouseup","time":706,"x":735,"y":117},{"time":707,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":895,"x":734,"y":117},{"type":"mousemove","time":1095,"x":316,"y":269},{"type":"mousemove","time":1307,"x":171,"y":289},{"type":"mousedown","time":1510,"x":171,"y":289},{"type":"mousemove","time":1540,"x":171,"y":290},{"type":"mousemove","time":1744,"x":175,"y":367},{"type":"mousemove","time":1944,"x":178,"y":409},{"type":"mousemove","time":2147,"x":212,"y":415},{"type":"mousemove","time":2348,"x":253,"y":419},{"type":"mousemove","time":2580,"x":254,"y":419},{"type":"mousemove","time":2798,"x":260,"y":420},{"type":"mouseup","time":3191,"x":260,"y":420},{"time":3192,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":3611,"x":257,"y":417},{"type":"mousemove","time":3812,"x":247,"y":406},{"type":"mousemove","time":4026,"x":178,"y":395},{"type":"mousedown","time":4159,"x":178,"y":395},{"type":"mousemove","time":4233,"x":183,"y":395},{"type":"mousemove","time":4436,"x":256,"y":394},{"type":"mousemove","time":4637,"x":266,"y":394},{"type":"mouseup","time":4684,"x":266,"y":394},{"time":4685,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":4855,"x":265,"y":394},{"type":"mousemove","time":5073,"x":269,"y":393},{"type":"mousemove","time":5273,"x":518,"y":385},{"type":"mousemove","time":5473,"x":566,"y":386},{"type":"mousemove","time":5678,"x":592,"y":390},{"type":"mousedown","time":5826,"x":592,"y":390},{"type":"mousemove","time":5906,"x":594,"y":390},{"type":"mousemove","time":6111,"x":676,"y":392},{"type":"mousemove","time":6313,"x":708,"y":395},{"type":"mousemove","time":6642,"x":708,"y":395},{"type":"mouseup","time":6739,"x":708,"y":395},{"time":6740,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":6860,"x":704,"y":395},{"type":"mousemove","time":7060,"x":672,"y":385},{"type":"mousemove","time":7260,"x":656,"y":381},{"type":"mousedown","time":7406,"x":655,"y":381},{"type":"mousemove","time":7476,"x":665,"y":384},{"type":"mousemove","time":7677,"x":692,"y":385},{"type":"mouseup","time":7893,"x":694,"y":385},{"time":7894,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":7944,"x":694,"y":385},{"type":"mousemove","time":8049,"x":694,"y":384},{"type":"mousemove","time":8258,"x":740,"y":160},{"type":"mousemove","time":8464,"x":771,"y":109},{"type":"mousemove","time":8675,"x":746,"y":115},{"type":"mousemove","time":8974,"x":747,"y":115},{"type":"mousemove","time":9184,"x":754,"y":115},{"type":"mousedown","time":9480,"x":754,"y":115},{"type":"mouseup","time":9551,"x":754,"y":115},{"time":9552,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":10069,"x":754,"y":115},{"type":"mouseup","time":10148,"x":754,"y":115},{"time":10149,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":10636,"x":754,"y":115},{"type":"mouseup","time":10706,"x":754,"y":115},{"time":10707,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":11182,"x":754,"y":115},{"type":"mouseup","time":11268,"x":754,"y":115},{"time":11269,"delay":1000,"type":"screenshot-auto"}],"scrollY":2233,"scrollX":0,"timestamp":1568038252219}] \ No newline at end of file +[{"name":"Action 1","ops":[{"type":"mousedown","time":409,"x":770,"y":435},{"type":"mousemove","time":509,"x":770,"y":434},{"type":"mousemove","time":712,"x":770,"y":252},{"type":"mousemove","time":913,"x":768,"y":150},{"type":"mousemove","time":1115,"x":767,"y":139},{"type":"mouseup","time":1480,"x":767,"y":139},{"time":1481,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":2065,"x":766,"y":139},{"type":"mousemove","time":2265,"x":727,"y":130},{"type":"mousemove","time":2478,"x":710,"y":75},{"type":"mousemove","time":2776,"x":709,"y":78},{"type":"mousedown","time":2859,"x":709,"y":78},{"type":"mouseup","time":2935,"x":709,"y":78},{"time":2936,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":2992,"x":709,"y":78},{"type":"mousemove","time":3017,"x":708,"y":79},{"type":"mousemove","time":3222,"x":442,"y":238},{"type":"mousemove","time":3423,"x":325,"y":220},{"type":"mousemove","time":3624,"x":326,"y":224},{"type":"mousemove","time":3857,"x":320,"y":215},{"type":"mousedown","time":3874,"x":320,"y":215},{"type":"mousemove","time":4057,"x":442,"y":311},{"type":"mousemove","time":4257,"x":545,"y":382},{"type":"mousemove","time":4457,"x":554,"y":393},{"type":"mousemove","time":4725,"x":557,"y":396},{"type":"mouseup","time":4732,"x":557,"y":396},{"time":4733,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":4948,"x":557,"y":396},{"type":"mousemove","time":4996,"x":557,"y":396},{"type":"mousemove","time":6022,"x":553,"y":392},{"type":"mousemove","time":6222,"x":406,"y":237},{"type":"mousemove","time":6427,"x":383,"y":198},{"type":"mousemove","time":6627,"x":387,"y":182},{"type":"mousedown","time":6659,"x":404,"y":186},{"type":"mousemove","time":6837,"x":673,"y":299},{"type":"mousemove","time":7038,"x":706,"y":335},{"type":"mouseup","time":7227,"x":706,"y":336},{"time":7228,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":7260,"x":706,"y":336},{"type":"mousemove","time":8179,"x":706,"y":336},{"type":"mousemove","time":8379,"x":690,"y":332},{"type":"mousemove","time":8579,"x":498,"y":284},{"type":"mousemove","time":8783,"x":476,"y":264},{"type":"mousemove","time":8983,"x":474,"y":248},{"type":"mousedown","time":9052,"x":474,"y":248},{"type":"mousemove","time":9196,"x":533,"y":306},{"type":"mousemove","time":9397,"x":553,"y":325},{"type":"mouseup","time":9468,"x":553,"y":325},{"time":9469,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":10044,"x":553,"y":324},{"type":"mousemove","time":10261,"x":553,"y":324},{"type":"mousemove","time":10461,"x":553,"y":324},{"type":"mousemove","time":10661,"x":422,"y":263},{"type":"mousemove","time":10866,"x":413,"y":246},{"type":"mousedown","time":10966,"x":413,"y":246},{"type":"mousemove","time":11066,"x":465,"y":303},{"type":"mousemove","time":11267,"x":518,"y":357},{"type":"mouseup","time":11320,"x":518,"y":357},{"time":11321,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":11508,"x":518,"y":357},{"type":"mousemove","time":11709,"x":518,"y":353},{"type":"mousemove","time":12955,"x":524,"y":345},{"type":"mousemove","time":13156,"x":678,"y":142},{"type":"mousemove","time":13361,"x":716,"y":110},{"type":"mousemove","time":13563,"x":726,"y":87},{"type":"mousedown","time":13735,"x":726,"y":86},{"type":"mousemove","time":13772,"x":726,"y":86},{"type":"mouseup","time":13857,"x":726,"y":86},{"time":13858,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":14608,"x":726,"y":86},{"type":"mouseup","time":14708,"x":726,"y":86},{"time":14709,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":15726,"x":726,"y":86},{"type":"mouseup","time":15812,"x":726,"y":86},{"time":15813,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":17005,"x":726,"y":86},{"type":"mouseup","time":17122,"x":726,"y":86},{"time":17123,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":19668,"x":724,"y":86},{"type":"mousemove","time":19869,"x":662,"y":86}],"scrollY":0,"scrollX":0,"timestamp":1568038153909},{"name":"Action 2","ops":[{"type":"mousedown","time":455,"x":728,"y":71},{"type":"mouseup","time":536,"x":728,"y":71},{"time":537,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":1128,"x":727,"y":72},{"type":"mousemove","time":1328,"x":488,"y":158},{"type":"mousemove","time":1532,"x":166,"y":204},{"type":"mousemove","time":1732,"x":149,"y":208},{"type":"mousedown","time":1780,"x":149,"y":208},{"type":"mousemove","time":1942,"x":204,"y":280},{"type":"mousemove","time":2142,"x":287,"y":360},{"type":"mousemove","time":2343,"x":294,"y":367},{"type":"mousemove","time":2549,"x":304,"y":378},{"type":"mousemove","time":2749,"x":305,"y":380},{"type":"mouseup","time":2852,"x":305,"y":380},{"time":2853,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":5602,"x":307,"y":379},{"type":"mousemove","time":5802,"x":727,"y":100},{"type":"mousemove","time":6020,"x":769,"y":75},{"type":"mousemove","time":6221,"x":737,"y":71},{"type":"mousemove","time":6421,"x":736,"y":71},{"type":"mousedown","time":6546,"x":736,"y":71},{"type":"mouseup","time":6619,"x":736,"y":71},{"time":6620,"delay":1000,"type":"screenshot-auto"}],"scrollY":576,"scrollX":0,"timestamp":1568038203184},{"name":"Action 3","ops":[{"type":"mousedown","time":440,"x":733,"y":88},{"type":"mouseup","time":528,"x":733,"y":88},{"time":529,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":746,"x":732,"y":88},{"type":"mousemove","time":946,"x":270,"y":226},{"type":"mousemove","time":1157,"x":187,"y":231},{"type":"mousemove","time":1357,"x":159,"y":243},{"type":"mousedown","time":1408,"x":159,"y":243},{"type":"mousemove","time":1560,"x":181,"y":287},{"type":"mousemove","time":1761,"x":278,"y":424},{"type":"mousemove","time":1962,"x":320,"y":460},{"type":"mousemove","time":2200,"x":320,"y":460},{"type":"mouseup","time":2275,"x":320,"y":460},{"time":2276,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":3032,"x":320,"y":460},{"type":"mousemove","time":3233,"x":527,"y":325},{"type":"mousemove","time":3443,"x":584,"y":266},{"type":"mousemove","time":3643,"x":595,"y":258},{"type":"mousedown","time":3730,"x":595,"y":258},{"type":"mousemove","time":3845,"x":612,"y":284},{"type":"mousemove","time":4047,"x":711,"y":381},{"type":"mousemove","time":4250,"x":733,"y":391},{"type":"mouseup","time":4368,"x":739,"y":394},{"time":4369,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":4486,"x":739,"y":394},{"type":"mousemove","time":5816,"x":738,"y":393},{"type":"mousemove","time":6023,"x":738,"y":202},{"type":"mousemove","time":6225,"x":753,"y":112},{"type":"mousemove","time":6430,"x":755,"y":96},{"type":"mousedown","time":6587,"x":756,"y":95},{"type":"mousemove","time":6631,"x":756,"y":95},{"type":"mouseup","time":6672,"x":756,"y":95},{"time":6673,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":7406,"x":756,"y":95},{"type":"mouseup","time":7508,"x":756,"y":95},{"time":7509,"delay":1000,"type":"screenshot-auto"}],"scrollY":1123,"scrollX":0,"timestamp":1568038221499},{"name":"Action 4","ops":[{"type":"mousedown","time":932,"x":727,"y":73},{"type":"mouseup","time":1028,"x":727,"y":73},{"time":1029,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":1377,"x":726,"y":73},{"type":"mousemove","time":1578,"x":218,"y":194},{"type":"mousemove","time":1778,"x":198,"y":196},{"type":"mousedown","time":1864,"x":198,"y":196},{"type":"mousemove","time":1980,"x":198,"y":211},{"type":"mousemove","time":2181,"x":202,"y":293},{"type":"mousemove","time":2382,"x":202,"y":378},{"type":"mousemove","time":2582,"x":201,"y":403},{"type":"mouseup","time":2904,"x":201,"y":403},{"time":2905,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":3399,"x":201,"y":403},{"type":"mousemove","time":3599,"x":212,"y":392},{"type":"mousemove","time":3805,"x":218,"y":303},{"type":"mousemove","time":4005,"x":213,"y":276},{"type":"mousedown","time":4037,"x":213,"y":276},{"type":"mousemove","time":4216,"x":217,"y":331},{"type":"mousemove","time":4416,"x":218,"y":356},{"type":"mousemove","time":4617,"x":219,"y":363},{"type":"mouseup","time":4647,"x":219,"y":363},{"time":4648,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":4967,"x":220,"y":363},{"type":"mousemove","time":5168,"x":353,"y":345},{"type":"mousemove","time":5367,"x":581,"y":284},{"type":"mousemove","time":5567,"x":627,"y":231},{"type":"mousedown","time":5657,"x":627,"y":230},{"type":"mousemove","time":5770,"x":629,"y":264},{"type":"mousemove","time":5983,"x":633,"y":328},{"type":"mousemove","time":6183,"x":640,"y":376},{"type":"mouseup","time":6585,"x":640,"y":376},{"time":6586,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":6970,"x":640,"y":375},{"type":"mousemove","time":7179,"x":640,"y":286},{"type":"mousemove","time":7384,"x":642,"y":264},{"type":"mousedown","time":7503,"x":642,"y":263},{"type":"mousemove","time":7588,"x":643,"y":281},{"type":"mousemove","time":7802,"x":647,"y":328},{"type":"mouseup","time":7953,"x":648,"y":331},{"time":7954,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":8023,"x":648,"y":331},{"type":"mousemove","time":8196,"x":648,"y":330},{"type":"mousemove","time":8405,"x":678,"y":197},{"type":"mousemove","time":8614,"x":723,"y":94},{"type":"mousemove","time":8823,"x":753,"y":75},{"type":"mousemove","time":9031,"x":754,"y":73},{"type":"mousedown","time":9049,"x":754,"y":73},{"type":"mouseup","time":9123,"x":754,"y":73},{"time":9124,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":9647,"x":754,"y":73},{"type":"mouseup","time":9725,"x":754,"y":73},{"time":9726,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":10291,"x":754,"y":73},{"type":"mouseup","time":10392,"x":754,"y":73},{"time":10393,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":10866,"x":754,"y":73},{"type":"mouseup","time":10956,"x":754,"y":73},{"time":10957,"delay":1000,"type":"screenshot-auto"}],"scrollY":1708,"scrollX":0,"timestamp":1568038236275},{"name":"Action 5","ops":[{"type":"mousedown","time":607,"x":735,"y":117},{"type":"mouseup","time":706,"x":735,"y":117},{"time":707,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":895,"x":734,"y":117},{"type":"mousemove","time":1095,"x":316,"y":269},{"type":"mousemove","time":1307,"x":171,"y":289},{"type":"mousedown","time":1510,"x":171,"y":289},{"type":"mousemove","time":1540,"x":171,"y":290},{"type":"mousemove","time":1744,"x":175,"y":367},{"type":"mousemove","time":1944,"x":178,"y":409},{"type":"mousemove","time":2147,"x":212,"y":415},{"type":"mousemove","time":2348,"x":253,"y":419},{"type":"mousemove","time":2580,"x":254,"y":419},{"type":"mousemove","time":2798,"x":260,"y":420},{"type":"mouseup","time":3191,"x":260,"y":420},{"time":3192,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":3611,"x":257,"y":417},{"type":"mousemove","time":3812,"x":247,"y":406},{"type":"mousemove","time":4026,"x":178,"y":395},{"type":"mousedown","time":4159,"x":178,"y":395},{"type":"mousemove","time":4233,"x":183,"y":395},{"type":"mousemove","time":4436,"x":256,"y":394},{"type":"mousemove","time":4637,"x":266,"y":394},{"type":"mouseup","time":4684,"x":266,"y":394},{"time":4685,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":4855,"x":265,"y":394},{"type":"mousemove","time":5073,"x":269,"y":393},{"type":"mousemove","time":5273,"x":518,"y":385},{"type":"mousemove","time":5473,"x":566,"y":386},{"type":"mousemove","time":5678,"x":592,"y":390},{"type":"mousedown","time":5826,"x":592,"y":390},{"type":"mousemove","time":5906,"x":594,"y":390},{"type":"mousemove","time":6111,"x":676,"y":392},{"type":"mousemove","time":6313,"x":708,"y":395},{"type":"mousemove","time":6642,"x":708,"y":395},{"type":"mouseup","time":6739,"x":708,"y":395},{"time":6740,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":6860,"x":704,"y":395},{"type":"mousemove","time":7060,"x":672,"y":385},{"type":"mousemove","time":7260,"x":656,"y":381},{"type":"mousedown","time":7406,"x":655,"y":381},{"type":"mousemove","time":7476,"x":665,"y":384},{"type":"mousemove","time":7677,"x":692,"y":385},{"type":"mouseup","time":7893,"x":694,"y":385},{"time":7894,"delay":1000,"type":"screenshot-auto"},{"type":"mousemove","time":7944,"x":694,"y":385},{"type":"mousemove","time":8049,"x":694,"y":384},{"type":"mousemove","time":8258,"x":740,"y":160},{"type":"mousemove","time":8464,"x":771,"y":109},{"type":"mousemove","time":8675,"x":746,"y":115},{"type":"mousemove","time":8974,"x":747,"y":115},{"type":"mousemove","time":9184,"x":754,"y":115},{"type":"mousedown","time":9480,"x":754,"y":115},{"type":"mouseup","time":9551,"x":754,"y":115},{"time":9552,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":10069,"x":754,"y":115},{"type":"mouseup","time":10148,"x":754,"y":115},{"time":10149,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":10636,"x":754,"y":115},{"type":"mouseup","time":10706,"x":754,"y":115},{"time":10707,"delay":1000,"type":"screenshot-auto"},{"type":"mousedown","time":11182,"x":754,"y":115},{"type":"mouseup","time":11268,"x":754,"y":115},{"time":11269,"delay":1000,"type":"screenshot-auto"}],"scrollY":2233,"scrollX":0,"timestamp":1568038252219},{"name":"Action 6","ops":[{"type":"mousemove","time":358,"x":292,"y":305},{"type":"mousemove","time":569,"x":202,"y":296},{"type":"mousemove","time":783,"x":146,"y":303},{"type":"mousemove","time":983,"x":228,"y":303},{"type":"mousemove","time":1192,"x":222,"y":322},{"type":"mousemove","time":1411,"x":266,"y":246},{"type":"mousemove","time":1619,"x":405,"y":247},{"type":"mousemove","time":1833,"x":400,"y":238},{"type":"mousemove","time":2036,"x":396,"y":236},{"type":"mousemove","time":2257,"x":424,"y":234},{"type":"mousemove","time":2457,"x":649,"y":262},{"type":"mousemove","time":2682,"x":770,"y":217},{"type":"mousemove","time":2895,"x":768,"y":212},{"type":"mousemove","time":3124,"x":762,"y":215},{"type":"mousedown","time":3200,"x":762,"y":215},{"type":"mouseup","time":3217,"x":762,"y":215},{"time":3218,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":3396,"x":761,"y":215},{"type":"mousemove","time":3602,"x":478,"y":315},{"type":"mousemove","time":3813,"x":393,"y":286},{"type":"mousemove","time":4019,"x":380,"y":274},{"type":"mousemove","time":4235,"x":378,"y":274},{"type":"mousedown","time":4401,"x":378,"y":274},{"type":"mousemove","time":4417,"x":379,"y":291},{"type":"mousemove","time":4639,"x":401,"y":458},{"type":"mousemove","time":4841,"x":410,"y":525},{"type":"mousemove","time":5067,"x":410,"y":527},{"type":"mouseup","time":5377,"x":410,"y":527},{"time":5378,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":5421,"x":448,"y":465},{"type":"mousemove","time":5647,"x":507,"y":396},{"type":"mousemove","time":5920,"x":507,"y":396},{"type":"mousemove","time":6680,"x":502,"y":384},{"type":"mousemove","time":6886,"x":398,"y":276},{"type":"mousemove","time":7087,"x":378,"y":231},{"type":"mousemove","time":7336,"x":370,"y":214},{"type":"mousedown","time":7624,"x":370,"y":214},{"type":"mouseup","time":7640,"x":370,"y":214},{"time":7641,"delay":400,"type":"screenshot-auto"},{"type":"mousedown","time":8944,"x":370,"y":214},{"type":"mouseup","time":8964,"x":370,"y":214},{"time":8965,"delay":400,"type":"screenshot-auto"},{"type":"mousedown","time":10163,"x":370,"y":214},{"type":"mouseup","time":10175,"x":370,"y":214},{"time":10176,"delay":400,"type":"screenshot-auto"},{"type":"mousedown","time":11716,"x":370,"y":214},{"type":"mouseup","time":11738,"x":370,"y":214},{"time":11739,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":12316,"x":371,"y":214},{"type":"mousemove","time":12563,"x":372,"y":214},{"type":"mousemove","time":12761,"x":372,"y":214},{"type":"mousemove","time":12993,"x":747,"y":257},{"type":"mousemove","time":13359,"x":799,"y":229},{"type":"mousemove","time":13571,"x":789,"y":217},{"type":"mousemove","time":13803,"x":786,"y":217},{"type":"mousedown","time":13900,"x":786,"y":217},{"type":"mouseup","time":13912,"x":786,"y":217},{"time":13913,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":15464,"x":786,"y":217},{"type":"mousemove","time":15679,"x":758,"y":233},{"type":"mousemove","time":15882,"x":623,"y":240},{"type":"mousemove","time":16097,"x":548,"y":237},{"type":"mousemove","time":16318,"x":681,"y":235},{"type":"mousemove","time":16520,"x":760,"y":220},{"type":"mousemove","time":16730,"x":778,"y":215},{"type":"mousemove","time":16959,"x":763,"y":224},{"type":"mousemove","time":17229,"x":766,"y":218},{"type":"mousemove","time":17479,"x":766,"y":218},{"type":"mousedown","time":19210,"x":766,"y":218},{"type":"mouseup","time":19227,"x":766,"y":218},{"time":19228,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":19357,"x":762,"y":218},{"type":"mousemove","time":19562,"x":414,"y":280},{"type":"mousemove","time":19763,"x":387,"y":281},{"type":"mousemove","time":19973,"x":491,"y":259},{"type":"mousemove","time":20181,"x":727,"y":212},{"type":"mousemove","time":20398,"x":764,"y":225},{"type":"mousemove","time":20602,"x":766,"y":217},{"type":"mousedown","time":20730,"x":766,"y":217},{"type":"mouseup","time":20752,"x":766,"y":217},{"time":20753,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":20902,"x":763,"y":217},{"type":"mousemove","time":21113,"x":429,"y":276},{"type":"mousemove","time":21326,"x":391,"y":282},{"type":"mousemove","time":21549,"x":387,"y":272},{"type":"mousedown","time":21788,"x":387,"y":271},{"type":"mousemove","time":21810,"x":387,"y":271},{"type":"mousemove","time":21824,"x":389,"y":298},{"type":"mousemove","time":22035,"x":401,"y":473},{"type":"mousemove","time":22242,"x":405,"y":503},{"type":"mousemove","time":22477,"x":406,"y":505},{"type":"mouseup","time":22566,"x":406,"y":505},{"time":22567,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":22602,"x":423,"y":460},{"type":"mousemove","time":22810,"x":448,"y":319},{"type":"mousemove","time":23018,"x":441,"y":291},{"type":"mousemove","time":23245,"x":406,"y":240},{"type":"mousemove","time":23455,"x":372,"y":213},{"type":"mousemove","time":23681,"x":366,"y":210},{"type":"mousedown","time":23745,"x":366,"y":210},{"type":"mouseup","time":23761,"x":366,"y":210},{"time":23762,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":24113,"x":370,"y":210},{"type":"mousemove","time":24334,"x":696,"y":217},{"type":"mousemove","time":24536,"x":738,"y":208},{"type":"mousemove","time":24758,"x":779,"y":209},{"type":"mousemove","time":25013,"x":785,"y":213},{"type":"mousedown","time":25433,"x":785,"y":213},{"type":"mouseup","time":25446,"x":785,"y":213},{"time":25447,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":26004,"x":781,"y":216},{"type":"mousemove","time":26204,"x":684,"y":263},{"type":"mousemove","time":26415,"x":538,"y":257},{"type":"mousemove","time":26637,"x":401,"y":238},{"type":"mousemove","time":26842,"x":368,"y":207},{"type":"mousemove","time":27065,"x":368,"y":206},{"type":"mousedown","time":27142,"x":368,"y":206},{"type":"mouseup","time":27158,"x":368,"y":206},{"time":27159,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":28240,"x":368,"y":206},{"type":"mousemove","time":28458,"x":405,"y":273},{"type":"mousemove","time":28672,"x":454,"y":310},{"type":"mousemove","time":28896,"x":473,"y":327}],"scrollY":2763,"scrollX":0,"timestamp":1569247963371}] \ No newline at end of file From 60d2751bdd879843ea6d7f74e25d1a7824589c31 Mon Sep 17 00:00:00 2001 From: yufeng04 Date: Tue, 24 Sep 2019 01:23:56 +0800 Subject: [PATCH 127/127] Modified the logic of function setSymbolStyle --- src/component/legend/LegendView.js | 16 ++++++++++------ test/legend-borderColor.html | 4 +++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/component/legend/LegendView.js b/src/component/legend/LegendView.js index c6c059e43c..3556038fb9 100644 --- a/src/component/legend/LegendView.js +++ b/src/component/legend/LegendView.js @@ -314,7 +314,7 @@ export default echarts.extendComponentView({ var inactiveColor = legendModel.get('inactiveColor'); var inactiveBorderColor = legendModel.get('inactiveBorderColor'); var symbolKeepAspect = legendModel.get('symbolKeepAspect'); - var itemStyle = legendModel.getModel('itemStyle').getItemStyle(); + var legendModelItemStyle = legendModel.getModel('itemStyle'); var isSelected = legendModel.isSelected(name); var itemGroup = new Group(); @@ -340,7 +340,7 @@ export default echarts.extendComponentView({ ); itemGroup.add( setSymbolStyle( - legendSymbol, legendSymbolType, itemStyle, + legendSymbol, legendSymbolType, legendModelItemStyle, borderColor, inactiveBorderColor, isSelected ) ); @@ -368,7 +368,7 @@ export default echarts.extendComponentView({ // Put symbol in the center itemGroup.add( setSymbolStyle( - legendSymbolCenter, symbolType, itemStyle, + legendSymbolCenter, symbolType, legendModelItemStyle, borderColor, inactiveBorderColor, isSelected ) ); @@ -503,15 +503,19 @@ export default echarts.extendComponentView({ }); -function setSymbolStyle(symbol, symbolType, itemStyle, borderColor, inactiveBorderColor, isSelected) { +function setSymbolStyle(symbol, symbolType, legendModelItemStyle, borderColor, inactiveBorderColor, isSelected) { + var itemStyle; if (symbolType !== 'line' && symbolType.indexOf('empty') < 0) { + itemStyle = legendModelItemStyle.getItemStyle(); symbol.style.stroke = borderColor; if (!isSelected) { itemStyle.stroke = inactiveBorderColor; } - symbol.setStyle(itemStyle); } - return symbol; + else { + itemStyle = legendModelItemStyle.getItemStyle(['borderWidth', 'borderColor']); + } + return symbol.setStyle(itemStyle); } function dispatchSelectAction(name, api) { diff --git a/test/legend-borderColor.html b/test/legend-borderColor.html index 7caa9fbd2d..8eb11a577d 100644 --- a/test/legend-borderColor.html +++ b/test/legend-borderColor.html @@ -74,7 +74,8 @@ data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'], itemStyle: { // borderColor: '#f00', - borderWidth: 3 + borderWidth: 3, + borderType: 'dashed' }, selected: { '联盟广告': false, @@ -179,6 +180,7 @@ title: [ '(Legend symbol of line)', 'the emptyCircle symbol doesn\'t have fillColor, so the strokeColor should be the same as color of corresponding series', + 'the borderType of legend symbol is dashed, especially the first emptyCircle symbol', 'the color of line in legend symbol should be same as corresponding symbol', 'the borderWidth of legend symbols should only be determined by legend.itemStyle.borderWidth', 'the second and the third legend symbol should be unselected'