From f370474fcadcdcf5c4324e729afeb481f0075a70 Mon Sep 17 00:00:00 2001 From: lang Date: Tue, 10 Nov 2015 23:08:45 +0800 Subject: [PATCH] Marker tooltip --- src/component/marker/MarkLineModel.js | 75 ++++++++++++-------------- src/component/marker/MarkLineView.js | 71 ++++++++++++++++++++---- src/component/marker/MarkPointModel.js | 6 ++- src/component/marker/MarkPointView.js | 61 ++++++++++++++++++--- src/component/marker/SeriesMarkLine.js | 6 +-- src/component/marker/markerHelper.js | 19 ++++--- src/component/tooltip.js | 69 ++++++++++++++---------- src/component/tooltip/TooltipModel.js | 2 +- src/data/List.js | 10 ++-- 9 files changed, 219 insertions(+), 100 deletions(-) diff --git a/src/component/marker/MarkLineModel.js b/src/component/marker/MarkLineModel.js index fe1ba51f3..b955ceed8 100644 --- a/src/component/marker/MarkLineModel.js +++ b/src/component/marker/MarkLineModel.js @@ -32,8 +32,9 @@ define(function (require) { else { mlModel.mergeOption(markLineOpt, true); } - // Use the same series index + // Use the same series index and name mlModel.seriesIndex = seriesModel.seriesIndex; + mlModel.name = seriesModel.name; seriesModel.markLineModel = mlModel; } else { @@ -56,6 +57,9 @@ define(function (require) { //smooth: false, smoothness: 0.2, // 平滑度 precision: 2, + tooltip: { + trigger: 'item' + }, effect: { show: false, loop: true, @@ -65,11 +69,33 @@ define(function (require) { // shadowColor: 'rgba(255,215,0,0.8)', // shadowBlur: lineWidth * 2 // 炫光模糊,默认等于scaleSize计算所得 }, - // 边捆绑 - bundling: { - enable: false, - // [0, 90] - maxTurningAngle: 45 + label: { + normal: { + show: true, + // 标签文本格式器,同Tooltip.formatter,不支持回调 + // formatter: null, + // 可选为 'start'|'end'|'left'|'right'|'top'|'bottom' + position: 'end' + // 默认使用全局文本样式,详见TEXTSTYLE + // textStyle: null + } + }, + lineStyle: { + normal: { + // 主色,线色,优先级高于borderColor和color + // color: 随borderColor, + // 优先于borderWidth + // width: 随borderWidth, + type: 'dashed' + //默认透明 + // shadowColor: 'rgba(0,0,0,0)', + // shadowBlur: 0, + // shadowOffsetX: 0, + // shadowOffsetY: 0 + }, + emphasis: { + width: 3 + } }, itemStyle: { normal: { @@ -78,42 +104,9 @@ define(function (require) { // 标线symbol边框颜色,优先于color // borderColor: 随color, // 标线symbol边框线宽,单位px,默认为2 - borderWidth: 2, - label: { - show: true, - // 标签文本格式器,同Tooltip.formatter,不支持回调 - // formatter: null, - // 可选为 'start'|'end'|'left'|'right'|'top'|'bottom' - position: 'end' - // 默认使用全局文本样式,详见TEXTSTYLE - // textStyle: null - }, - lineStyle: { - // 主色,线色,优先级高于borderColor和color - // color: 随borderColor, - // 优先于borderWidth - // width: 随borderWidth, - type: 'dashed' - //默认透明 - // shadowColor: 'rgba(0,0,0,0)', - // shadowBlur: 0, - // shadowOffsetX: 0, - // shadowOffsetY: 0 - } - }, - emphasis: { - // color: 各异 - label: { - show: false - // 标签文本格式器,同Tooltip.formatter,不支持回调 - // formatter: null, - // position: 'inside' // 'left'|'right'|'top'|'bottom' - // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE - }, - lineStyle: { - width: 3 - } + borderWidth: 2 } + // emphasis: {} } } }); diff --git a/src/component/marker/MarkLineView.js b/src/component/marker/MarkLineView.js index 086415073..c186c8077 100644 --- a/src/component/marker/MarkLineView.js +++ b/src/component/marker/MarkLineView.js @@ -1,7 +1,13 @@ define(function (require) { + var SeriesModel = require('../../model/Series'); var zrUtil = require('zrender/core/util'); var List = require('../../data/List'); + var formatUtil = require('../../util/format'); + var retrieveValue = require('../../util/model').retrieveValue; + + var addCommas = formatUtil.addCommas; + var encodeHTML = formatUtil.encodeHTML; var markerHelper = require('./markerHelper'); @@ -35,14 +41,15 @@ define(function (require) { mlFrom[valueAxisKey] = mlTo[valueAxisKey] = value; - item = [ - mlFrom, - mlTo - ]; - }; + item = [mlFrom, mlTo, { // Extra option for tooltip and label + __rawValue: value, + name: item.name + }]; + } return [ markerHelper.dataTransform(data, baseAxis, valueAxis, item[0]), - markerHelper.dataTransform(data, baseAxis, valueAxis, item[1]) + markerHelper.dataTransform(data, baseAxis, valueAxis, item[1]), + item[2] || {} ]; }; @@ -51,6 +58,31 @@ define(function (require) { && markerHelper.dataFilter(coordSys, dimensionInverse, item[1]); } + var seriesModelProto = SeriesModel.prototype; + var markLineFormatMixin = { + getFormatParams: seriesModelProto.getFormatParams, + + getFormattedLabel: seriesModelProto.getFormattedLabel, + + formatTooltip: function (dataIndex) { + var data = this._data; + var value = data.getRawValue(dataIndex); + var formattedValue = zrUtil.isArray(value) + ? zrUtil.map(value, addCommas).join(', ') : addCommas(value); + var name = data.getName(dataIndex); + return this.name + '
' + + ((name ? encodeHTML(name) + ' : ' : '') + formattedValue); + }, + + getData: function () { + return this._data; + }, + + setData: function (data) { + this._data = data; + } + }; + require('../../echarts').extendComponentView({ type: 'markLine', @@ -94,12 +126,21 @@ define(function (require) { } this.group.add(seriesMarkLine.group); - var mlData = createList(coordSys, seriesData, mlModel) + var mlData = createList(coordSys, seriesData, mlModel); var dims = coordSys.dimensions; var fromData = mlData.from; var toData = mlData.to; + // Line data for tooltip and formatter + var lineData = mlData.line; + lineData.getRawValue = function (idx) { + var option = this.getItemModel(idx).option; + return retrieveValue(option.__rawValue, option.value, ''); + }; + zrUtil.mixin(mlModel, markLineFormatMixin); + mlModel.setData(lineData); + var symbolType = mlModel.get('symbol'); var symbolSize = mlModel.get('symbolSize'); if (!zrUtil.isArray(symbolType)) { @@ -116,6 +157,12 @@ define(function (require) { seriesMarkLine.update(fromData, toData); + // Set host model for tooltip + // FIXME + mlData.from.eachItemGraphicEl(function (el, idx) { + el.hostModel = mlModel; + }); + function updateDataVisualAndLayout(data, idx, isFrom) { var itemModel = data.getItemModel(idx); @@ -161,6 +208,8 @@ define(function (require) { ); var fromData = new List(dimensionInfosMap, mlModel); var toData = new List(dimensionInfosMap, mlModel); + // No dimensions + var lineData = new List([], mlModel); if (coordSys) { var baseAxis = coordSys.getBaseAxis(); @@ -188,11 +237,15 @@ define(function (require) { toData.initData( zrUtil.map(optData, function (item) { return item[1]; }) ); + lineData.initData( + zrUtil.map(optData, function (item) { return item[2]; }) + ); } return { from: fromData, - to: toData + to: toData, + line: lineData }; - }; + } }); \ No newline at end of file diff --git a/src/component/marker/MarkPointModel.js b/src/component/marker/MarkPointModel.js index 038546dbc..bd1ff977f 100644 --- a/src/component/marker/MarkPointModel.js +++ b/src/component/marker/MarkPointModel.js @@ -31,8 +31,9 @@ define(function (require) { else { mpModel.mergeOption(markPointOpt, true); } - // Use the same series index + // Use the same series index and name mpModel.seriesIndex = seriesModel.seriesIndex; + mpModel.name = seriesModel.name; seriesModel.markPointModel = mpModel; } else { @@ -50,6 +51,9 @@ define(function (require) { symbolSize: 50, // 标注大小 // symbolRotate: null, // 标注旋转控制 large: false, + tooltip: { + trigger: 'item' + }, effect: { show: false, loop: true, diff --git a/src/component/marker/MarkPointView.js b/src/component/marker/MarkPointView.js index 8d9402335..c8a7ba46b 100644 --- a/src/component/marker/MarkPointView.js +++ b/src/component/marker/MarkPointView.js @@ -1,12 +1,44 @@ define(function (require) { + var SeriesModel = require('../../model/Series'); var SymbolDraw = require('../../chart/helper/SymbolDraw'); var zrUtil = require('zrender/core/util'); + var formatUtil = require('../../util/format'); + var retrieveValue = require('../../util/model').retrieveValue; + + var addCommas = formatUtil.addCommas; + var encodeHTML = formatUtil.encodeHTML; var List = require('../../data/List'); var markerHelper = require('./markerHelper'); + // FIXME + var seriesModelProto = SeriesModel.prototype; + var markPointFormatMixin = { + getFormatParams: seriesModelProto.getFormatParams, + + getFormattedLabel: seriesModelProto.getFormattedLabel, + + formatTooltip: function (dataIndex) { + var data = this._data; + var value = data.getRawValue(dataIndex); + var formattedValue = zrUtil.isArray(value) + ? zrUtil.map(value, addCommas).join(', ') : addCommas(value); + var name = data.getName(dataIndex); + return this.name + '
' + + ((name ? encodeHTML(name) + ' : ' : '') + formattedValue); + }, + + getData: function () { + return this._data; + }, + + setData: function (data) { + this._data = data; + } + }; + require('../../echarts').extendComponentView({ type: 'markPoint', @@ -15,7 +47,7 @@ define(function (require) { this._symbolDrawMap = {}; }, - render: function (markPointModel, ecModel) { + render: function (markPointModel, ecModel, api) { var symbolDrawMap = this._symbolDrawMap; for (var name in symbolDrawMap) { symbolDrawMap[name].__keep = false; @@ -23,7 +55,7 @@ define(function (require) { ecModel.eachSeries(function (seriesModel) { var mpModel = seriesModel.markPointModel; - mpModel && this._renderSeriesMP(seriesModel, mpModel); + mpModel && this._renderSeriesMP(seriesModel, mpModel, api); }, this); for (var name in symbolDrawMap) { @@ -34,7 +66,7 @@ define(function (require) { } }, - _renderSeriesMP: function (seriesModel, mpModel) { + _renderSeriesMP: function (seriesModel, mpModel, api) { var coordSys = seriesModel.coordinateSystem; var seriesName = seriesModel.name; var seriesData = seriesModel.getData(); @@ -48,6 +80,16 @@ define(function (require) { var mpData = createList(coordSys, seriesData, mpModel); var dims = coordSys.dimensions; + // Overwrite getRawValue + // FIXME + mpData.getRawValue = function (idx) { + var option = this.getItemModel(idx).option; + return retrieveValue(option.__rawValue, option.value, ''); + }; + // FIXME + zrUtil.mixin(mpModel, markPointFormatMixin); + mpModel.setData(mpData); + mpData.each(function (idx) { var itemModel = mpData.getItemModel(idx); var point; @@ -73,10 +115,17 @@ define(function (require) { }); // TODO Text are wrong - symbolDraw.updateData(mpData, seriesModel, true); - + symbolDraw.updateData( + mpData, mpModel, api, true + ); this.group.add(symbolDraw.group); + // Set host model for tooltip + // FIXME + mpData.eachItemGraphicEl(function (el) { + el.hostModel = mpModel; + }); + symbolDraw.__keep = true; } }); @@ -119,5 +168,5 @@ define(function (require) { } return mpData; - }; + } }); \ No newline at end of file diff --git a/src/component/marker/SeriesMarkLine.js b/src/component/marker/SeriesMarkLine.js index f1a7ee2a2..587c3434d 100644 --- a/src/component/marker/SeriesMarkLine.js +++ b/src/component/marker/SeriesMarkLine.js @@ -167,18 +167,18 @@ define(function (require) { { stroke: fromData.getItemVisual(idx, 'color') }, - itemModel.getModel('itemStyle.normal.lineStyle').getLineStyle() + itemModel.getModel('lineStyle.normal').getLineStyle() )); graphic.setHoverStyle( line, - itemModel.getModel('itemStyle.emphasis.lineStyle').getLineStyle() + itemModel.getModel('lineStyle.emphasis').getLineStyle() ); }); this._fromData = fromData; this._toData = toData; - } + }; return SeriesMarkLine; }); \ No newline at end of file diff --git a/src/component/marker/markerHelper.js b/src/component/marker/markerHelper.js index 29a325e29..087371c83 100644 --- a/src/component/marker/markerHelper.js +++ b/src/component/marker/markerHelper.js @@ -67,28 +67,33 @@ define(function (require) { // 1. If not specify the position with pixel directly // 2. If value is not a data array. Which uses xAxis, yAxis to specify the value on each dimension if (isNaN(item.x) || isNaN(item.y) && !zrUtil.isArray(item.value)) { + var valueAxisDim = valueAxis.dim; + var valueIndex = (valueAxisDim === 'angle' || valueAxisDim === 'x') ? 0 : 1; // Clone the option // Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value - // Competitable with 2.x item = zrUtil.extend({}, item); - - // Special types, Compatible with 2.0 if (item.type && markerTypeCalculator[item.type] && baseAxis && valueAxis) { var value = markerTypeCalculator[item.type]( - data, baseAxis.dim, valueAxis.dim + data, baseAxis.dim, valueAxisDim ); - value.push(+item.value); + if (item.value != null) { + value.push(+item.value); + } item.value = value; } else { + var originalValue = item.value; // FIXME Only has one of xAxis and yAxis. item.value = [ item.xAxis != null ? item.xAxis : item.radiusAxis, - item.yAxis != null ? item.yAxis : item.angleAxis, - +item.value + item.yAxis != null ? item.yAxis : item.angleAxis ]; + if (originalValue != null) { + item.value.push(+originalValue); + } } + item.__rawValue = item.value[valueIndex]; } return item; }; diff --git a/src/component/tooltip.js b/src/component/tooltip.js index 4bce314f5..c33a6b1db 100644 --- a/src/component/tooltip.js +++ b/src/component/tooltip.js @@ -219,12 +219,14 @@ define(function (require) { // Always show item tooltip if mouse is on the element with dataIndex if (el && el.dataIndex != null) { - - var seriesModel = ecModel.getSeriesByIndex( + // Use hostModel in element if possible + // Used when mouseover on a element like markPoint or edge + // In which case, the data is not main data in series. + var hostModel = el.hostModel || ecModel.getSeriesByIndex( el.seriesIndex, true ); var dataIndex = el.dataIndex; - var itemModel = seriesModel.getData().getItemModel(dataIndex); + var itemModel = hostModel.getData().getItemModel(dataIndex); // Series or single data may use item trigger when global is axis trigger if ((itemModel.get('tooltip.trigger') || trigger) === 'axis') { this._showAxisTooltip(tooltipModel, ecModel, e); @@ -232,9 +234,11 @@ define(function (require) { else { // Reset ticket this._ticket = ''; + // Reset lastHoverData + this._lastHoverData = null; // If either single data or series use item trigger this._hideAxisPointer(); - this._showItemTooltipContent(seriesModel, dataIndex, e); + this._showItemTooltipContent(hostModel, dataIndex, e); } } else { @@ -342,6 +346,7 @@ define(function (require) { var self = this; var axisPointerType = axisPointerModel.get('type'); + var moveAnimation = axisPointerType !== 'cross'; if (axisPointerType === 'cross') { moveGridLine('x', point, cartesian.getAxis('y').getExtent()); @@ -371,12 +376,13 @@ define(function (require) { var pointerEl = self._getPointerElement( cartesian, axisPointerModel, axisType, targetShape ); - pointerEl.animateTo({ - shape: targetShape - }, 200, 'cubicOut'); - // pointerEl.attr({ - // shape: targetShape - // }); + moveAnimation + ? pointerEl.animateTo({ + shape: targetShape + }, 200, 'cubicOut') + : pointerEl.attr({ + shape: targetShape + }); } /** @@ -393,13 +399,13 @@ define(function (require) { var pointerEl = self._getPointerElement( cartesian, axisPointerModel, axisType, targetShape ); - // FIXME 动画总是感觉不连贯 - pointerEl.animateTo({ - shape: targetShape - }, 200, 'cubicOut'); - // pointerEl.attr({ - // shape: targetShape - // }); + moveAnimation + ? pointerEl.animateTo({ + shape: targetShape + }, 200, 'cubicOut') + : pointerEl.attr({ + shape: targetShape + }); } }, @@ -418,6 +424,8 @@ define(function (require) { var angleAxis = polar.getAngleAxis(); var radiusAxis = polar.getRadiusAxis(); + var moveAnimation = axisPointerType !== 'cross'; + if (axisPointerType === 'cross') { movePolarLine('angle', point, radiusAxis.getExtent()); movePolarLine('radius', point, angleAxis.getExtent()); @@ -456,12 +464,14 @@ define(function (require) { var pointerEl = self._getPointerElement( polar, axisPointerModel, axisType, targetShape ); - pointerEl.animateTo({ - shape: targetShape - }, 200, 'cubicOut'); - // pointerEl.attr({ - // shape: targetShape - // }); + + moveAnimation + ? pointerEl.animateTo({ + shape: targetShape + }, 200, 'cubicOut') + : pointerEl.attr({ + shape: targetShape + }); } /** @@ -497,12 +507,13 @@ define(function (require) { var pointerEl = self._getPointerElement( polar, axisPointerModel, axisType, targetShape ); - pointerEl.animateTo({ - shape: targetShape - }, 200, 'cubicOut'); - // pointerEl.attr({ - // shape: targetShape - // }); + moveAnimation + ? pointerEl.animateTo({ + shape: targetShape + }, 200, 'cubicOut') + : pointerEl.attr({ + shape: targetShape + }); } }, diff --git a/src/component/tooltip/TooltipModel.js b/src/component/tooltip/TooltipModel.js index dc1550561..b21b2dd36 100644 --- a/src/component/tooltip/TooltipModel.js +++ b/src/component/tooltip/TooltipModel.js @@ -43,7 +43,7 @@ define(function (require) { enterable: false, // 提示背景颜色,默认为透明度为0.7的黑色 - backgroundColor: 'rgba(0,0,0,0.7)', + backgroundColor: 'rgba(50,50,50,0.7)', // 提示边框颜色 borderColor: '#333', diff --git a/src/data/List.js b/src/data/List.js index f84729546..e242f599d 100644 --- a/src/data/List.js +++ b/src/data/List.js @@ -222,11 +222,12 @@ define(function (require) { ); for (var idx = 0; idx < data.length; idx++) { var value = data[idx]; - // Each data item contains `value` and other option + // Each data item is an option contains value or other properties // { - // value: [] + // value: + // itemStyle: // } - if (data[idx] != null && data[idx].hasOwnProperty(valueProp)) { + if (data[idx] != null && (typeof data[idx] === 'object') && !zrUtil.isArray(data[idx])) { value = data[idx][valueProp]; var model = new Model(data[idx], this.hostModel, this.hostModel.ecModel); @@ -234,6 +235,9 @@ define(function (require) { optionModelIndices[idx] = modelIdx; optionModels.push(model); } + // Each data item is value + // [1, 2] + // 2 else { // Reference to the undefined optionModelIndices[idx] = -1; -- GitLab