/**
 * echarts图表类：力导向图
 *
 * @author pissang (https://github.com/pissang/)
 *
 */
module.exports = function (require) {
  'use strict';

  var ChartBase = require('./base');

  var Graph = require('../data/Graph');

  var ForceLayout = require('../layout/Force'); // 图形依赖


  var LineShape = require('zrender/shape/Line');

  var BezierCurveShape = require('zrender/shape/BezierCurve');

  var ImageShape = require('zrender/shape/Image');

  var IconShape = require('../util/shape/Icon');

  var ecConfig = require('../config'); // 力导向布局图默认参数


  ecConfig.force = {
    zlevel: 1,
    // 一级层叠
    z: 2,
    // 二级层叠
    // 布局中心
    center: ['50%', '50%'],
    // 布局大小
    size: '100%',
    // 防止节点和节点，节点和边之间的重叠
    preventOverlap: false,
    // 布局冷却因子，值越小结束时间越短，值越大时间越长但是结果也越收敛
    coolDown: 0.99,
    // 数据映射到圆的半径的最小值和最大值
    minRadius: 10,
    maxRadius: 20,
    // 是否根据屏幕比例拉伸
    ratioScaling: false,
    // 在 500+ 顶点的图上建议设置 large 为 true, 会使用 Barnes-Hut simulation
    // 同时开启 useWorker 并且把 steps 值调大
    // 关于Barnes-Hut simulation: http://en.wikipedia.org/wiki/Barnes–Hut_simulation
    large: false,
    // 是否在浏览器支持 worker 的时候使用 web worker
    useWorker: false,
    // 每一帧 force 迭代的次数，仅在启用webworker的情况下有用
    steps: 1,
    // 布局缩放因子，并不完全精确, 效果跟布局大小类似
    scaling: 1.0,
    // 向心力因子，越大向心力越大（ 所有顶点会往 center 的位置收拢 )
    gravity: 1,
    symbol: 'circle',
    // symbolSize 为 0 的话使用映射到minRadius-maxRadius后的值
    symbolSize: 0,
    linkSymbol: null,
    linkSymbolSize: [10, 15],
    draggable: true,
    clickable: true,
    roam: false,
    // 分类里如果有样式会覆盖节点默认样式
    // categories: [{
    // itemStyle
    // symbol
    // symbolSize
    // name
    // }],
    itemStyle: {
      normal: {
        // color: 各异,
        label: {
          show: false,
          position: 'inside' // textStyle: null      // 默认使用全局文本样式，详见TEXTSTYLE

        },
        nodeStyle: {
          brushType: 'both',
          borderColor: '#5182ab',
          borderWidth: 1
        },
        linkStyle: {
          color: '#5182ab',
          width: 1,
          type: 'line'
        }
      },
      emphasis: {
        // color: 各异,
        label: {
          show: false // textStyle: null      // 默认使用全局文本样式，详见TEXTSTYLE

        },
        nodeStyle: {},
        linkStyle: {
          opacity: 0
        }
      }
    } // nodes: [{
    //     name: 'xxx',
    //     value: 1,
    //     itemStyle: {},
    //     initial: [0, 0],
    //     fixX: false,
    //     fixY: false,
    //     ignore: false,
    //     symbol: 'circle',
    //     symbolSize: 0
    // }]
    // links: [{
    //      source: 1,
    //      target: 2,
    //      weight: 1,
    //      itemStyle: {}
    // }, {
    //      source: 'xxx',
    //      target: 'ooo'
    // }]

  };

  var ecData = require('../util/ecData');

  var zrUtil = require('zrender/tool/util');

  var zrConfig = require('zrender/config');

  var vec2 = require('zrender/tool/vector');
  /**
   * 构造函数
   * @param {Object} messageCenter echart消息中心
   * @param {ZRender} zr zrender实例
   * @param {Object} series 数据
   * @param {Object} component 组件
   */


  function Force(ecTheme, messageCenter, zr, option, myChart) {
    var self = this; // 图表基类

    ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart); // 保存节点的位置，改变数据时能够有更好的动画效果

    this.__nodePositionMap = {};
    this._graph = new Graph(true);
    this._layout = new ForceLayout();

    this._layout.onupdate = function () {
      self._step();
    };

    this._steps = 1; // 关闭可拖拽属性

    this.ondragstart = function () {
      ondragstart.apply(self, arguments);
    };

    this.ondragend = function () {
      ondragend.apply(self, arguments);
    };

    this.ondrop = function () {};

    this.shapeHandler.ondragstart = function () {
      self.isDragstart = true;
    };

    this.onmousemove = function () {
      onmousemove.apply(self, arguments);
    };

    this.refresh(option);
  }
  /**
   * 绘制图形
   */


  Force.prototype = {
    constructor: Force,
    type: ecConfig.CHART_TYPE_FORCE,
    _init: function () {
      this.selectedMap = {};
      var legend = this.component.legend;
      var series = this.series;
      var serieName;
      this.clear();

      for (var i = 0, l = series.length; i < l; i++) {
        var serie = series[i];

        if (serie.type === ecConfig.CHART_TYPE_FORCE) {
          series[i] = this.reformOption(series[i]);
          serieName = series[i].name || ''; // 系列图例开关

          this.selectedMap[serieName] = legend ? legend.isSelected(serieName) : true;

          if (!this.selectedMap[serieName]) {
            continue;
          }

          this.buildMark(i); // TODO 多个 force 

          this._initSerie(serie, i);

          break;
        }
      }

      this.animationEffect();
    },
    _getNodeCategory: function (serie, node) {
      return serie.categories && serie.categories[node.category || 0];
    },
    _getNodeQueryTarget: function (serie, node, type) {
      type = type || 'normal';
      var category = this._getNodeCategory(serie, node) || {};
      return [// Node
      node.itemStyle && node.itemStyle[type], // Category
      category && category.itemStyle && category.itemStyle[type], // Serie
      serie.itemStyle[type].nodeStyle];
    },
    _getEdgeQueryTarget: function (serie, edge, type) {
      type = type || 'normal';
      return [edge.itemStyle && edge.itemStyle[type], serie.itemStyle[type].linkStyle];
    },
    _initSerie: function (serie, serieIdx) {
      this._temperature = 1; // matrix 表示边

      if (serie.matrix) {
        this._graph = this._getSerieGraphFromDataMatrix(serie);
      } // links 表示边
      else if (serie.links) {
        this._graph = this._getSerieGraphFromNodeLinks(serie);
      }

      this._buildLinkShapes(serie, serieIdx);

      this._buildNodeShapes(serie, serieIdx);

      var panable = serie.roam === true || serie.roam === 'move';
      var zoomable = serie.roam === true || serie.roam === 'scale'; // Enable pan and zooom

      this.zr.modLayer(this.getZlevelBase(), {
        panable: panable,
        zoomable: zoomable
      });

      if (this.query('markPoint.effect.show') || this.query('markLine.effect.show')) {
        this.zr.modLayer(ecConfig.EFFECT_ZLEVEL, {
          panable: panable,
          zoomable: zoomable
        });
      }

      this._initLayout(serie);

      this._step();
    },
    _getSerieGraphFromDataMatrix: function (serie) {
      var nodesData = [];
      var count = 0;
      var matrix = []; // 复制一份新的matrix

      for (var i = 0; i < serie.matrix.length; i++) {
        matrix[i] = serie.matrix[i].slice();
      }

      var data = serie.data || serie.nodes;

      for (var i = 0; i < data.length; i++) {
        var node = {};
        var group = data[i];

        for (var key in group) {
          // name改为id
          if (key === 'name') {
            node['id'] = group['name'];
          } else {
            node[key] = group[key];
          }
        } // legends 选择优先级 category -> group


        var category = this._getNodeCategory(serie, group);

        var name = category ? category.name : group.name;
        this.selectedMap[name] = this.isSelected(name);

        if (this.selectedMap[name]) {
          nodesData.push(node);
          count++;
        } else {
          // 过滤legend未选中的数据
          matrix.splice(count, 1);

          for (var j = 0; j < matrix.length; j++) {
            matrix[j].splice(count, 1);
          }
        }
      }

      var graph = Graph.fromMatrix(nodesData, matrix, true); // Prepare layout parameters

      graph.eachNode(function (n, idx) {
        n.layout = {
          size: n.data.value,
          mass: 0
        };
        n.rawIndex = idx;
      });
      graph.eachEdge(function (e) {
        e.layout = {
          weight: e.data.weight
        };
      });
      return graph;
    },
    _getSerieGraphFromNodeLinks: function (serie) {
      var graph = new Graph(true);
      var nodes = serie.data || serie.nodes;

      for (var i = 0, len = nodes.length; i < len; i++) {
        var n = nodes[i];

        if (!n || n.ignore) {
          continue;
        } // legends 选择优先级 category -> group


        var category = this._getNodeCategory(serie, n);

        var name = category ? category.name : n.name;
        this.selectedMap[name] = this.isSelected(name);

        if (this.selectedMap[name]) {
          var node = graph.addNode(n.name, n);
          node.rawIndex = i;
        }
      }

      for (var i = 0, len = serie.links.length; i < len; i++) {
        var e = serie.links[i];
        var n1 = e.source;
        var n2 = e.target;

        if (typeof n1 === 'number') {
          n1 = nodes[n1];

          if (n1) {
            n1 = n1.name;
          }
        }

        if (typeof n2 === 'number') {
          n2 = nodes[n2];

          if (n2) {
            n2 = n2.name;
          }
        }

        var edge = graph.addEdge(n1, n2, e);

        if (edge) {
          edge.rawIndex = i;
        }
      }

      graph.eachNode(function (n) {
        var value = n.data.value;

        if (value == null) {
          // value 是 null 或者 undefined
          value = 0; // 默认使用所有边值的和作为节点的大小, 不修改 data 里的数值

          for (var i = 0; i < n.edges.length; i++) {
            value += n.edges[i].data.weight || 0;
          }
        }

        n.layout = {
          size: value,
          mass: 0
        };
      });
      graph.eachEdge(function (e) {
        e.layout = {
          // 默认 weight 为1
          weight: e.data.weight == null ? 1 : e.data.weight
        };
      });
      return graph;
    },
    _initLayout: function (serie) {
      var graph = this._graph;
      var len = graph.nodes.length;
      var minRadius = this.query(serie, 'minRadius');
      var maxRadius = this.query(serie, 'maxRadius');
      this._steps = serie.steps || 1;
      var layout = this._layout;
      layout.center = this.parseCenter(this.zr, serie.center);
      layout.width = this.parsePercent(serie.size, this.zr.getWidth());
      layout.height = this.parsePercent(serie.size, this.zr.getHeight());
      layout.large = serie.large;
      layout.scaling = serie.scaling;
      layout.ratioScaling = serie.ratioScaling;
      layout.gravity = serie.gravity;
      layout.temperature = 1;
      layout.coolDown = serie.coolDown;
      layout.preventNodeEdgeOverlap = serie.preventOverlap;
      layout.preventNodeOverlap = serie.preventOverlap; // 将值映射到minRadius-maxRadius的范围上

      var min = Infinity;
      var max = -Infinity;

      for (var i = 0; i < len; i++) {
        var gNode = graph.nodes[i];
        max = Math.max(gNode.layout.size, max);
        min = Math.min(gNode.layout.size, min);
      }

      var divider = max - min;

      for (var i = 0; i < len; i++) {
        var gNode = graph.nodes[i];

        if (divider > 0) {
          gNode.layout.size = (gNode.layout.size - min) * (maxRadius - minRadius) / divider + minRadius; // 节点质量是归一的

          gNode.layout.mass = gNode.layout.size / maxRadius;
        } else {
          gNode.layout.size = (maxRadius - minRadius) / 2;
          gNode.layout.mass = 0.5;
        }
      }

      for (var i = 0; i < len; i++) {
        // var initPos;
        var gNode = graph.nodes[i];

        if (typeof this.__nodePositionMap[gNode.id] !== 'undefined') {
          gNode.layout.position = vec2.create();
          vec2.copy(gNode.layout.position, this.__nodePositionMap[gNode.id]);
        } else if (typeof gNode.data.initial !== 'undefined') {
          gNode.layout.position = vec2.create();
          vec2.copy(gNode.layout.position, gNode.data.initial);
        } else {
          var center = this._layout.center;
          var size = Math.min(this._layout.width, this._layout.height);
          gNode.layout.position = _randomInSquare(center[0], center[1], size * 0.8);
        }

        var style = gNode.shape.style;
        var radius = gNode.layout.size;
        style.width = style.width || radius * 2;
        style.height = style.height || radius * 2;
        style.x = -style.width / 2;
        style.y = -style.height / 2;
        vec2.copy(gNode.shape.position, gNode.layout.position);
      } // 边


      len = graph.edges.length;
      max = -Infinity;

      for (var i = 0; i < len; i++) {
        var e = graph.edges[i];

        if (e.layout.weight > max) {
          max = e.layout.weight;
        }
      } // 权重归一


      for (var i = 0; i < len; i++) {
        var e = graph.edges[i];
        e.layout.weight /= max;
      }

      this._layout.init(graph, serie.useWorker);
    },
    _buildNodeShapes: function (serie, serieIdx) {
      var graph = this._graph;
      var categories = this.query(serie, 'categories');
      graph.eachNode(function (node) {
        var category = this._getNodeCategory(serie, node.data);

        var queryTarget = [node.data, category, serie];

        var styleQueryTarget = this._getNodeQueryTarget(serie, node.data);

        var emphasisStyleQueryTarget = this._getNodeQueryTarget(serie, node.data, 'emphasis');

        var shape = new IconShape({
          style: {
            x: 0,
            y: 0,
            color: this.deepQuery(styleQueryTarget, 'color'),
            brushType: 'both',
            // 兼容原有写法
            strokeColor: this.deepQuery(styleQueryTarget, 'strokeColor') || this.deepQuery(styleQueryTarget, 'borderColor'),
            lineWidth: this.deepQuery(styleQueryTarget, 'lineWidth') || this.deepQuery(styleQueryTarget, 'borderWidth')
          },
          highlightStyle: {
            color: this.deepQuery(emphasisStyleQueryTarget, 'color'),
            // 兼容原有写法
            strokeColor: this.deepQuery(emphasisStyleQueryTarget, 'strokeColor') || this.deepQuery(emphasisStyleQueryTarget, 'borderColor'),
            lineWidth: this.deepQuery(emphasisStyleQueryTarget, 'lineWidth') || this.deepQuery(emphasisStyleQueryTarget, 'borderWidth')
          },
          clickable: serie.clickable,
          zlevel: this.getZlevelBase(),
          z: this.getZBase()
        });

        if (!shape.style.color) {
          shape.style.color = category ? this.getColor(category.name) : this.getColor(node.id);
        }

        shape.style.iconType = this.deepQuery(queryTarget, 'symbol');
        var symbolSize = this.deepQuery(queryTarget, 'symbolSize') || 0;

        if (typeof symbolSize === 'number') {
          symbolSize = [symbolSize, symbolSize];
        } // 强制设定节点大小，否则默认映射到 minRadius 到 maxRadius 后的值


        shape.style.width = symbolSize[0] * 2;
        shape.style.height = symbolSize[1] * 2;

        if (shape.style.iconType.match('image')) {
          shape.style.image = shape.style.iconType.replace(new RegExp('^image:\\/\\/'), '');
          shape = new ImageShape({
            style: shape.style,
            highlightStyle: shape.highlightStyle,
            clickable: shape.clickable,
            zlevel: this.getZlevelBase(),
            z: this.getZBase()
          });
        } // 节点标签样式


        if (this.deepQuery(queryTarget, 'itemStyle.normal.label.show')) {
          shape.style.text = node.data.label == null ? node.id : node.data.label;
          shape.style.textPosition = this.deepQuery(queryTarget, 'itemStyle.normal.label.position');
          shape.style.textColor = this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle.color');
          shape.style.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle') || {});
        }

        if (this.deepQuery(queryTarget, 'itemStyle.emphasis.label.show')) {
          shape.highlightStyle.textPosition = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.position');
          shape.highlightStyle.textColor = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle.color');
          shape.highlightStyle.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle') || {});
        } // 拖拽特性


        if (this.deepQuery(queryTarget, 'draggable')) {
          this.setCalculable(shape);
          shape.dragEnableTime = 0;
          shape.draggable = true;
          shape.ondragstart = this.shapeHandler.ondragstart;
          shape.ondragover = null;
        }

        var categoryName = '';

        if (typeof node.category !== 'undefined') {
          var category = categories[node.category];
          categoryName = category && category.name || '';
        } // !!Pack data before addShape


        ecData.pack(shape, serie, serieIdx, // data
        node.data, // data index
        node.rawIndex, // name
        node.data.name || '', // category
        // special
        node.category);
        this.shapeList.push(shape);
        this.zr.addShape(shape);
        node.shape = shape;
      }, this);
    },
    _buildLinkShapes: function (serie, serieIdx) {
      var graph = this._graph;
      var len = graph.edges.length;

      for (var i = 0; i < len; i++) {
        var gEdge = graph.edges[i];
        var link = gEdge.data;
        var source = gEdge.node1;
        var target = gEdge.node2;
        var otherEdge = graph.getEdge(target, source);

        var queryTarget = this._getEdgeQueryTarget(serie, link);

        var linkType = this.deepQuery(queryTarget, 'type'); // TODO 暂时只有线段支持箭头

        if (serie.linkSymbol && serie.linkSymbol !== 'none') {
          linkType = 'line';
        }

        var LinkShapeCtor = linkType === 'line' ? LineShape : BezierCurveShape;
        var linkShape = new LinkShapeCtor({
          style: {
            xStart: 0,
            yStart: 0,
            xEnd: 0,
            yEnd: 0
          },
          clickable: this.query(serie, 'clickable'),
          highlightStyle: {},
          zlevel: this.getZlevelBase(),
          z: this.getZBase()
        });

        if (otherEdge && otherEdge.shape) {
          // 偏移一定位置放置双向边重叠
          linkShape.style.offset = 4;
          otherEdge.shape.style.offset = 4;
        }

        zrUtil.merge(linkShape.style, this.query(serie, 'itemStyle.normal.linkStyle'), true);
        zrUtil.merge(linkShape.highlightStyle, this.query(serie, 'itemStyle.emphasis.linkStyle'), true);

        if (typeof link.itemStyle !== 'undefined') {
          if (link.itemStyle.normal) {
            zrUtil.merge(linkShape.style, link.itemStyle.normal, true);
          }

          if (link.itemStyle.emphasis) {
            zrUtil.merge(linkShape.highlightStyle, link.itemStyle.emphasis, true);
          }
        } // 兼容原有写法


        linkShape.style.lineWidth = linkShape.style.lineWidth || linkShape.style.width;
        linkShape.style.strokeColor = linkShape.style.strokeColor || linkShape.style.color;
        linkShape.highlightStyle.lineWidth = linkShape.highlightStyle.lineWidth || linkShape.highlightStyle.width;
        linkShape.highlightStyle.strokeColor = linkShape.highlightStyle.strokeColor || linkShape.highlightStyle.color;
        ecData.pack(linkShape, // serie
        serie, // serie index
        serieIdx, // link data
        gEdge.data, // link data index
        gEdge.rawIndex == null ? i : gEdge.rawIndex, // source name - target name
        gEdge.data.name || source.id + ' - ' + target.id, // link source id
        // special
        source.id, // link target id
        // special2
        target.id);
        this.shapeList.push(linkShape);
        this.zr.addShape(linkShape);
        gEdge.shape = linkShape; // Arrow shape

        if (serie.linkSymbol && serie.linkSymbol !== 'none') {
          var symbolShape = new IconShape({
            style: {
              x: -5,
              y: 0,
              width: serie.linkSymbolSize[0],
              height: serie.linkSymbolSize[1],
              iconType: serie.linkSymbol,
              brushType: 'fill',
              // Use same style with link shape
              color: linkShape.style.strokeColor
            },
            highlightStyle: {
              brushType: 'fill'
            },
            position: [0, 0],
            rotation: 0,
            zlevel: this.getZlevelBase(),
            z: this.getZBase()
          });
          linkShape._symbolShape = symbolShape;
          this.shapeList.push(symbolShape);
          this.zr.addShape(symbolShape);
        }
      }
    },
    _updateLinkShapes: function () {
      var v = vec2.create();
      var n = vec2.create();
      var p1 = vec2.create();
      var p2 = vec2.create();
      var edges = this._graph.edges;

      for (var i = 0, len = edges.length; i < len; i++) {
        var edge = edges[i];
        var sourceShape = edge.node1.shape;
        var targetShape = edge.node2.shape;
        vec2.copy(p1, sourceShape.position);
        vec2.copy(p2, targetShape.position);
        var edgeShapeStyle = edge.shape.style;
        vec2.sub(v, p1, p2);
        vec2.normalize(v, v);

        if (edgeShapeStyle.offset) {
          n[0] = v[1];
          n[1] = -v[0];
          vec2.scaleAndAdd(p1, p1, n, edgeShapeStyle.offset);
          vec2.scaleAndAdd(p2, p2, n, edgeShapeStyle.offset);
        } else if (edge.shape.type === 'bezier-curve') {
          edgeShapeStyle.cpX1 = (p1[0] + p2[0]) / 2 - (p2[1] - p1[1]) / 4;
          edgeShapeStyle.cpY1 = (p1[1] + p2[1]) / 2 - (p1[0] - p2[0]) / 4;
        }

        edgeShapeStyle.xStart = p1[0];
        edgeShapeStyle.yStart = p1[1];
        edgeShapeStyle.xEnd = p2[0];
        edgeShapeStyle.yEnd = p2[1];
        edge.shape.modSelf();

        if (edge.shape._symbolShape) {
          var symbolShape = edge.shape._symbolShape;
          vec2.copy(symbolShape.position, p2);
          vec2.scaleAndAdd(symbolShape.position, symbolShape.position, v, targetShape.style.width / 2 + 2);
          var angle = Math.atan2(v[1], v[0]);
          symbolShape.rotation = Math.PI / 2 - angle;
          symbolShape.modSelf();
        }
      }
    },
    _syncNodePositions: function () {
      var graph = this._graph;

      for (var i = 0; i < graph.nodes.length; i++) {
        var gNode = graph.nodes[i];
        var position = gNode.layout.position;
        var node = gNode.data;
        var shape = gNode.shape;
        var fixX = shape.fixed || node.fixX;
        var fixY = shape.fixed || node.fixY;

        if (fixX === true) {
          fixX = 1;
        } else if (isNaN(fixX)) {
          fixX = 0;
        }

        if (fixY === true) {
          fixY = 1;
        } else if (isNaN(fixY)) {
          fixY = 0;
        }

        shape.position[0] += (position[0] - shape.position[0]) * (1 - fixX);
        shape.position[1] += (position[1] - shape.position[1]) * (1 - fixY);
        vec2.copy(position, shape.position);
        var nodeName = node.name;

        if (nodeName) {
          var gPos = this.__nodePositionMap[nodeName];

          if (!gPos) {
            gPos = this.__nodePositionMap[nodeName] = vec2.create();
          }

          vec2.copy(gPos, position);
        }

        shape.modSelf();
      }
    },
    _step: function (e) {
      this._syncNodePositions();

      this._updateLinkShapes();

      this.zr.refreshNextFrame();

      if (this._layout.temperature > 0.01) {
        this._layout.step(this._steps);
      } else {
        this.messageCenter.dispatch(ecConfig.EVENT.FORCE_LAYOUT_END, {}, {}, this.myChart);
      }
    },
    refresh: function (newOption) {
      if (newOption) {
        this.option = newOption;
        this.series = this.option.series;
      }

      this.legend = this.component.legend;

      if (this.legend) {
        this.getColor = function (param) {
          return this.legend.getColor(param);
        };

        this.isSelected = function (param) {
          return this.legend.isSelected(param);
        };
      } else {
        var colorMap = {};
        var count = 0;

        this.getColor = function (key) {
          if (colorMap[key]) {
            return colorMap[key];
          }

          if (!colorMap[key]) {
            colorMap[key] = this.zr.getColor(count++);
          }

          return colorMap[key];
        };

        this.isSelected = function () {
          return true;
        };
      }

      this._init();
    },
    dispose: function () {
      this.clear();
      this.shapeList = null;
      this.effectList = null;

      this._layout.dispose();

      this._layout = null;
      this.__nodePositionMap = {};
    },
    getPosition: function () {
      var position = [];

      this._graph.eachNode(function (n) {
        if (n.layout) {
          position.push({
            name: n.data.name,
            position: Array.prototype.slice.call(n.layout.position)
          });
        }
      });

      return position;
    }
  };
  /**
   * 拖拽开始
   */

  function ondragstart(param) {
    if (!this.isDragstart || !param.target) {
      // 没有在当前实例上发生拖拽行为则直接返回
      return;
    }

    var shape = param.target;
    shape.fixed = true; // 处理完拖拽事件后复位

    this.isDragstart = false;
    this.zr.on(zrConfig.EVENT.MOUSEMOVE, this.onmousemove);
  }

  function onmousemove() {
    this._layout.temperature = 0.8;

    this._step();
  }
  /**
   * 数据项被拖拽出去，重载基类方法
   */


  function ondragend(param, status) {
    if (!this.isDragend || !param.target) {
      // 没有在当前实例上发生拖拽行为则直接返回
      return;
    }

    var shape = param.target;
    shape.fixed = false; // 别status = {}赋值啊！！

    status.dragIn = true; //你自己refresh的话把他设为false，设true就会重新调refresh接口

    status.needRefresh = false; // 处理完拖拽事件后复位

    this.isDragend = false;
    this.zr.un(zrConfig.EVENT.MOUSEMOVE, this.onmousemove);
  }

  function _randomInSquare(x, y, size) {
    var v = vec2.create();
    v[0] = (Math.random() - 0.5) * size + x;
    v[1] = (Math.random() - 0.5) * size + y;
    return v;
  }

  zrUtil.inherits(Force, ChartBase); // 图表注册

  require('../chart').define('force', Force);

  return Force;
}(require);