188 lines
6.2 KiB
JavaScript
188 lines
6.2 KiB
JavaScript
![]() |
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;
|