function _createSuper(Derived) { return function () { var Super = _getPrototypeOf(Derived), result; if (_isNativeReflectConstruct()) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } var Base = require('../../base'); var SimulateAnneal = /*#__PURE__*/function (_Base) { _inheritsLoose(SimulateAnneal, _Base); var _super = _createSuper(SimulateAnneal); function SimulateAnneal() { return _Base.apply(this, arguments) || this; } var _proto = SimulateAnneal.prototype; _proto.getDefaultCfg = function getDefaultCfg() { return { // 最大移动距离 maxMove: 5, // 线长的权重 lineLength: 0.2, // 线碰撞权重 intersect: 1, // 标签与标签碰撞权重 labelToLabel: 30, // 标签与别的shape碰撞权重 labelToShape: 30, // 标签偏移 orient: 3, // 迭代次数 iteration: 200, // 退火阈值 threshold: 0.1 }; } // 简单的图形碰撞检测 ; _proto._intersect = function _intersect(x1, x2, x3, x4, y1, y2, y3, y4) { var denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); var numera = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); var numerb = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3); var mua = numera / denom; var mub = numerb / denom; if (!(mua < 0 || mua > 1 || mub < 0 || mub > 1)) { return true; } return false; } // 计算重排一个label后的能量值 ; _proto.energy = function energy(index) { var self = this; var labels = self.get('labels'); var shapes = self.get('shapes'); var labelLen = labels.length; var label = labels[index]; var shape = shapes[index]; var bbox = label.getBBox(); var energy = 0; var dx = labels[index].attr('x') - shapes[index].attr('x'); var dy = labels[index].attr('y') - shapes[index].attr('y'); var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { energy += dist * self.get('lineLength'); } dx /= dist; dy /= dist; if (dx > 0 && dy > 0) { energy += 0; } else if (dx < 0 && dy > 0) { energy += self.get('orient'); } else if (dx < 0 && dy < 0) { energy += self.get('orient') * 2; } else { energy += self.get('orient') * 3; } var overlap, overlapX, overlapY, temp, tempBBox, tempShape, tempShapeBBox; for (var i = 0; i < labelLen; i++) { temp = labels[i]; tempBBox = temp.getBBox(); tempShape = shapes[i]; tempShapeBBox = tempShape.getBBox(); // 标签与标签碰撞增加能量 if (i !== index) { overlap = self._intersect(shape.attr('x'), label.attr('x'), tempShape.attr('x'), temp.attr('x'), shape.attr('y'), label.attr('y'), tempShape.attr('y'), temp.attr('y')); if (overlap) { energy += self.get('intersect'); } overlapX = Math.max(0, Math.min(tempBBox.maxX, bbox.maxX) - Math.max(tempBBox.minX, bbox.minX)); overlapY = Math.max(0, Math.min(tempBBox.maxY, bbox.maxY) - Math.max(tempBBox.minY, bbox.minY)); energy += overlapX * overlapY * self.get('labelToLabel'); } // 标签与shape碰撞能量 overlapX = Math.max(0, Math.min(tempShapeBBox.maxX, bbox.maxX) - Math.max(tempShapeBBox.minX, bbox.minX)); overlapY = Math.max(0, Math.min(tempShapeBBox.maxY, bbox.maxY) - Math.max(tempShapeBBox.minY, bbox.minY)); energy += overlapX * overlapY * self.get('labelToShape'); } return energy; } // 蒙特卡罗模拟位移 ; _proto.move = function move(current) { var self = this; var labels = this.get('labels'); var random = Math.floor(Math.random() * labels.length); var label = labels[random]; var origin = { x: labels[random].attr('x'), y: labels[random].attr('y') }; var originEnergy = self.energy(random); var moveX = label.attr('x') + (Math.random() - 0.5) * self.get('maxMove'); if (moveX < 0) { moveX = origin.x; } var moveY = label.attr('y') + (Math.random() - 0.5) * self.get('maxMove'); if (moveY < 0) { moveY = origin.y; } label.attr({ x: moveX, y: moveY }); var newEnergy = self.energy(random); var d = newEnergy - originEnergy; if (Math.random() > Math.exp(-d / current)) { label.attr({ x: origin.x, y: origin.y }); } }; _proto.cooling = function cooling(current, init, iterate) { return current - init / iterate; }; _proto.adjust = function adjust(labels, shapes) { var self = this; var iteration = self.get('iteration'); self.set('labels', labels); self.set('shapes', shapes); var initTime = 1; var currentTime = 1; for (var i = 0; i < iteration; i++) { for (var j = 0; j < labels.length; j++) { self.move(currentTime); } currentTime = self.cooling(currentTime, initTime, iteration); if (currentTime < self.get('threshold')) { break; } } }; return SimulateAnneal; }(Base); module.exports = SimulateAnneal;