docs: function (dataIndex, multipleSeries, dataType, renderMode) {
  
          var series = this;
          renderMode = renderMode || 'html';
          var newLine = renderMode === 'html' ? '<br/>' : '\n';
          var isRichText = renderMode === 'richText';
          var markers = {};
          var markerId = 0;
  
          function formatArrayValue(value) {
              // ??? TODO refactor these logic.
              // check: category-no-encode-has-axis-data in dataset.html
              var vertially = zrUtil.reduce(value, function (vertially, val, idx) {
                  var dimItem = data.getDimensionInfo(idx);
                  return vertially |= dimItem && dimItem.tooltip !== false && dimItem.displayName != null;
              }, 0);
  
              var result = [];
  
              tooltipDims.length
                  ? zrUtil.each(tooltipDims, function (dim) {
                      setEachItem(retrieveRawValue(data, dataIndex, dim), dim);
                  })
                  // By default, all dims is used on tooltip.
                  : zrUtil.each(value, setEachItem);
  
              function setEachItem(val, dim) {
                  var dimInfo = data.getDimensionInfo(dim);
                  // If `dimInfo.tooltip` is not set, show tooltip.
                  if (!dimInfo || dimInfo.otherDims.tooltip === false) {
                      return;
                  }
                  var dimType = dimInfo.type;
                  var markName = 'sub' + series.seriesIndex + 'at' + markerId;
                  var dimHead = getTooltipMarker({
                      color: color,
                      type: 'subItem',
                      renderMode: renderMode,
                      markerId: markName
                  });
  
                  var dimHeadStr = typeof dimHead === 'string' ? dimHead : dimHead.content;
                  var valStr = (vertially
                          ? dimHeadStr + encodeHTML(dimInfo.displayName || '-') + ': '
                          : ''
                      )
                      // FIXME should not format time for raw data?
                      + encodeHTML(dimType === 'ordinal'
                          ? val + ''
                          : dimType === 'time'
                          ? (multipleSeries ? '' : formatTime('yyyy/MM/dd hh:mm:ss', val))
                          : addCommas(val)
                      );
                  valStr && result.push(valStr);
  
                  if (isRichText) {
                      markers[markName] = color;
                      ++markerId;
                  }
              }
  
              var newLine = vertially ? (isRichText ? '\n' : '<br/>') : '';
              var content = newLine + result.join(newLine || ', ');
              return {
                  renderMode: renderMode,
                  content: content,
                  style: markers
              };
          }
  
          function formatSingleValue(val) {
              // return encodeHTML(addCommas(val));
              return {
                  renderMode: renderMode,
                  content: encodeHTML(addCommas(val)),
                  style: markers
              };
          }
  
          var data = this.getData();
          var tooltipDims = data.mapDimension('defaultedTooltip', true);
          var tooltipDimLen = tooltipDims.length;
          var value = this.getRawValue(dataIndex);
          var isValueArr = zrUtil.isArray(value);
  
          var color = data.getItemVisual(dataIndex, 'color');
          if (zrUtil.isObject(color) && color.colorStops) {
              color = (color.colorStops[0] || {}).color;
          }
          color = color || 'transparent';
  
          // Complicated rule for pretty tooltip.
          var formattedValue = (tooltipDimLen > 1 || (isValueArr && !tooltipDimLen))
              ? formatArrayValue(value)
              : tooltipDimLen
              ? formatSingleValue(retrieveRawValue(data, dataIndex, tooltipDims[0]))
              : formatSingleValue(isValueArr ? value[0] : value);
          var content = formattedValue.content;
  
          var markName = series.seriesIndex + 'at' + markerId;
          var colorEl = getTooltipMarker({
              color: color,
              type: 'item',
              renderMode: renderMode,
              markerId: markName
          });
          markers[markName] = color;
          ++markerId;
  
          var name = data.getName(dataIndex);
  
          var seriesName = this.name;
          if (!modelUtil.isNameSpecified(this)) {
              seriesName = '';
          }
          seriesName = seriesName
              ? encodeHTML(seriesName) + (!multipleSeries ? newLine : ': ')
              : '';
  
          var colorStr = typeof colorEl === 'string' ? colorEl : colorEl.content;
          var html = !multipleSeries
              ? seriesName + colorStr
                  + (name
                      ? encodeHTML(name) + ': ' + content
                      : content
                  )
              : colorStr + seriesName + content;
  
          return {
              html: html,
              markers: markers
          };
      }