<commit_before>const Util = require('../../util');
const { LabelsRenderer } = require('../label/index');
const { Group } = require('@ali/g');
const Grid = require('./grid');

class Base extends Group {
  getDefaultCfg() {
    return {
      /**
       * Ψһʶڶ
       * @type {[type]}
       */
      _id: null,
      zIndex: 4,
      /**
       * ϵ
       * @type {Array}
       */
      ticks: null,
      /**
       * ߵͼãónullʾ
       * @type {Object}
       */
      line: null,
      /**
       * ̶ߵʽãónullʾ
       * @type {Object}
       */
      tickLine: null,
      /**
       * ο̶߸δøԣʾ
       * @type {Number}
       */
      subTickCount: 0,
      /**
       * ο̶ʽ
       * @type {Object}
       */
      subTickLine: null,
      /**
       * դʽãΪ nullʾ
       * @type {Object}
       */
      grid: null,
      /**
       * ϵı
       * @type {Object}
       */
      label: {
        textStyle: {}, // ıʽ
        autoRotate: true,
        formatter: null//  ʽıʾ
      },
      /**
       * ʽ
       * @type {Object}
       */
      title: {
        autoRotate: true, // Զת
        textStyle: {} // ıʽ
      },
      autoPaint: true // @type {Boolean} ǷԶ
    };
  }

  _beforeRenderUI() {
    // Ĭʽ
    const title = this.get('title');
    const label = this.get('label');
    const grid = this.get('grid');
    const textStyle = {
      fontSize: 12,
      fill: '#ccc',
      textBaseline: 'middle'
    };
    if (title) {
      Util.defaultsDeep(title, {
        autoRotate: true,
        textStyle,
        offset: 40
      });
      this.setSilent('title', title);
    }
    if (label) {
      Util.defaultsDeep(label, {
        autoRotate: true,
        textStyle,
        offset: 10
      });
      this.setSilent('label', label);
    }
    if (grid) {
      Util.defaultsDeep(grid, {
        lineStyle: {
          lineWidth: 1,
          stroke: '#C0D0E0'
        }
      });
      this.setSilent('grid', grid);
    }
  }

  _renderUI() {
    const labelCfg = this.get('label');
    if (labelCfg) {
      this.renderLabels();
    }
    if (this.get('autoPaint')) {
      this.paint();
    }
    if (!Util.isNil(this.get('title'))) {
      this.renderTitle();
    }
    this.sort();
  }

  _parseTicks(ticks) {
    ticks = ticks || [];
    const ticksLength = ticks.length;
    for (let i = 0; i < ticksLength; i++) {
      const item = ticks[i];
      if (!Util.isObject(item)) {
        ticks[i] = this.parseTick(item, i, ticksLength);
      }
    }
    this.set('ticks', ticks);
    return ticks;
  }

  _addTickItem(index, point, length, type = '') {
    let tickItems = this.get('tickItems');
    let subTickItems = this.get('subTickItems');
    const end = this.getTickEnd(point, length, index);

    const cfg = {
      x1: point.x,
      y1: point.y,
      x2: end.x,
      y2: end.y
    };

    if (!tickItems) {
      tickItems = [];
    }

    if (!subTickItems) {
      subTickItems = [];
    }

    if (type === 'sub') {
      subTickItems.push(cfg);
    } else {
      tickItems.push(cfg);
    }

    this.set('tickItems', tickItems);
    this.set('subTickItems', subTickItems);
  }

  _renderLine() {
    let lineCfg = this.get('line');
    let path;
    if (lineCfg) {
      path = this.getLinePath();
      lineCfg = Util.mix({
        path
      }, lineCfg);
      const lineShape = this.addShape('path', {
        attrs: lineCfg
      });
      lineShape.name = 'axis-line';
      this.set('lineShape', lineShape);
    }
  }

  _processTicks() {
    const self = this;
    const labelCfg = self.get('label');
    const subTickCount = self.get('subTickCount');
    const tickLineCfg = self.get('tickLine');
    let ticks = self.get('ticks');
    ticks = self._parseTicks(ticks);

    Util.each(ticks, function(tick, index) {
      const tickPoint = self.getTickPoint(tick.value, index);
      if (tickLineCfg) {
        self._addTickItem(index, tickPoint, tickLineCfg.length);
      }
      if (labelCfg) {
        self.addLabel(tick, tickPoint, index);
      }
    });

    if (subTickCount) { // ôμֵ㣬Ӵμtick
      const subTickLineCfg = self.get('subTickLine');
      Util.each(ticks, function(tick, index) {
        if (index > 0) {
          let diff = tick.value - ticks[index - 1].value;
          diff = diff / (self.get('subTickCount') + 1);

          for (let i = 1; i <= subTickCount; i++) {
            const subTick = {
              text: '',
              value: index ? ticks[index - 1].value + i * diff : i * diff
            };

            const tickPoint = self.getTickPoint(subTick.value);
            let subTickLength;
            if (subTickLineCfg && subTickLineCfg.length) {
              subTickLength = subTickLineCfg.length;
            } else {
              subTickLength = parseInt(tickLineCfg.length * (3 / 5), 10);
            }
            self._addTickItem(i - 1, tickPoint, subTickLength, 'sub');
          }
        }
      });
    }
  }

  _addTickLine(ticks, lineCfg) {
    const self = this;
    const cfg = Util.mix({}, lineCfg);
    const path = [];
    Util.each(ticks, function(item) {
      path.push([ 'M', item.x1, item.y1 ]);
      path.push([ 'L', item.x2, item.y2 ]);
    });
    delete cfg.length;
    cfg.path = path;
    const tickShape = self.addShape('path', {
      attrs: cfg
    });
    tickShape.name = 'axis-ticks';
    tickShape._id = this.get('_id') + '-ticks'; // ÿ label  _id Ψһʶ
    tickShape.set('coord', this.get('coord'));
  }

  _renderTicks() {
    const self = this;
    const tickItems = self.get('tickItems');
    const subTickItems = self.get('subTickItems');

    if (!Util.isEmpty(tickItems)) {
      const tickLineCfg = self.get('tickLine');
      self._addTickLine(tickItems, tickLineCfg);
    }

    if (!Util.isEmpty(subTickItems)) {
      const subTickLineCfg = self.get('subTickLine') || self.get('tickLine');
      self._addTickLine(subTickItems, subTickLineCfg);
    }
  }

  _renderGrid() {
    const grid = this.get('grid');
    if (!grid) {
      return;
    }
    grid.coord = this.get('coord');
    this.set('gridGroup', this.addGroup(Grid, grid));
  }

  paint() {
    this._renderLine();
    this._processTicks();
    this._renderTicks();
    this._renderGrid();
    const labelCfg = this.get('label');
    if (labelCfg && labelCfg.autoRotate) {
      this.autoRotateLabels();
    }
  }

  parseTick(tick, index, length) {
    return {
      text: tick,
      value: index / (length - 1)
    };
  }

  getTextAnchor(vector) {
    const ratio = Math.abs(vector[1] / vector[0]);
    let align;
    if (ratio >= 1) { // 
      align = 'center';
    } else {
      if (vector[0] > 0) { // Ҳ
        align = 'start';
      } else { // 
        align = 'end';
      }
    }
    return align;
  }

  getMaxLabelWidth(labelsGroup) {
    const labels = labelsGroup.get('children');
    let max = 0;
    Util.each(labels, function(label) {
      const bbox = label.getBBox();
      const width = bbox.width;
      if (max < width) {
        max = width;
      }
    });
    return max;
  }

  remove() {
    super.remove();
    const gridGroup = this.get('gridGroup');
    gridGroup && gridGroup.remove();
    this.removeLabels();
  }

  /**
   * תı
   * @abstract
   * @return {[type]} [description]
   */
  autoRotateLabels() {}

  /**
   * Ⱦ
   * @abstract
   * @return {[type]} [description]
   */
  renderTitle() {}

  /**
   * ȡߵ path
   * @abstract
   * @return {[type]} [description]
   */
  getLinePath() {}

  /**
   * ȡtickڻϵλ
   * @abstract
   * @return {[type]} [description]
   */
  getTickPoint() {}

  /**
   * ȡʾߵյ
   * @abstract
   * @return {[type]} [description]
   */
  getTickEnd() {}

  /**
   * ȡ
   * @abstract
   * @return {[type]} [description]
   */
  getSideVector() {}
}

Util.assign(Base.prototype, LabelsRenderer, {
  addLabel(tick, point, index) {
    const labelsGroup = this.get('labelsGroup');
    const label = {};
    let rst;

    if (labelsGroup) {
      const offset = this.get('label').offset || this.get('_labelOffset');
      const vector = this.getSideVector(offset, point, index);
      point = {
        x: point.x + vector[0],
        y: point.y + vector[1]
      };

      label.text = tick.text;
      label.x = point.x;
      label.y = point.y;
      label.textAlign = this.getTextAnchor(vector);
      rst = labelsGroup.addLabel(label);
      rst.name = 'axis-label';
      rst._id = this.get('_id') + '-' + tick.tickValue; // ÿ label  _id Ψһʶ
      rst.set('coord', this.get('coord'));<commit_msg>fix: label 如果是自定义 html, addShape 不会返回 labelShape.<commit_after>const Util = require('../../util');
const { LabelsRenderer } = require('../label/index');
const { Group } = require('@ali/g');
const Grid = require('./grid');

class Base extends Group {
  getDefaultCfg() {
    return {
      /**
       * Ψһʶڶ
       * @type {[type]}
       */
      _id: null,
      zIndex: 4,
      /**
       * ϵ
       * @type {Array}
       */
      ticks: null,
      /**
       * ߵͼãónullʾ
       * @type {Object}
       */
      line: null,
      /**
       * ̶ߵʽãónullʾ
       * @type {Object}
       */
      tickLine: null,
      /**
       * ο̶߸δøԣʾ
       * @type {Number}
       */
      subTickCount: 0,
      /**
       * ο̶ʽ
       * @type {Object}
       */
      subTickLine: null,
      /**
       * դʽãΪ nullʾ
       * @type {Object}
       */
      grid: null,
      /**
       * ϵı
       * @type {Object}
       */
      label: {
        textStyle: {}, // ıʽ
        autoRotate: true,
        formatter: null//  ʽıʾ
      },
      /**
       * ʽ
       * @type {Object}
       */
      title: {
        autoRotate: true, // Զת
        textStyle: {} // ıʽ
      },
      autoPaint: true // @type {Boolean} ǷԶ
    };
  }

  _beforeRenderUI() {
    // Ĭʽ
    const title = this.get('title');
    const label = this.get('label');
    const grid = this.get('grid');
    const textStyle = {
      fontSize: 12,
      fill: '#ccc',
      textBaseline: 'middle'
    };
    if (title) {
      Util.defaultsDeep(title, {
        autoRotate: true,
        textStyle,
        offset: 40
      });
      this.setSilent('title', title);
    }
    if (label) {
      Util.defaultsDeep(label, {
        autoRotate: true,
        textStyle,
        offset: 10
      });
      this.setSilent('label', label);
    }
    if (grid) {
      Util.defaultsDeep(grid, {
        lineStyle: {
          lineWidth: 1,
          stroke: '#C0D0E0'
        }
      });
      this.setSilent('grid', grid);
    }
  }

  _renderUI() {
    const labelCfg = this.get('label');
    if (labelCfg) {
      this.renderLabels();
    }
    if (this.get('autoPaint')) {
      this.paint();
    }
    if (!Util.isNil(this.get('title'))) {
      this.renderTitle();
    }
    this.sort();
  }

  _parseTicks(ticks) {
    ticks = ticks || [];
    const ticksLength = ticks.length;
    for (let i = 0; i < ticksLength; i++) {
      const item = ticks[i];
      if (!Util.isObject(item)) {
        ticks[i] = this.parseTick(item, i, ticksLength);
      }
    }
    this.set('ticks', ticks);
    return ticks;
  }

  _addTickItem(index, point, length, type = '') {
    let tickItems = this.get('tickItems');
    let subTickItems = this.get('subTickItems');
    const end = this.getTickEnd(point, length, index);

    const cfg = {
      x1: point.x,
      y1: point.y,
      x2: end.x,
      y2: end.y
    };

    if (!tickItems) {
      tickItems = [];
    }

    if (!subTickItems) {
      subTickItems = [];
    }

    if (type === 'sub') {
      subTickItems.push(cfg);
    } else {
      tickItems.push(cfg);
    }

    this.set('tickItems', tickItems);
    this.set('subTickItems', subTickItems);
  }

  _renderLine() {
    let lineCfg = this.get('line');
    let path;
    if (lineCfg) {
      path = this.getLinePath();
      lineCfg = Util.mix({
        path
      }, lineCfg);
      const lineShape = this.addShape('path', {
        attrs: lineCfg
      });
      lineShape.name = 'axis-line';
      this.set('lineShape', lineShape);
    }
  }

  _processTicks() {
    const self = this;
    const labelCfg = self.get('label');
    const subTickCount = self.get('subTickCount');
    const tickLineCfg = self.get('tickLine');
    let ticks = self.get('ticks');
    ticks = self._parseTicks(ticks);

    Util.each(ticks, function(tick, index) {
      const tickPoint = self.getTickPoint(tick.value, index);
      if (tickLineCfg) {
        self._addTickItem(index, tickPoint, tickLineCfg.length);
      }
      if (labelCfg) {
        self.addLabel(tick, tickPoint, index);
      }
    });

    if (subTickCount) { // ôμֵ㣬Ӵμtick
      const subTickLineCfg = self.get('subTickLine');
      Util.each(ticks, function(tick, index) {
        if (index > 0) {
          let diff = tick.value - ticks[index - 1].value;
          diff = diff / (self.get('subTickCount') + 1);

          for (let i = 1; i <= subTickCount; i++) {
            const subTick = {
              text: '',
              value: index ? ticks[index - 1].value + i * diff : i * diff
            };

            const tickPoint = self.getTickPoint(subTick.value);
            let subTickLength;
            if (subTickLineCfg && subTickLineCfg.length) {
              subTickLength = subTickLineCfg.length;
            } else {
              subTickLength = parseInt(tickLineCfg.length * (3 / 5), 10);
            }
            self._addTickItem(i - 1, tickPoint, subTickLength, 'sub');
          }
        }
      });
    }
  }

  _addTickLine(ticks, lineCfg) {
    const self = this;
    const cfg = Util.mix({}, lineCfg);
    const path = [];
    Util.each(ticks, function(item) {
      path.push([ 'M', item.x1, item.y1 ]);
      path.push([ 'L', item.x2, item.y2 ]);
    });
    delete cfg.length;
    cfg.path = path;
    const tickShape = self.addShape('path', {
      attrs: cfg
    });
    tickShape.name = 'axis-ticks';
    tickShape._id = this.get('_id') + '-ticks'; // ÿ label  _id Ψһʶ
    tickShape.set('coord', this.get('coord'));
  }

  _renderTicks() {
    const self = this;
    const tickItems = self.get('tickItems');
    const subTickItems = self.get('subTickItems');

    if (!Util.isEmpty(tickItems)) {
      const tickLineCfg = self.get('tickLine');
      self._addTickLine(tickItems, tickLineCfg);
    }

    if (!Util.isEmpty(subTickItems)) {
      const subTickLineCfg = self.get('subTickLine') || self.get('tickLine');
      self._addTickLine(subTickItems, subTickLineCfg);
    }
  }

  _renderGrid() {
    const grid = this.get('grid');
    if (!grid) {
      return;
    }
    grid.coord = this.get('coord');
    this.set('gridGroup', this.addGroup(Grid, grid));
  }

  paint() {
    this._renderLine();
    this._processTicks();
    this._renderTicks();
    this._renderGrid();
    const labelCfg = this.get('label');
    if (labelCfg && labelCfg.autoRotate) {
      this.autoRotateLabels();
    }
  }

  parseTick(tick, index, length) {
    return {
      text: tick,
      value: index / (length - 1)
    };
  }

  getTextAnchor(vector) {
    const ratio = Math.abs(vector[1] / vector[0]);
    let align;
    if (ratio >= 1) { // 
      align = 'center';
    } else {
      if (vector[0] > 0) { // Ҳ
        align = 'start';
      } else { // 
        align = 'end';
      }
    }
    return align;
  }

  getMaxLabelWidth(labelsGroup) {
    const labels = labelsGroup.get('children');
    let max = 0;
    Util.each(labels, function(label) {
      const bbox = label.getBBox();
      const width = bbox.width;
      if (max < width) {
        max = width;
      }
    });
    return max;
  }

  remove() {
    super.remove();
    const gridGroup = this.get('gridGroup');
    gridGroup && gridGroup.remove();
    this.removeLabels();
  }

  /**
   * תı
   * @abstract
   * @return {[type]} [description]
   */
  autoRotateLabels() {}

  /**
   * Ⱦ
   * @abstract
   * @return {[type]} [description]
   */
  renderTitle() {}

  /**
   * ȡߵ path
   * @abstract
   * @return {[type]} [description]
   */
  getLinePath() {}

  /**
   * ȡtickڻϵλ
   * @abstract
   * @return {[type]} [description]
   */
  getTickPoint() {}

  /**
   * ȡʾߵյ
   * @abstract
   * @return {[type]} [description]
   */
  getTickEnd() {}

  /**
   * ȡ
   * @abstract
   * @return {[type]} [description]
   */
  getSideVector() {}
}

Util.assign(Base.prototype, LabelsRenderer, {
  addLabel(tick, point, index) {
    const labelsGroup = this.get('labelsGroup');
    const label = {};
    let rst;

    if (labelsGroup) {
      const offset = this.get('label').offset || this.get('_labelOffset');
      const vector = this.getSideVector(offset, point, index);
      point = {
        x: point.x + vector[0],
        y: point.y + vector[1]
      };

      label.text = tick.text;
      label.x = point.x;
      label.y = point.y;
      label.textAlign = this.getTextAnchor(vector);
      rst = labelsGroup.addLabel(label);
      if (rst) {
        rst.name = 'axis-label';
        rst._id = this.get('_id') + '-' + tick.tickValue; // ÿ label  _id Ψһʶ
        rst.set('coord', this.get('coord'));
      }
{'fraction_non_alphanumeric': 0.16171539502323667, 'fraction_numerical': 0.004706159185834461, 'mean_word_length': 1.898056597340607, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2982018', 'n_tokens_mistral': 5988, 'n_tokens_neox': 5858, 'n_words': 1149}