You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by ov...@apache.org on 2018/07/03 07:08:59 UTC

[incubator-echarts] branch master updated: feat(tooltip): improve tooltip interface, implement other functions

This is an automated email from the ASF dual-hosted git repository.

ovilia pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git


The following commit(s) were added to refs/heads/master by this push:
     new c631068  feat(tooltip): improve tooltip interface, implement other functions
c631068 is described below

commit c631068aa4ec3458ba04b9f3842f106759405460
Author: Ovilia <zw...@gmail.com>
AuthorDate: Tue Jul 3 15:08:34 2018 +0800

    feat(tooltip): improve tooltip interface, implement other functions
---
 src/component/tooltip/TooltipModel.js       |  6 ++--
 src/component/tooltip/TooltipRichContent.js | 53 +++++++++++++++++++++++++++--
 src/component/tooltip/TooltipView.js        | 34 ++++++++++--------
 src/model/Series.js                         | 42 +++++++++++++++++------
 src/model/mixin/dataFormat.js               |  7 +++-
 src/util/format.js                          | 23 +++++++++----
 6 files changed, 125 insertions(+), 40 deletions(-)

diff --git a/src/component/tooltip/TooltipModel.js b/src/component/tooltip/TooltipModel.js
index 5fe862b..b115871 100644
--- a/src/component/tooltip/TooltipModel.js
+++ b/src/component/tooltip/TooltipModel.js
@@ -46,10 +46,10 @@ export default echarts.extendComponentModel({
 
         displayMode: 'single', // 'single' | 'multipleByCoordSys'
 
-        useHtml: 'auto', // 'auto', true, or false
+        renderMode: 'auto', // 'auto' | 'html' | 'richtext'
         // 'auto': use html by default, and use non-html if `document` is not defined
-        // true: use html for tooltip
-        // false: use canvas, svg, and etc. for tooltip
+        // 'html': use html for tooltip
+        // 'richtext': use canvas, svg, and etc. for tooltip
 
         // 位置 {Array} | {Function}
         // position: null
diff --git a/src/component/tooltip/TooltipRichContent.js b/src/component/tooltip/TooltipRichContent.js
index b5f8078..d7df394 100644
--- a/src/component/tooltip/TooltipRichContent.js
+++ b/src/component/tooltip/TooltipRichContent.js
@@ -17,6 +17,7 @@
 * under the License.
 */
 
+import * as zrUtil from 'zrender/src/core/util';
 import Group from 'zrender/src/container/Group';
 import Text from 'zrender/src/graphic/Text';
 
@@ -30,9 +31,6 @@ function TooltipRichContent(api) {
     var zr = this._zr = api.getZr();
     // zr.add(this.el);
 
-    this._x = api.getWidth() / 2;
-    this._y = api.getHeight() / 2;
-
     this._show = false;
 
     /**
@@ -55,6 +53,7 @@ TooltipRichContent.prototype = {
      * Update when tooltip is rendered
      */
     update: function () {
+        // noop
     },
 
     show: function (tooltipModel) {
@@ -66,6 +65,13 @@ TooltipRichContent.prototype = {
         this._show = true;
     },
 
+    /**
+     * Set tooltip content
+     *
+     * @param {string} content rich text string of content
+     * @param {Object} markerRich rich text style
+     * @param {Object} tooltipModel tooltip model
+     */
     setContent: function (content, markerRich, tooltipModel) {
         if (this.el) {
             this._zr.remove(this.el);
@@ -103,6 +109,34 @@ TooltipRichContent.prototype = {
             z: tooltipModel.get('z')
         });
         this._zr.add(this.el);
+
+        var self = this;
+        this.el.on('mouseover', function () {
+            // clear the timeout in hideLater and keep showing tooltip
+            if (self._enterable) {
+                clearTimeout(self._hideTimeout);
+                self._show = true;
+            }
+            self._inContent = true;
+        });
+        this.el.on('mousemove', function (e) {
+            e = e || window.event;
+            if (!self._enterable) {
+                // Try trigger zrender event to avoid mouse
+                // in and out shape too frequently
+                var handler = zr.handler;
+                eventUtil.normalizeEvent(container, e, true);
+                handler.dispatch('mousemove', e);
+            }
+        });
+        this.el.on('mouseout', function () {
+            if (self._enterable) {
+                if (self._show) {
+                    self.hideLater(self._hideDelay);
+                }
+            }
+            self._inContent = false;
+        });
     },
 
     setEnterable: function (enterable) {
@@ -121,9 +155,22 @@ TooltipRichContent.prototype = {
     },
 
     hide: function () {
+        this.el.hide();
+        this._show = false;
     },
 
     hideLater: function (time) {
+        if (this._show && !(this._inContent && this._enterable)) {
+            if (time) {
+                this._hideDelay = time;
+                // Set show false to avoid invoke hideLater mutiple times
+                this._show = false;
+                this._hideTimeout = setTimeout(zrUtil.bind(this.hide, this), time);
+            }
+            else {
+                this.hide();
+            }
+        }
     },
 
     isShow: function () {
diff --git a/src/component/tooltip/TooltipView.js b/src/component/tooltip/TooltipView.js
index 0427904..4ce0d30 100644
--- a/src/component/tooltip/TooltipView.js
+++ b/src/component/tooltip/TooltipView.js
@@ -50,23 +50,27 @@ export default echarts.extendComponentView({
         }
         var tooltip = ecModel.get('tooltip');
 
-        this._isRich = false;
-        if (tooltip.length && (tooltip[0].useHtml === false // force using non-html
-            || tooltip[0].useHtml === 'auto' && !document)) // auto using non-html when no `document`
-        {
-            this._isRich = true;
+        this._renderMode = 'html';
+        if (tooltip.length) {
+            if (tooltip[0].renderMode === 'auto') {
+                // using html when `document` exists, use richtext otherwise
+                this._renderMode = document ? 'html' : 'richtext';
+            }
+            else {
+                this._renderMode = tooltip[0].renderMode || this._renderMode;
+            }
         }
 
-        var tooltipContent
-        if (this._isRich) {
-            tooltipContent = new TooltipRichContent(api);
+        var tooltipContent;
+        if (this._renderMode === 'html') {
+            tooltipContent = new TooltipContent(api.getDom(), api);
+            this._newLine = '<br/>';
         }
         else {
-            tooltipContent = new TooltipContent(api.getDom(), api);
+            tooltipContent = new TooltipRichContent(api);
+            this._newLine = '\n';
         }
 
-        this._newLine = this._isRich ? '\n' : '<br/>';
-
         this._tooltipContent = tooltipContent;
     },
 
@@ -364,7 +368,7 @@ export default echarts.extendComponentView({
             globalTooltipModel
         ]);
 
-        var isRich = this._isRich;
+        var renderMode = this._renderMode;
         var newLine = this._newLine;
 
         var markers = {};
@@ -409,7 +413,7 @@ export default echarts.extendComponentView({
 
                     if (dataParams) {
                         singleParamsList.push(dataParams);
-                        var seriesTooltip = series.formatTooltip(dataIndex, true, null, isRich);
+                        var seriesTooltip = series.formatTooltip(dataIndex, true, null, renderMode);
 
                         var html;
                         if (zrUtil.isObject(seriesTooltip)) {
@@ -429,7 +433,7 @@ export default echarts.extendComponentView({
                 // (1) shold be the first data which has name?
                 // (2) themeRiver, firstDataIndex is array, and first line is unnecessary.
                 var firstLine = valueLabel;
-                if (isRich) {
+                if (renderMode !== 'html') {
                     singleDefaultHTML.push(seriesDefaultHTML.join(newLine))
                 }
                 else {
@@ -495,7 +499,7 @@ export default echarts.extendComponentView({
         }
 
         var params = dataModel.getDataParams(dataIndex, dataType);
-        var seriesTooltip = dataModel.formatTooltip(dataIndex, false, dataType, this._isRich);
+        var seriesTooltip = dataModel.formatTooltip(dataIndex, false, dataType, this._renderMode);
         var defaultHtml, markers;
         if (zrUtil.isObject(seriesTooltip)) {
             defaultHtml = seriesTooltip.html;
diff --git a/src/model/Series.js b/src/model/Series.js
index 32db075..af39fc4 100644
--- a/src/model/Series.js
+++ b/src/model/Series.js
@@ -303,13 +303,19 @@ var SeriesModel = ComponentModel.extend({
      * @param {number} dataIndex
      * @param {boolean} [multipleSeries=false]
      * @param {number} [dataType]
-     * @param {boolean} [isRich=false]
+     * @param {string} [renderMode='html'] valid values: 'html' and 'richtext'.
+     *                                     'html' is used for rendering tooltip in extra DOM form, and the result
+     *                                     string is used as DOM HTML content.
+     *                                     'richtext' is used for rendering tooltip in rich text form, for those where
+     *                                     DOM operation is not supported.
      * @return {Object} formatted tooltip with `html` and `markers`
      */
-    formatTooltip: function (dataIndex, multipleSeries, dataType, isRich) {
+    formatTooltip: function (dataIndex, multipleSeries, dataType, renderMode) {
 
         var series = this;
-        var newLine = isRich ? '\n' : '<br/>';
+        renderMode = renderMode || 'html';
+        var newLine = renderMode === 'html' ? '<br/>' : '\n';
+        var isRichText = renderMode === 'richtext';
         var markers = {};
         var markerId = 0;
 
@@ -338,9 +344,16 @@ var SeriesModel = ComponentModel.extend({
                 }
                 var dimType = dimInfo.type;
                 var markName = series.seriesIndex + 'at' + markerId;
-                var dimHead = getTooltipMarker({color: color, type: 'subItem', isRich: isRich, markerId: markName});
+                var dimHead = getTooltipMarker({
+                    color: color,
+                    type: 'subItem',
+                    renderMode: renderMode,
+                    markerId: markName
+                });
+
+                var dimHeadStr = typeof dimHead === 'string' ? dimHead : dimHead.content;
                 var valStr = (vertially
-                        ? dimHead + encodeHTML(dimInfo.displayName || '-') + ': '
+                        ? dimHeadStr + encodeHTML(dimInfo.displayName || '-') + ': '
                         : ''
                     )
                     // FIXME should not format time for raw data?
@@ -352,15 +365,16 @@ var SeriesModel = ComponentModel.extend({
                     );
                 valStr && result.push(valStr);
 
-                if (isRich) {
+                if (isRichText) {
                     markers[markName] = color;
                     ++markerId;
                 }
             }
 
             return {
-                html: (vertially ? isRich : '') + result.join(vertially ? isRich : ', '),
-                markers: markers
+                renderMode: renderMode,
+                content: (vertially ? isRichText : '') + result.join(vertially ? isRichText : ', '),
+                style: markers
             };
         }
 
@@ -388,7 +402,12 @@ var SeriesModel = ComponentModel.extend({
             : formatSingleValue(isValueArr ? value[0] : value);
 
         var markName = series.seriesIndex + 'at' + markerId;
-        var colorEl = getTooltipMarker({ color: color, type: 'item', isRich: isRich, markerId: markName });
+        var colorEl = getTooltipMarker({
+            color: color,
+            type: 'item',
+            renderMode: renderMode,
+            markerId: markName
+        });
         markers[markName] = color;
         ++markerId;
 
@@ -402,13 +421,14 @@ var SeriesModel = ComponentModel.extend({
             ? encodeHTML(seriesName) + (!multipleSeries ? newLine : ': ')
             : '';
 
+        var colorStr = typeof colorEl === 'string' ? colorEl : colorEl.content;
         var html = !multipleSeries
-            ? seriesName + colorEl
+            ? seriesName + colorStr
                 + (name
                     ? encodeHTML(name) + ': ' + formattedValue
                     : formattedValue
                 )
-            : colorEl + seriesName + formattedValue;
+            : colorStr + seriesName + formattedValue;
 
         return {
             html: html,
diff --git a/src/model/mixin/dataFormat.js b/src/model/mixin/dataFormat.js
index 5b6087c..11fd5e1 100644
--- a/src/model/mixin/dataFormat.js
+++ b/src/model/mixin/dataFormat.js
@@ -37,6 +37,8 @@ export default {
         var name = data.getName(dataIndex);
         var itemOpt = data.getRawDataItem(dataIndex);
         var color = data.getItemVisual(dataIndex, 'color');
+        var tooltip = this.ecModel.get('tooltip');
+        var renderMode = tooltip && tooltip.length ? tooltip[0].renderMode : 'auto';
 
         return {
             componentType: this.mainType,
@@ -51,7 +53,10 @@ export default {
             dataType: dataType,
             value: rawValue,
             color: color,
-            marker: getTooltipMarker(color),
+            marker: getTooltipMarker({
+                color: color,
+                renderMode: renderMode
+            }),
 
             // Param name list for mapping `a`, `b`, `c`, `d`, `e`
             $vars: ['seriesName', 'name', 'value']
diff --git a/src/util/format.js b/src/util/format.js
index 119756b..0f0581b 100644
--- a/src/util/format.js
+++ b/src/util/format.js
@@ -20,6 +20,7 @@
 import * as zrUtil from 'zrender/src/core/util';
 import * as textContain from 'zrender/src/contain/text';
 import * as numberUtil from './number';
+import Text from 'zrender/src/graphic/Text';
 
 /**
  * 每三位默认加,格式化
@@ -135,7 +136,8 @@ export function formatTplSimple(tpl, param, encode) {
  * @param {string} [opt.color]
  * @param {string} [opt.extraCssText]
  * @param {string} [opt.type='item'] 'item' or 'subItem'
- * @param {boolean} [opt.isRich=false] if renders with rich text
+ * @param {string} [opt.renderMode='html'] render mode of tooltip, 'html' or 'richtext'
+ * @param {string} [opt.markerId='X'] id name for marker. If only one marker is in a rich text, this can be omitted.
  * @return {string}
  */
 export function getTooltipMarker(opt, extraCssText) {
@@ -143,17 +145,14 @@ export function getTooltipMarker(opt, extraCssText) {
     var color = opt.color;
     var type = opt.type;
     var extraCssText = opt.extraCssText;
-    var isRich = opt.isRich == null ? false : opt.isRich;
+    var renderMode = opt.renderMode || 'html';
+    var markerId = opt.markerId || 'X';
 
     if (!color) {
         return '';
     }
 
-    if (isRich) {
-        // Space for rich element marker
-        return '{marker' + opt.markerId + '|}  ';
-    }
-    else {
+    if (renderMode === 'html') {
         return type === 'subItem'
         ? '<span style="display:inline-block;vertical-align:middle;margin-right:8px;margin-left:3px;'
             + 'border-radius:4px;width:4px;height:4px;background-color:'
@@ -162,6 +161,16 @@ export function getTooltipMarker(opt, extraCssText) {
             + 'border-radius:10px;width:10px;height:10px;background-color:'
             + encodeHTML(color) + ';' + (extraCssText || '') + '"></span>';
     }
+    else {
+        // Space for rich element marker
+        return {
+            renderMode: renderMode,
+            content: '{marker' + markerId + '|}  ',
+            style: {
+                color: color
+            }
+        };
+    }
 }
 
 function pad(str, len) {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org