@7polo/kityminder-core
Version:
KityMinder Core Implement
171 lines (151 loc) • 5.7 kB
JavaScript
define(function(require, exports, module) {
var kity = require('../core/kity');
var utils = require('../core/utils');
var keymap = require('../core/keymap');
var Minder = require('../core/minder');
var MinderNode = require('../core/node');
var Command = require('../core/command');
var Module = require('../core/module');
var Renderer = require('../core/render');
Module.register('KeyboardModule', function() {
var min = Math.min,
max = Math.max,
abs = Math.abs,
sqrt = Math.sqrt,
exp = Math.exp;
function buildPositionNetwork(root) {
var pointIndexes = [],
p;
root.traverse(function(node) {
p = node.getLayoutBox();
// bugfix: 不应导航到收起的节点(判断其尺寸是否存在)
if (p.width && p.height) {
pointIndexes.push({
left: p.x,
top: p.y,
right: p.x + p.width,
bottom: p.y + p.height,
width: p.width,
height: p.height,
node: node
});
}
});
for (var i = 0; i < pointIndexes.length; i++) {
findClosestPointsFor(pointIndexes, i);
}
}
// 这是金泉的点子,赞!
// 求两个不相交矩形的最近距离
function getCoefedDistance(box1, box2) {
var xMin, xMax, yMin, yMax, xDist, yDist, dist, cx, cy;
xMin = min(box1.left, box2.left);
xMax = max(box1.right, box2.right);
yMin = min(box1.top, box2.top);
yMax = max(box1.bottom, box2.bottom);
xDist = xMax - xMin - box1.width - box2.width;
yDist = yMax - yMin - box1.height - box2.height;
if (xDist < 0) dist = yDist;
else if (yDist < 0) dist = xDist;
else dist = sqrt(xDist * xDist + yDist * yDist);
var node1 = box1.node;
var node2 = box2.node;
// sibling
if (node1.parent == node2.parent) {
dist /= 10;
}
// parent
if (node2.parent == node1) {
dist /= 5;
}
return dist;
}
function findClosestPointsFor(pointIndexes, iFind) {
var find = pointIndexes[iFind];
var most = {},
quad;
var current, dist;
for (var i = 0; i < pointIndexes.length; i++) {
if (i == iFind) continue;
current = pointIndexes[i];
dist = getCoefedDistance(current, find);
// left check
if (current.right < find.left) {
if (!most.left || dist < most.left.dist) {
most.left = {
dist: dist,
node: current.node
};
}
}
// right check
if (current.left > find.right) {
if (!most.right || dist < most.right.dist) {
most.right = {
dist: dist,
node: current.node
};
}
}
// top check
if (current.bottom < find.top) {
if (!most.top || dist < most.top.dist) {
most.top = {
dist: dist,
node: current.node
};
}
}
// bottom check
if (current.top > find.bottom) {
if (!most.down || dist < most.down.dist) {
most.down = {
dist: dist,
node: current.node
};
}
}
}
find.node._nearestNodes = {
right: most.right && most.right.node || null,
top: most.top && most.top.node || null,
left: most.left && most.left.node || null,
down: most.down && most.down.node || null
};
}
function navigateTo(km, direction) {
var referNode = km.getSelectedNode();
if (!referNode) {
km.select(km.getRoot());
buildPositionNetwork(km.getRoot());
return;
}
if (!referNode._nearestNodes) {
buildPositionNetwork(km.getRoot());
}
var nextNode = referNode._nearestNodes[direction];
if (nextNode) {
km.select(nextNode, true);
}
}
// 稀释用
var lastFrame;
return {
'events': {
'layoutallfinish': function() {
var root = this.getRoot();
buildPositionNetwork(root);
},
'normal.keydown readonly.keydown': function(e) {
var minder = this;
['left', 'right', 'up', 'down'].forEach(function(key) {
if (e.isShortcutKey(key)) {
navigateTo(minder, key == 'up' ? 'top' : key);
e.preventDefault();
}
});
}
}
};
});
});