Browse Source

Pull request #3312: KERNEL-14012 feat: core/structure文件夹

Merge in VISUAL/fineui from ~DAILER/fineui:es6 to es6

* commit 'c4184571d3c5b808fb3231add275aa356ffdf513':
  KERNEL-14012 feat: core/structure文件夹
  KERNEL-14012 feat: core/structure文件夹
  KERNEL-14012 feat: core/structure文件夹
es6
Dailer-刘荣歆 2 years ago
parent
commit
929649567a
  1. 12
      src/core/index.js
  2. 720
      src/core/structure/aes.js
  3. 37
      src/core/structure/aspect.js
  4. 70
      src/core/structure/base64.js
  5. 47
      src/core/structure/cache.js
  6. 192
      src/core/structure/cellSizeAndPositionManager.js
  7. 70
      src/core/structure/heap.js
  8. 13
      src/core/structure/index.js
  9. 58
      src/core/structure/linkedHashMap.js
  10. 38
      src/core/structure/lru.js
  11. 111
      src/core/structure/prefixIntervalTree.js
  12. 93
      src/core/structure/queue.js
  13. 79
      src/core/structure/sectionManager.js
  14. 578
      src/core/structure/tree.js
  15. 49
      src/core/structure/vector.js

12
src/core/index.js

@ -1,4 +1,3 @@
import * as base from "./2.base"; import * as base from "./2.base";
import * as ob from "./3.ob"; import * as ob from "./3.ob";
import * as widget from "./4.widget"; import * as widget from "./4.widget";
@ -7,10 +6,11 @@ import * as action from "./action";
import * as behavior from "./behavior"; import * as behavior from "./behavior";
import * as controllers from "./controller"; import * as controllers from "./controller";
import * as func from "./func"; import * as func from "./func";
import { StyleLoaderManager } from "./loader/loader.style"; import * as structure from "./structure";
import {StyleLoaderManager} from "./loader/loader.style";
import "./h"; import "./h";
import { ShowListener } from "./listener/listener.show"; import {ShowListener} from "./listener/listener.show";
import { shortcut } from "./decorator"; import {shortcut} from "./decorator";
export * from "./2.base"; export * from "./2.base";
export * from "./3.ob"; export * from "./3.ob";
@ -20,6 +20,7 @@ export * from "./action";
export * from "./behavior"; export * from "./behavior";
export * from "./controller"; export * from "./controller";
export * from "./func"; export * from "./func";
export * from "./structure";
// 有了后删掉 // 有了后删掉
export const emptyFn = () => { } export const emptyFn = () => { }
@ -28,7 +29,7 @@ export {
StyleLoaderManager, StyleLoaderManager,
ShowListener, ShowListener,
shortcut, shortcut,
} };
Object.assign(BI, { Object.assign(BI, {
...base, ...base,
@ -42,4 +43,5 @@ Object.assign(BI, {
...func, ...func,
StyleLoaderManager, StyleLoaderManager,
ShowListener, ShowListener,
...structure,
}); });

720
src/core/structure/aes.js

File diff suppressed because it is too large Load Diff

37
src/core/structure/aspect.js

@ -1,15 +1,14 @@
!(function () { function _aspect(type) {
function aspect (type) {
return function (target, methodName, advice) { return function (target, methodName, advice) {
var exist = target[methodName], let exist = target[methodName],
dispatcher; dispatcher;
if (!exist || exist.target != target) { if (!exist || exist.target != target) {
dispatcher = target[methodName] = function () { dispatcher = target[methodName] = function () {
// before methods // before methods
var beforeArr = dispatcher.before; let beforeArr = dispatcher.before;
var args = arguments, next; let args = arguments, next;
for (var l = beforeArr.length; l--;) { for (let l = beforeArr.length; l--;) {
next = beforeArr[l].advice.apply(this, args); next = beforeArr[l].advice.apply(this, args);
if (next === false) { if (next === false) {
return false; return false;
@ -17,10 +16,10 @@
args = next || args; args = next || args;
} }
// target method // target method
var rs = dispatcher.method.apply(this, args); let rs = dispatcher.method.apply(this, args);
// after methods // after methods
var afterArr = dispatcher.after; let afterArr = dispatcher.after;
for (var i = 0, ii = afterArr.length; i < ii; i++) { for (let i = 0, ii = afterArr.length; i < ii; i++) {
next = afterArr[i].advice.call(this, rs, args); next = afterArr[i].advice.call(this, rs, args);
if (rs === false) { if (rs === false) {
return false; return false;
@ -39,25 +38,21 @@
dispatcher.target = target; dispatcher.target = target;
} }
var aspectArr = (dispatcher || exist)[type]; let aspectArr = (dispatcher || exist)[type];
var obj = { let obj = {
advice: advice, advice: advice,
_index: aspectArr.length, _index: aspectArr.length,
remove: function () { remove: function () {
aspectArr.splice(this._index, 1); aspectArr.splice(this._index, 1);
} },
}; };
aspectArr.push(obj); aspectArr.push(obj);
return obj; return obj;
}; };
} }
BI.aspect = {
before: aspect("before"),
after: aspect("after")
};
return BI.aspect;
})(); export const aspect = {
before: _aspect("before"),
after: _aspect("after"),
};

70
src/core/structure/base64.js

@ -1,17 +1,14 @@
const _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
!(function () {
var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; // private method for UTF-8 encoding
const _utf8_encode = function (string) {
// private method for UTF-8 encoding
var _utf8_encode = function (string) {
string = string.replace(/\r\n/g, "\n"); string = string.replace(/\r\n/g, "\n");
var utftext = ""; let utftext = "";
for (var n = 0; n < string.length; n++) { for (let n = 0; n < string.length; n++) {
var c = string.charCodeAt(n); const c = string.charCodeAt(n);
if (c < 128) { if (c < 128) {
utftext += String.fromCharCode(c); utftext += String.fromCharCode(c);
@ -27,13 +24,13 @@
} }
return utftext; return utftext;
}; };
// private method for UTF-8 decoding // private method for UTF-8 decoding
var _utf8_decode = function (utftext) { const _utf8_decode = function (utftext) {
var string = ""; let string = "";
var i = 0; let i = 0;
var c = 0, c3 = 0, c2 = 0; let c = 0, c3 = 0, c2 = 0;
while (i < utftext.length) { while (i < utftext.length) {
@ -55,14 +52,17 @@
} }
return string; return string;
}; };
BI._.extend(BI, { /**
* base64 encode
encode: function (input) { * @param input
var output = ""; * @returns {string}
var chr1, chr2, chr3, enc1, enc2, enc3, enc4; */
var i = 0; export function encode(input) {
let output = "";
let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
let i = 0;
input = _utf8_encode(input); input = _utf8_encode(input);
@ -88,14 +88,18 @@
} }
return output; return output;
}, }
// public method for decoding /**
decode: function (input) { * base64 decode
var output = ""; * @param input
var chr1, chr2, chr3; * @returns {string}
var enc1, enc2, enc3, enc4; */
var i = 0; export function decode(input) {
let output = "";
let chr1, chr2, chr3;
let enc1, enc2, enc3, enc4;
let i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
@ -125,6 +129,4 @@
return output; return output;
} }
});
})();

47
src/core/structure/cache.js

@ -1,43 +1,42 @@
export const Cache = {
BI.Cache = {
_prefix: "bi", _prefix: "bi",
setUsername: function (username) { setUsername: function (username) {
localStorage.setItem(BI.Cache._prefix + ".username", (username + "" || "").toUpperCase()); localStorage.setItem(Cache._prefix + ".username", (username + "" || "").toUpperCase());
}, },
getUsername: function () { getUsername: function () {
return localStorage.getItem(BI.Cache._prefix + ".username") || ""; return localStorage.getItem(Cache._prefix + ".username") || "";
}, },
_getKeyPrefix: function () { _getKeyPrefix: function () {
return BI.Cache.getUsername() + "." + BI.Cache._prefix + "."; return Cache.getUsername() + "." + Cache._prefix + ".";
}, },
_generateKey: function (key) { _generateKey: function (key) {
return BI.Cache._getKeyPrefix() + (key || ""); return Cache._getKeyPrefix() + (key || "");
}, },
getItem: function (key) { getItem: function (key) {
return localStorage.getItem(BI.Cache._generateKey(key)); return localStorage.getItem(Cache._generateKey(key));
}, },
setItem: function (key, value) { setItem: function (key, value) {
localStorage.setItem(BI.Cache._generateKey(key), value); localStorage.setItem(Cache._generateKey(key), value);
}, },
removeItem: function (key) { removeItem: function (key) {
localStorage.removeItem(BI.Cache._generateKey(key)); localStorage.removeItem(Cache._generateKey(key));
}, },
clear: function () { clear: function () {
for (var i = localStorage.length; i >= 0; i--) { for (let i = localStorage.length; i >= 0; i--) {
var key = localStorage.key(i); const key = localStorage.key(i);
if (key) { if (key) {
if (key.indexOf(BI.Cache._getKeyPrefix()) === 0) { if (key.indexOf(Cache._getKeyPrefix()) === 0) {
localStorage.removeItem(key); localStorage.removeItem(key);
} }
} }
} }
}, },
keys: function () { keys: function () {
var result = []; const result = [];
for (var i = localStorage.length; i >= 0; i--) { for (let i = localStorage.length; i >= 0; i--) {
var key = localStorage.key(i); const key = localStorage.key(i);
if (key) { if (key) {
var prefix = BI.Cache._getKeyPrefix(); const prefix = Cache._getKeyPrefix();
if (key.indexOf(prefix) === 0) { if (key.indexOf(prefix) === 0) {
result[result.length] = key.substring(prefix.length); result[result.length] = key.substring(prefix.length);
} }
@ -47,10 +46,10 @@ BI.Cache = {
}, },
addCookie: function (name, value, path, expiresHours) { addCookie: function (name, value, path, expiresHours) {
var cookieString = name + "=" + encodeURI(value); let cookieString = name + "=" + encodeURI(value);
// 判断是否设置过期时间 // 判断是否设置过期时间
if (expiresHours && expiresHours > 0) { if (expiresHours && expiresHours > 0) {
var date = new Date(); const date = new Date();
// expires是标准GMT格式时间,应该使用时间戳作为起始时间 // expires是标准GMT格式时间,应该使用时间戳作为起始时间
date.setTime(date.getTime() + expiresHours * 3600 * 1000); date.setTime(date.getTime() + expiresHours * 3600 * 1000);
cookieString = cookieString + "; expires=" + date.toUTCString(); cookieString = cookieString + "; expires=" + date.toUTCString();
@ -61,17 +60,19 @@ BI.Cache = {
document.cookie = cookieString; document.cookie = cookieString;
}, },
getCookie: function (name) { getCookie: function (name) {
var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)"); let arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
if (arr = document.cookie.match(reg)) {return decodeURI(arr[2]);} if (arr = document.cookie.match(reg)) {
return decodeURI(arr[2]);
}
return null; return null;
}, },
deleteCookie: function (name, path) { deleteCookie: function (name, path) {
var date = new Date(); const date = new Date();
date.setTime(date.getTime() - 10000); date.setTime(date.getTime() - 10000);
var cookieString = name + "=v; expires=" + date.toUTCString(); let cookieString = name + "=v; expires=" + date.toUTCString();
if (path) { if (path) {
cookieString = cookieString + "; path=" + path; cookieString = cookieString + "; path=" + path;
} }
document.cookie = cookieString; document.cookie = cookieString;
} },
}; };

192
src/core/structure/cellSizeAndPositionManager.js

@ -1,40 +1,40 @@
BI.CellSizeAndPositionManager = function (cellCount, cellSizeGetter, estimatedCellSize) { export class CellSizeAndPositionManager {
constructor(cellCount, cellSizeGetter, estimatedCellSize) {
this._cellSizeGetter = cellSizeGetter; this._cellSizeGetter = cellSizeGetter;
this._cellCount = cellCount; this._cellCount = cellCount;
this._estimatedCellSize = estimatedCellSize; this._estimatedCellSize = estimatedCellSize;
this._cellSizeAndPositionData = {}; this._cellSizeAndPositionData = {};
this._lastMeasuredIndex = -1; this._lastMeasuredIndex = -1;
}; }
BI.CellSizeAndPositionManager.prototype = { configure(cellCount, estimatedCellSize) {
constructor: BI.CellSizeAndPositionManager,
configure: function (cellCount, estimatedCellSize) {
this._cellCount = cellCount; this._cellCount = cellCount;
this._estimatedCellSize = estimatedCellSize; this._estimatedCellSize = estimatedCellSize;
}, }
getCellCount: function () { getCellCount() {
return this._cellCount; return this._cellCount;
}, }
getEstimatedCellSize: function () { getEstimatedCellSize() {
return this._estimatedCellSize; return this._estimatedCellSize;
}, }
getLastMeasuredIndex: function () { getLastMeasuredIndex() {
return this._lastMeasuredIndex; return this._lastMeasuredIndex;
}, }
getSizeAndPositionOfCell: function (index) { getSizeAndPositionOfCell(index) {
if (index < 0 || index >= this._cellCount) { if (index < 0 || index >= this._cellCount) {
return; return;
} }
if (index > this._lastMeasuredIndex) { if (index > this._lastMeasuredIndex) {
var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell(); const lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell();
var offset = lastMeasuredCellSizeAndPosition.offset + lastMeasuredCellSizeAndPosition.size; let offset = lastMeasuredCellSizeAndPosition.offset + lastMeasuredCellSizeAndPosition.size;
for (var i = this._lastMeasuredIndex + 1; i <= index; i++) { for (let i = this._lastMeasuredIndex + 1; i <= index; i++) {
var size = this._cellSizeGetter(i); const size = this._cellSizeGetter(i);
if (size == null || isNaN(size)) { if (size == null || isNaN(size)) {
continue; continue;
@ -42,7 +42,7 @@ BI.CellSizeAndPositionManager.prototype = {
this._cellSizeAndPositionData[i] = { this._cellSizeAndPositionData[i] = {
offset: offset, offset: offset,
size: size size: size,
}; };
offset += size; offset += size;
@ -51,28 +51,28 @@ BI.CellSizeAndPositionManager.prototype = {
this._lastMeasuredIndex = index; this._lastMeasuredIndex = index;
} }
return this._cellSizeAndPositionData[index]; return this._cellSizeAndPositionData[index];
}, }
getSizeAndPositionOfLastMeasuredCell: function () { getSizeAndPositionOfLastMeasuredCell() {
return this._lastMeasuredIndex >= 0 return this._lastMeasuredIndex >= 0
? this._cellSizeAndPositionData[this._lastMeasuredIndex] ? this._cellSizeAndPositionData[this._lastMeasuredIndex]
: { : {
offset: 0, offset: 0,
size: 0 size: 0,
}; };
}, }
getTotalSize: function () { getTotalSize() {
var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell(); const lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell();
return lastMeasuredCellSizeAndPosition.offset + lastMeasuredCellSizeAndPosition.size + (this._cellCount - this._lastMeasuredIndex - 1) * this._estimatedCellSize; return lastMeasuredCellSizeAndPosition.offset + lastMeasuredCellSizeAndPosition.size + (this._cellCount - this._lastMeasuredIndex - 1) * this._estimatedCellSize;
}, }
getUpdatedOffsetForIndex: function (align, containerSize, currentOffset, targetIndex) { getUpdatedOffsetForIndex(align, containerSize, currentOffset, targetIndex) {
var datum = this.getSizeAndPositionOfCell(targetIndex); const datum = this.getSizeAndPositionOfCell(targetIndex);
var maxOffset = datum.offset; const maxOffset = datum.offset;
var minOffset = maxOffset - containerSize + datum.size; const minOffset = maxOffset - containerSize + datum.size;
var idealOffset; let idealOffset;
switch (align) { switch (align) {
case "start": case "start":
@ -89,25 +89,25 @@ BI.CellSizeAndPositionManager.prototype = {
break; break;
} }
var totalSize = this.getTotalSize(); const totalSize = this.getTotalSize();
return Math.max(0, Math.min(totalSize - containerSize, idealOffset)); return Math.max(0, Math.min(totalSize - containerSize, idealOffset));
}, }
getVisibleCellRange: function (containerSize, offset) { getVisibleCellRange(containerSize, offset) {
var totalSize = this.getTotalSize(); const totalSize = this.getTotalSize();
if (totalSize === 0) { if (totalSize === 0) {
return {}; return {};
} }
var maxOffset = offset + containerSize; const maxOffset = offset + containerSize;
var start = this._findNearestCell(offset); const start = this._findNearestCell(offset);
var datum = this.getSizeAndPositionOfCell(start); const datum = this.getSizeAndPositionOfCell(start);
offset = datum.offset + datum.size; offset = datum.offset + datum.size;
var stop = start; let stop = start;
while (offset < maxOffset && stop < this._cellCount - 1) { while (offset < maxOffset && stop < this._cellCount - 1) {
stop++; stop++;
@ -116,17 +116,17 @@ BI.CellSizeAndPositionManager.prototype = {
return { return {
start: start, start: start,
stop: stop stop: stop,
}; };
}, }
resetCell: function (index) { resetCell(index) {
this._lastMeasuredIndex = Math.min(this._lastMeasuredIndex, index - 1); this._lastMeasuredIndex = Math.min(this._lastMeasuredIndex, index - 1);
}, }
_binarySearch: function (high, low, offset) { _binarySearch(high, low, offset) {
var middle; let middle;
var currentOffset; let currentOffset;
while (low <= high) { while (low <= high) {
middle = low + Math.floor((high - low) / 2); middle = low + Math.floor((high - low) / 2);
@ -144,10 +144,10 @@ BI.CellSizeAndPositionManager.prototype = {
if (low > 0) { if (low > 0) {
return low - 1; return low - 1;
} }
}, }
_exponentialSearch: function (index, offset) { _exponentialSearch(index, offset) {
var interval = 1; let interval = 1;
while (index < this._cellCount && this.getSizeAndPositionOfCell(index).offset < offset) { while (index < this._cellCount && this.getSizeAndPositionOfCell(index).offset < offset) {
index += interval; index += interval;
@ -155,17 +155,17 @@ BI.CellSizeAndPositionManager.prototype = {
} }
return this._binarySearch(Math.min(index, this._cellCount - 1), Math.floor(index / 2), offset); return this._binarySearch(Math.min(index, this._cellCount - 1), Math.floor(index / 2), offset);
}, }
_findNearestCell: function (offset) { _findNearestCell(offset) {
if (isNaN(offset)) { if (isNaN(offset)) {
return; return;
} }
offset = Math.max(0, offset); offset = Math.max(0, offset);
var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell(); const lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell();
var lastMeasuredIndex = Math.max(0, this._lastMeasuredIndex); const lastMeasuredIndex = Math.max(0, this._lastMeasuredIndex);
if (lastMeasuredCellSizeAndPosition.offset >= offset) { if (lastMeasuredCellSizeAndPosition.offset >= offset) {
return this._binarySearch(lastMeasuredIndex, 0, offset); return this._binarySearch(lastMeasuredIndex, 0, offset);
@ -173,99 +173,97 @@ BI.CellSizeAndPositionManager.prototype = {
return this._exponentialSearch(lastMeasuredIndex, offset); return this._exponentialSearch(lastMeasuredIndex, offset);
} }
}; }
BI.ScalingCellSizeAndPositionManager = function (cellCount, cellSizeGetter, estimatedCellSize, maxScrollSize) { export class ScalingCellSizeAndPositionManager {
this._cellSizeAndPositionManager = new BI.CellSizeAndPositionManager(cellCount, cellSizeGetter, estimatedCellSize); constructor(cellCount, cellSizeGetter, estimatedCellSize, maxScrollSize) {
this._cellSizeAndPositionManager = new CellSizeAndPositionManager(cellCount, cellSizeGetter, estimatedCellSize);
this._maxScrollSize = maxScrollSize || 10000000; this._maxScrollSize = maxScrollSize || 10000000;
}; }
BI.ScalingCellSizeAndPositionManager.prototype = {
constructor: BI.ScalingCellSizeAndPositionManager,
configure: function () { configure() {
this._cellSizeAndPositionManager.configure.apply(this._cellSizeAndPositionManager, arguments); this._cellSizeAndPositionManager.configure.apply(this._cellSizeAndPositionManager, arguments);
}, }
getCellCount: function () { getCellCount() {
return this._cellSizeAndPositionManager.getCellCount(); return this._cellSizeAndPositionManager.getCellCount();
}, }
getEstimatedCellSize: function () { getEstimatedCellSize() {
return this._cellSizeAndPositionManager.getEstimatedCellSize(); return this._cellSizeAndPositionManager.getEstimatedCellSize();
}, }
getLastMeasuredIndex: function () { getLastMeasuredIndex() {
return this._cellSizeAndPositionManager.getLastMeasuredIndex(); return this._cellSizeAndPositionManager.getLastMeasuredIndex();
}, }
getOffsetAdjustment: function (containerSize, offset) { getOffsetAdjustment(containerSize, offset) {
var totalSize = this._cellSizeAndPositionManager.getTotalSize(); const totalSize = this._cellSizeAndPositionManager.getTotalSize();
var safeTotalSize = this.getTotalSize(); const safeTotalSize = this.getTotalSize();
var offsetPercentage = this._getOffsetPercentage(containerSize, offset, safeTotalSize); const offsetPercentage = this._getOffsetPercentage(containerSize, offset, safeTotalSize);
return Math.round(offsetPercentage * (safeTotalSize - totalSize)); return Math.round(offsetPercentage * (safeTotalSize - totalSize));
}, }
getSizeAndPositionOfCell: function (index) { getSizeAndPositionOfCell(index) {
return this._cellSizeAndPositionManager.getSizeAndPositionOfCell(index); return this._cellSizeAndPositionManager.getSizeAndPositionOfCell(index);
}, }
getSizeAndPositionOfLastMeasuredCell: function () { getSizeAndPositionOfLastMeasuredCell() {
return this._cellSizeAndPositionManager.getSizeAndPositionOfLastMeasuredCell(); return this._cellSizeAndPositionManager.getSizeAndPositionOfLastMeasuredCell();
}, }
getTotalSize: function () { getTotalSize() {
return Math.min(this._maxScrollSize, this._cellSizeAndPositionManager.getTotalSize()); return Math.min(this._maxScrollSize, this._cellSizeAndPositionManager.getTotalSize());
}, }
getUpdatedOffsetForIndex: function (align, containerSize, currentOffset, targetIndex) { getUpdatedOffsetForIndex(align, containerSize, currentOffset, targetIndex) {
currentOffset = this._safeOffsetToOffset(containerSize, currentOffset); currentOffset = this._safeOffsetToOffset(containerSize, currentOffset);
var offset = this._cellSizeAndPositionManager.getUpdatedOffsetForIndex(align, containerSize, currentOffset, targetIndex); const offset = this._cellSizeAndPositionManager.getUpdatedOffsetForIndex(align, containerSize, currentOffset, targetIndex);
return this._offsetToSafeOffset(containerSize, offset); return this._offsetToSafeOffset(containerSize, offset);
}, }
getVisibleCellRange: function (containerSize, offset) { getVisibleCellRange(containerSize, offset) {
offset = this._safeOffsetToOffset(containerSize, offset); offset = this._safeOffsetToOffset(containerSize, offset);
return this._cellSizeAndPositionManager.getVisibleCellRange(containerSize, offset); return this._cellSizeAndPositionManager.getVisibleCellRange(containerSize, offset);
}, }
resetCell: function (index) { resetCell(index) {
this._cellSizeAndPositionManager.resetCell(index); this._cellSizeAndPositionManager.resetCell(index);
}, }
_getOffsetPercentage: function (containerSize, offset, totalSize) { _getOffsetPercentage(containerSize, offset, totalSize) {
return totalSize <= containerSize return totalSize <= containerSize
? 0 ? 0
: offset / (totalSize - containerSize); : offset / (totalSize - containerSize);
}, }
_offsetToSafeOffset: function (containerSize, offset) { _offsetToSafeOffset(containerSize, offset) {
var totalSize = this._cellSizeAndPositionManager.getTotalSize(); const totalSize = this._cellSizeAndPositionManager.getTotalSize();
var safeTotalSize = this.getTotalSize(); const safeTotalSize = this.getTotalSize();
if (totalSize === safeTotalSize) { if (totalSize === safeTotalSize) {
return offset; return offset;
} }
var offsetPercentage = this._getOffsetPercentage(containerSize, offset, totalSize); const offsetPercentage = this._getOffsetPercentage(containerSize, offset, totalSize);
return Math.round(offsetPercentage * (safeTotalSize - containerSize)); return Math.round(offsetPercentage * (safeTotalSize - containerSize));
}, }
_safeOffsetToOffset: function (containerSize, offset) { _safeOffsetToOffset(containerSize, offset) {
var totalSize = this._cellSizeAndPositionManager.getTotalSize(); const totalSize = this._cellSizeAndPositionManager.getTotalSize();
var safeTotalSize = this.getTotalSize(); const safeTotalSize = this.getTotalSize();
if (totalSize === safeTotalSize) { if (totalSize === safeTotalSize) {
return offset; return offset;
} }
var offsetPercentage = this._getOffsetPercentage(containerSize, offset, safeTotalSize); const offsetPercentage = this._getOffsetPercentage(containerSize, offset, safeTotalSize);
return Math.round(offsetPercentage * (totalSize - containerSize)); return Math.round(offsetPercentage * (totalSize - containerSize));
} }
}; }

70
src/core/structure/heap.js

@ -1,30 +1,27 @@
function defaultComparator(a, b) {
(function () {
function defaultComparator (a, b) {
return a < b; return a < b;
} }
BI.Heap = function (items, comparator) { export class Heap {
constructor(items, comparator) {
this._items = items || []; this._items = items || [];
this._size = this._items.length; this._size = this._items.length;
this._comparator = comparator || defaultComparator; this._comparator = comparator || defaultComparator;
this._heapify(); this._heapify();
}; }
BI.Heap.prototype = { empty() {
constructor: BI.Heap,
empty: function () {
return this._size === 0; return this._size === 0;
}, }
pop: function () { pop() {
if (this._size === 0) { if (this._size === 0) {
return; return;
} }
var elt = this._items[0]; const elt = this._items[0];
var lastElt = this._items.pop(); const lastElt = this._items.pop();
this._size--; this._size--;
if (this._size > 0) { if (this._size > 0) {
@ -33,36 +30,36 @@
} }
return elt; return elt;
}, }
push: function (item) { push(item) {
this._items[this._size++] = item; this._items[this._size++] = item;
this._bubbleUp(this._size - 1); this._bubbleUp(this._size - 1);
}, }
size: function () { size() {
return this._size; return this._size;
}, }
peek: function () { peek() {
if (this._size === 0) { if (this._size === 0) {
return; return;
} }
return this._items[0]; return this._items[0];
}, }
_heapify: function () { _heapify() {
for (var index = Math.floor((this._size + 1) / 2); index >= 0; index--) { for (let index = Math.floor((this._size + 1) / 2); index >= 0; index--) {
this._sinkDown(index); this._sinkDown(index);
} }
}, }
_bubbleUp: function (index) { _bubbleUp(index) {
var elt = this._items[index]; const elt = this._items[index];
while (index > 0) { while (index > 0) {
var parentIndex = Math.floor((index + 1) / 2) - 1; const parentIndex = Math.floor((index + 1) / 2) - 1;
var parentElt = this._items[parentIndex]; const parentElt = this._items[parentIndex];
// if parentElt < elt, stop // if parentElt < elt, stop
if (this._comparator(parentElt, elt)) { if (this._comparator(parentElt, elt)) {
@ -74,25 +71,25 @@
this._items[index] = parentElt; this._items[index] = parentElt;
index = parentIndex; index = parentIndex;
} }
}, }
_sinkDown: function (index) { _sinkDown(index) {
var elt = this._items[index]; const elt = this._items[index];
while (true) { while (true) {
var leftChildIndex = 2 * (index + 1) - 1; const leftChildIndex = 2 * (index + 1) - 1;
var rightChildIndex = 2 * (index + 1); const rightChildIndex = 2 * (index + 1);
var swapIndex = -1; let swapIndex = -1;
if (leftChildIndex < this._size) { if (leftChildIndex < this._size) {
var leftChild = this._items[leftChildIndex]; const leftChild = this._items[leftChildIndex];
if (this._comparator(leftChild, elt)) { if (this._comparator(leftChild, elt)) {
swapIndex = leftChildIndex; swapIndex = leftChildIndex;
} }
} }
if (rightChildIndex < this._size) { if (rightChildIndex < this._size) {
var rightChild = this._items[rightChildIndex]; const rightChild = this._items[rightChildIndex];
if (this._comparator(rightChild, elt)) { if (this._comparator(rightChild, elt)) {
if (swapIndex === -1 || if (swapIndex === -1 ||
this._comparator(rightChild, this._items[swapIndex])) { this._comparator(rightChild, this._items[swapIndex])) {
@ -111,5 +108,4 @@
index = swapIndex; index = swapIndex;
} }
} }
}; }
})();

13
src/core/structure/index.js

@ -0,0 +1,13 @@
export * from "./aes";
export * from "./aspect";
export * from "./base64";
export * from "./cache";
export * from "./cellSizeAndPositionManager";
export * from "./heap";
export * from "./linkedHashMap";
export * from "./lru";
export * from "./prefixIntervalTree";
export * from "./queue";
export * from "./sectionManager";
export * from "./tree";
export * from "./vector";

58
src/core/structure/linkedHashMap.js

@ -1,19 +1,14 @@
export class LinkHashMap {
!(function () { constructor() {
BI.LinkHashMap = function () {
this.array = []; this.array = [];
this.map = {}; this.map = {};
};
BI.LinkHashMap.prototype = {
constructor: BI.LinkHashMap,
has: function (key) {
if (key in this.map) {
return true;
} }
return false;
},
add: function (key, value) { has(key) {
return key in this.map;
}
add(key, value) {
if (typeof key === "undefined") { if (typeof key === "undefined") {
return; return;
} }
@ -23,50 +18,49 @@
this.array.push(key); this.array.push(key);
this.map[key] = value; this.map[key] = value;
} }
}, }
remove: function (key) { remove(key) {
if (key in this.map) { if (key in this.map) {
delete this.map[key]; delete this.map[key];
for (var i = 0; i < this.array.length; i++) { for (let i = 0; i < this.array.length; i++) {
if (this.array[i] == key) { if (this.array[i] == key) {
this.array.splice(i, 1); this.array.splice(i, 1);
break; break;
} }
} }
} }
}, }
size: function () { size() {
return this.array.length; return this.array.length;
}, }
each: function (fn, scope) { each(fn, scope) {
var scope = scope || window; scope = scope || window;
var fn = fn || null; fn = fn || null;
if (fn == null || typeof (fn) !== "function") { if (fn == null || typeof (fn) !== "function") {
return; return;
} }
for (var i = 0; i < this.array.length; i++) { for (let i = 0; i < this.array.length; i++) {
var key = this.array[i]; const key = this.array[i];
var value = this.map[key]; const value = this.map[key];
var re = fn.call(scope, key, value, i, this.array, this.map); const re = fn.call(scope, key, value, i, this.array, this.map);
if (re == false) { if (re == false) {
break; break;
} }
} }
}, }
get: function (key) { get(key) {
return this.map[key]; return this.map[key];
}, }
toArray: function () { toArray() {
var array = []; const array = [];
this.each(function (key, value) { this.each(function (key, value) {
array.push(value); array.push(value);
}); });
return array; return array;
} }
}; }
})();

38
src/core/structure/lru.js

@ -1,24 +1,21 @@
export class LRU {
!(function () { constructor(limit) {
BI.LRU = function (limit) {
this.size = 0; this.size = 0;
this.limit = limit; this.limit = limit;
this.head = this.tail = undefined; this.head = this.tail = undefined;
this._keymap = {}; this._keymap = {};
}; }
var p = BI.LRU.prototype;
p.put = function (key, value) { put(key, value) {
var removed; let removed;
if (this.size === this.limit) { if (this.size === this.limit) {
removed = this.shift(); removed = this.shift();
} }
var entry = this.get(key, true); let entry = this.get(key, true);
if (!entry) { if (!entry) {
entry = { entry = {
key: key key: key,
}; };
this._keymap[key] = entry; this._keymap[key] = entry;
if (this.tail) { if (this.tail) {
@ -33,10 +30,10 @@
entry.value = value; entry.value = value;
return removed; return removed;
}; }
p.shift = function () { shift() {
var entry = this.head; const entry = this.head;
if (entry) { if (entry) {
this.head = this.head.newer; this.head = this.head.newer;
this.head.older = undefined; this.head.older = undefined;
@ -45,11 +42,10 @@
this.size--; this.size--;
} }
return entry; return entry;
}; }
p.get = function (key, returnEntry) { get(key, returnEntry) {
var entry = this._keymap[key]; const entry = this._keymap[key];
if (entry === undefined) return; if (entry === undefined) return;
if (entry === this.tail) { if (entry === this.tail) {
return returnEntry return returnEntry
@ -78,9 +74,9 @@
return returnEntry return returnEntry
? entry ? entry
: entry.value; : entry.value;
}; }
p.has = function (key) { has(key) {
return this._keymap[key] != null; return this._keymap[key] != null;
}; }
})(); }

111
src/core/structure/prefixIntervalTree.js

@ -1,32 +1,32 @@
// 线段树 // 线段树
(function () { const parent = function (node) {
var parent = function (node) {
return Math.floor(node / 2); return Math.floor(node / 2);
}; };
var Int32Array = _global.Int32Array || function (size) { const Int32Array = _global.Int32Array || function (size) {
var xs = []; const xs = [];
for (var i = size - 1; i >= 0; --i) { for (let i = size - 1; i >= 0; --i) {
xs[i] = 0; xs[i] = 0;
} }
return xs; return xs;
}; };
var ceilLog2 = function (x) { const ceilLog2 = function (x) {
var y = 1; let y = 1;
while (y < x) { while (y < x) {
y *= 2; y *= 2;
} }
return y; return y;
}; };
BI.PrefixIntervalTree = function (xs) { export class PrefixIntervalTree {
constructor(xs) {
this._size = xs.length; this._size = xs.length;
this._half = ceilLog2(this._size); this._half = ceilLog2(this._size);
// _heap是一个_size两倍以上的堆 // _heap是一个_size两倍以上的堆
this._heap = new Int32Array(2 * this._half); this._heap = new Int32Array(2 * this._half);
var i; let i;
// 初始化 >= _size 的堆空间, 即叶子节点 // 初始化 >= _size 的堆空间, 即叶子节点
for (i = 0; i < this._size; ++i) { for (i = 0; i < this._size; ++i) {
this._heap[this._half + i] = xs[i]; this._heap[this._half + i] = xs[i];
@ -35,13 +35,23 @@
for (i = this._half - 1; i > 0; --i) { for (i = this._half - 1; i > 0; --i) {
this._heap[i] = this._heap[2 * i] + this._heap[2 * i + 1]; this._heap[i] = this._heap[2 * i] + this._heap[2 * i + 1];
} }
}; }
static uniform(size, initialValue) {
const xs = [];
for (let i = size - 1; i >= 0; --i) {
xs[i] = initialValue;
}
return new PrefixIntervalTree(xs);
}
BI.PrefixIntervalTree.prototype = { static empty(size) {
constructor: BI.PrefixIntervalTree, return PrefixIntervalTree.uniform(size, 0);
// 往_half之后的空间set值,需要更新其所有祖先节点的值 }
set: function (index, value) {
var node = this._half + index; set(index, value) {
let node = this._half + index;
this._heap[node] = value; this._heap[node] = value;
node = parent(node); node = parent(node);
@ -49,27 +59,27 @@
this._heap[node] = this._heap[node] =
this._heap[2 * node] + this._heap[2 * node + 1]; this._heap[2 * node] + this._heap[2 * node + 1];
} }
}, }
get: function (index) { get(index) {
var node = this._half + index; const node = this._half + index;
return this._heap[node]; return this._heap[node];
}, }
getSize: function () { getSize() {
return this._size; return this._size;
}, }
/** /**
* get(0) + get(1) + ... + get(end - 1). * get(0) + get(1) + ... + get(end - 1).
*/ */
sumUntil: function (end) { sumUntil(end) {
if (end === 0) { if (end === 0) {
return 0; return 0;
} }
var node = this._half + end - 1; let node = this._half + end - 1;
var sum = this._heap[node]; let sum = this._heap[node];
for (; node !== 1; node = parent(node)) { for (; node !== 1; node = parent(node)) {
if (node % 2 === 1) { if (node % 2 === 1) {
sum += this._heap[node - 1]; sum += this._heap[node - 1];
@ -77,38 +87,38 @@
} }
return sum; return sum;
}, }
/** /**
* get(0) + get(1) + ... + get(inclusiveEnd). * get(0) + get(1) + ... + get(inclusiveEnd).
*/ */
sumTo: function (inclusiveEnd) { sumTo(inclusiveEnd) {
return this.sumUntil(inclusiveEnd + 1); return this.sumUntil(inclusiveEnd + 1);
}, }
/** /**
* sum get(begin) + get(begin + 1) + ... + get(end - 1). * sum get(begin) + get(begin + 1) + ... + get(end - 1).
*/ */
sum: function (begin, end) { sum(begin, end) {
return this.sumUntil(end) - this.sumUntil(begin); return this.sumUntil(end) - this.sumUntil(begin);
}, }
/** /**
* Returns the smallest i such that 0 <= i <= size and sumUntil(i) <= t, or * Returns the smallest i such that 0 <= i <= size and sumUntil(i) <= t, or
* -1 if no such i exists. * -1 if no such i exists.
*/ */
greatestLowerBound: function (t) { greatestLowerBound(t) {
if (t < 0) { if (t < 0) {
return -1; return -1;
} }
var node = 1; let node = 1;
if (this._heap[node] <= t) { if (this._heap[node] <= t) {
return this._size; return this._size;
} }
while (node < this._half) { while (node < this._half) {
var leftSum = this._heap[2 * node]; const leftSum = this._heap[2 * node];
if (t < leftSum) { if (t < leftSum) {
node = 2 * node; node = 2 * node;
} else { } else {
@ -118,24 +128,24 @@
} }
return node - this._half; return node - this._half;
}, }
/** /**
* Returns the smallest i such that 0 <= i <= size and sumUntil(i) < t, or * Returns the smallest i such that 0 <= i <= size and sumUntil(i) < t, or
* -1 if no such i exists. * -1 if no such i exists.
*/ */
greatestStrictLowerBound: function (t) { greatestStrictLowerBound(t) {
if (t <= 0) { if (t <= 0) {
return -1; return -1;
} }
var node = 1; let node = 1;
if (this._heap[node] < t) { if (this._heap[node] < t) {
return this._size; return this._size;
} }
while (node < this._half) { while (node < this._half) {
var leftSum = this._heap[2 * node]; const leftSum = this._heap[2 * node];
if (t <= leftSum) { if (t <= leftSum) {
node = 2 * node; node = 2 * node;
} else { } else {
@ -145,36 +155,23 @@
} }
return node - this._half; return node - this._half;
}, }
/** /**
* Returns the smallest i such that 0 <= i <= size and t <= sumUntil(i), or * Returns the smallest i such that 0 <= i <= size and t <= sumUntil(i), or
* size + 1 if no such i exists. * size + 1 if no such i exists.
*/ */
leastUpperBound: function (t) { leastUpperBound(t) {
return this.greatestStrictLowerBound(t) + 1; return this.greatestStrictLowerBound(t) + 1;
}, }
/** /**
* Returns the smallest i such that 0 <= i <= size and t < sumUntil(i), or * Returns the smallest i such that 0 <= i <= size and t < sumUntil(i), or
* size + 1 if no such i exists. * size + 1 if no such i exists.
*/ */
leastStrictUpperBound: function (t) { leastStrictUpperBound(t) {
return this.greatestLowerBound(t) + 1; return this.greatestLowerBound(t) + 1;
} }
};
BI.PrefixIntervalTree.uniform = function (size, initialValue) {
var xs = [];
for (var i = size - 1; i >= 0; --i) {
xs[i] = initialValue;
}
return new BI.PrefixIntervalTree(xs);
};
BI.PrefixIntervalTree.empty = function (size) {
return BI.PrefixIntervalTree.uniform(size, 0);
};
})(); }

93
src/core/structure/queue.js

@ -1,89 +1,86 @@
import {contains, remove} from "../2.base";
!(function () { export class Queue {
BI.Queue = function (capacity) { constructor(capacity) {
this.capacity = capacity; this.capacity = capacity;
this.array = []; this.array = [];
}; }
BI.Queue.prototype = {
constructor: BI.Queue,
contains: function (v) { contains(v) {
return BI.contains(this.array, v); return contains(this.array, v);
}, }
indexOf: function (v) { indexOf(v) {
return BI.contains(this.array, v); return contains(this.array, v);
}, }
getElementByIndex: function (index) { getElementByIndex(index) {
return this.array[index]; return this.array[index];
}, }
push: function (v) { push(v) {
this.array.push(v); this.array.push(v);
if (this.capacity && this.array.length > this.capacity) { if (this.capacity && this.array.length > this.capacity) {
this.array.shift(); this.array.shift();
} }
}, }
pop: function () { pop() {
this.array.pop(); this.array.pop();
}, }
shift: function () { shift() {
this.array.shift(); this.array.shift();
}, }
unshift: function (v) { unshift(v) {
this.array.unshift(v); this.array.unshift(v);
if (this.capacity && this.array.length > this.capacity) { if (this.capacity && this.array.length > this.capacity) {
this.array.pop(); this.array.pop();
} }
}, }
remove: function (v) { remove(v) {
BI.remove(this.array, v); remove(this.array, v);
}, }
splice: function () { splice() {
this.array.splice.apply(this.array, arguments); this.array.splice.apply(this.array, arguments);
}, }
slice: function () { slice() {
this.array.slice.apply(this.array, arguments); this.array.slice.apply(this.array, arguments);
}, }
size: function () { size() {
return this.array.length; return this.array.length;
}, }
each: function (fn, scope) { each(fn, scope) {
var scope = scope || window; scope = scope || window;
var fn = fn || null; fn = fn || null;
if (fn == null || typeof (fn) !== "function") { if (fn == null || typeof (fn) !== "function") {
return; return;
} }
for (var i = 0; i < this.array.length; i++) { for (let i = 0; i < this.array.length; i++) {
var re = fn.call(scope, i, this.array[i], this.array); const re = fn.call(scope, i, this.array[i], this.array);
if (re == false) { if (re === false) {
break; break;
} }
} }
}, }
toArray: function () { toArray() {
return this.array; return this.array;
}, }
fromArray: function (array) { fromArray(array) {
var self = this; array.each(v => this.push(v));
BI.each(array, function (i, v) { }
self.push(v);
});
},
clear: function () { clear() {
this.array.length = 0; this.array.length = 0;
} }
}; }
})();

79
src/core/structure/sectionManager.js

@ -1,5 +1,7 @@
!(function () { import {each, keys, map, size} from "../2.base";
var Section = function (height, width, x, y) {
class Section {
constructor(height, width, x, y) {
this.height = height; this.height = height;
this.width = width; this.width = width;
this.x = x; this.x = x;
@ -7,60 +9,58 @@
this._indexMap = {}; this._indexMap = {};
this._indices = []; this._indices = [];
}; }
Section.prototype = { addCellIndex(index) {
constructor: Section,
addCellIndex: function (index) {
if (!this._indexMap[index]) { if (!this._indexMap[index]) {
this._indexMap[index] = true; this._indexMap[index] = true;
this._indices.push(index); this._indices.push(index);
} }
}, }
getCellIndices: function () { getCellIndices() {
return this._indices; return this._indices;
} }
}; }
var SECTION_SIZE = 100; const SECTION_SIZE = 100;
BI.SectionManager = function (sectionSize) {
this._sectionSize = sectionSize || SECTION_SIZE; export class SectionManager {
constructor(sectionSize = SECTION_SIZE) {
this._sectionSize = sectionSize;
this._cellMetadata = []; this._cellMetadata = [];
this._sections = {}; this._sections = {};
}; }
BI.SectionManager.prototype = { getCellIndices(height, width, x, y) {
constructor: BI.SectionManager, const indices = {};
getCellIndices: function (height, width, x, y) {
var indices = {};
BI.each(this.getSections(height, width, x, y), function (i, section) { each(this.getSections(height, width, x, y), function (i, section) {
BI.each(section.getCellIndices(), function (j, index) { each(section.getCellIndices(), function (j, index) {
indices[index] = index; indices[index] = index;
}); });
}); });
return BI.map(BI.keys(indices), function (i, index) { return map(keys(indices), function (i, index) {
return indices[index]; return indices[index];
}); });
}, }
getCellMetadata: function (index) { getCellMetadata(index) {
return this._cellMetadata[index]; return this._cellMetadata[index];
}, }
getSections: function (height, width, x, y) { getSections(height, width, x, y) {
var sectionXStart = Math.floor(x / this._sectionSize); const sectionXStart = Math.floor(x / this._sectionSize);
var sectionXStop = Math.floor((x + width - 1) / this._sectionSize); const sectionXStop = Math.floor((x + width - 1) / this._sectionSize);
var sectionYStart = Math.floor(y / this._sectionSize); const sectionYStart = Math.floor(y / this._sectionSize);
var sectionYStop = Math.floor((y + height - 1) / this._sectionSize); const sectionYStop = Math.floor((y + height - 1) / this._sectionSize);
var sections = []; const sections = [];
for (var sectionX = sectionXStart; sectionX <= sectionXStop; sectionX++) { for (let sectionX = sectionXStart; sectionX <= sectionXStop; sectionX++) {
for (var sectionY = sectionYStart; sectionY <= sectionYStop; sectionY++) { for (let sectionY = sectionYStart; sectionY <= sectionYStop; sectionY++) {
var key = sectionX + "." + sectionY; const key = sectionX + "." + sectionY;
if (!this._sections[key]) { if (!this._sections[key]) {
this._sections[key] = new Section(this._sectionSize, this._sectionSize, sectionX * this._sectionSize, sectionY * this._sectionSize); this._sections[key] = new Section(this._sectionSize, this._sectionSize, sectionX * this._sectionSize, sectionY * this._sectionSize);
@ -71,18 +71,17 @@
} }
return sections; return sections;
}, }
getTotalSectionCount: function () { getTotalSectionCount() {
return BI.size(this._sections); return size(this._sections);
}, }
registerCell: function (cellMetadatum, index) { registerCell(cellMetadatum, index) {
this._cellMetadata[index] = cellMetadatum; this._cellMetadata[index] = cellMetadatum;
BI.each(this.getSections(cellMetadatum.height, cellMetadatum.width, cellMetadatum.x, cellMetadatum.y), function (i, section) { each(this.getSections(cellMetadatum.height, cellMetadatum.width, cellMetadatum.x, cellMetadatum.y), function (i, section) {
section.addCellIndex(index); section.addCellIndex(index);
}); });
} }
}; }
})();

578
src/core/structure/tree.js

@ -1,125 +1,263 @@
(function () { import {
BI.Tree = function () { isObject,
this.root = new BI.Node(BI.UUID()); UUID,
}; extend,
isEmpty,
BI.Tree.prototype = { isArray,
constructor: BI.Tree, first,
addNode: function (node, newNode, index) { last,
if (BI.isNull(newNode)) { findIndex,
isUndefined,
isNull,
each,
deepClone,
isEqual, some, every, clone
} from "../2.base";
export class Node {
constructor(id) {
if (isObject(id)) {
extend(this, id);
} else {
this.id = id;
}
this.clear();
}
set(key, value) {
if (isObject(key)) {
extend(this, key);
return;
}
this[key] = value;
}
get(key) {
return this[key];
}
isLeaf() {
return isEmpty(this.children);
}
getChildren() {
return this.children;
}
getChildrenLength() {
return this.children.length;
}
getFirstChild() {
return first(this.children);
}
getLastChild() {
return last(this.children);
}
setLeft(left) {
this.left = left;
}
getLeft() {
return this.left;
}
setRight(right) {
this.right = right;
}
getRight() {
return this.right;
}
setParent(parent) {
this.parent = parent;
}
getParent() {
return this.parent;
}
getChild(index) {
return this.children[index];
}
getChildIndex(id) {
return findIndex(this.children, function (i, ch) {
return ch.get("id") === id;
});
}
removeChild(id) {
this.removeChildByIndex(this.getChildIndex(id));
}
removeChildByIndex(index) {
const before = this.getChild(index - 1);
const behind = this.getChild(index + 1);
if (before != null) {
before.setRight(behind || null);
}
if (behind != null) {
behind.setLeft(before || null);
}
this.children.splice(index, 1);
}
removeAllChilds() {
this.children = [];
}
addChild(child, index) {
let cur = null;
if (isUndefined(index)) {
cur = this.children.length - 1;
} else {
cur = index - 1;
}
child.setParent(this);
if (cur >= 0) {
this.getChild(cur) && this.getChild(cur).setRight(child);
child.setLeft(this.getChild(cur));
}
if (isUndefined(index)) {
this.children.push(child);
} else {
this.children.splice(index, 0, child);
}
}
equals(obj) {
return this === obj || this.id === obj.id;
}
clear() {
this.parent = null;
this.left = null;
this.right = null;
this.children = [];
}
}
export class Tree {
constructor() {
this.root = new Node(UUID());
}
addNode(node, newNode, index) {
if (isNull(newNode)) {
this.root.addChild(node, index); this.root.addChild(node, index);
} else if (BI.isNull(node)) { } else if (isNull(node)) {
this.root.addChild(newNode, index); this.root.addChild(newNode, index);
} else { } else {
node.addChild(newNode, index); node.addChild(newNode, index);
} }
}, }
isRoot: function (node) { isRoot(node) {
return node === this.root; return node === this.root;
}, }
getRoot: function () { getRoot() {
return this.root; return this.root;
}, }
clear: function () { clear() {
this.root.clear(); this.root.clear();
}, }
initTree: function (nodes) { initTree(nodes) {
var self = this;
this.clear(); this.clear();
var queue = []; const queue = [];
BI.each(nodes, function (i, node) { each(nodes, (i, node) => {
var n = new BI.Node(node); const n = new Node(node);
n.set("data", node); n.set("data", node);
self.addNode(n); this.addNode(n);
queue.push(n); queue.push(n);
}); });
while (!BI.isEmpty(queue)) { while (!isEmpty(queue)) {
var parent = queue.shift(); const parent = queue.shift();
var node = parent.get("data"); const node = parent.get("data");
BI.each(node.children, function (i, child) { each(node.children, (i, child) => {
var n = new BI.Node(child); const n = new Node(child);
n.set("data", child); n.set("data", child);
queue.push(n); queue.push(n);
self.addNode(parent, n); this.addNode(parent, n);
}); });
} }
}, }
_toJSON: function (node) { _toJSON(node) {
var self = this; const children = [];
var children = []; each(node.getChildren(), (i, child) => {
BI.each(node.getChildren(), function (i, child) { children.push(this._toJSON(child));
children.push(self._toJSON(child));
}); });
return BI.extend({ return extend({
id: node.id id: node.id,
}, BI.deepClone(node.get("data")), (children.length > 0 ? { }, deepClone(node.get("data")), (children.length > 0 ? {
children: children children: children,
} : {})); } : {}));
}, }
toJSON: function (node) { toJSON(node) {
var self = this, result = []; const result = [];
BI.each((node || this.root).getChildren(), function (i, child) { each((node || this.root).getChildren(), (i, child) => {
result.push(self._toJSON(child)); result.push(this._toJSON(child));
}); });
return result; return result;
}, }
_toJSONWithNode: function (node) { _toJSONWithNode(node) {
var self = this; const children = [];
var children = []; each(node.getChildren(), (i, child) => {
BI.each(node.getChildren(), function (i, child) { children.push(this._toJSONWithNode(child));
children.push(self._toJSONWithNode(child));
}); });
return BI.extend({ return extend({
id: node.id id: node.id,
}, BI.deepClone(node.get("data")), { }, deepClone(node.get("data")), {
node: node node: node,
}, (children.length > 0 ? { }, (children.length > 0 ? {
children: children children: children,
} : {})); } : {}));
}, }
toJSONWithNode: function (node) { toJSONWithNode(node) {
var self = this, result = []; const result = [];
BI.each((node || this.root).getChildren(), function (i, child) { each((node || this.root).getChildren(), (i, child) => {
result.push(self._toJSONWithNode(child)); result.push(this._toJSONWithNode(child));
}); });
return result; return result;
}, }
search: function (root, target, param) { search(root, target, param) {
if (!(root instanceof BI.Node)) { if (!(root instanceof Node)) {
return arguments.callee.apply(this, [this.root, root, target]); return this.search(this.root, root, target);
} }
var self = this, next = null; let next = null;
if (BI.isNull(target)) { if (isNull(target)) {
return null; return null;
} }
if (BI.isEqual(root[param || "id"], target)) { if (isEqual(root[param || "id"], target)) {
return root; return root;
} }
BI.any(root.getChildren(), function (i, child) { some(root.getChildren(), (i, child) => {
next = self.search(child, target, param); next = this.search(child, target, param);
if (null !== next) { if (null !== next) {
return true; return true;
} }
}); });
return next; return next;
}, }
_traverse: function (node, callback) { _traverse(node, callback) {
var queue = []; let queue = [];
queue.push(node); queue.push(node);
while (!BI.isEmpty(queue)) { while (!isEmpty(queue)) {
var temp = queue.shift(); const temp = queue.shift();
var b = callback && callback(temp); const b = callback && callback(temp);
if (b === false) { if (b === false) {
break; break;
} }
@ -130,51 +268,50 @@
queue = queue.concat(temp.getChildren()); queue = queue.concat(temp.getChildren());
} }
} }
}, }
traverse: function (callback) { traverse(callback) {
this._traverse(this.root, callback); this._traverse(this.root, callback);
}, }
_recursion: function (node, route, callback) { _recursion(node, route, callback) {
var self = this; return every(node.getChildren(), (i, child) => {
return BI.every(node.getChildren(), function (i, child) { const next = clone(route);
var next = BI.clone(route);
next.push(child.id); next.push(child.id);
var b = callback && callback(child, next); const b = callback && callback(child, next);
if (b === false) { if (b === false) {
return false; return false;
} }
if (b === true) { if (b === true) {
return true; return true;
} }
return self._recursion(child, next, callback); return this._recursion(child, next, callback);
}); });
}, }
recursion: function (callback) { recursion(callback) {
this._recursion(this.root, [], callback); this._recursion(this.root, [], callback);
}, }
inOrderTraverse: function (callback) { inOrderTraverse(callback) {
this._inOrderTraverse(this.root, callback); this._inOrderTraverse(this.root, callback);
}, }
// 中序遍历(递归) // 中序遍历(递归)
_inOrderTraverse: function (node, callback) { _inOrderTraverse(node, callback) {
if (node != null) { if (node != null) {
this._inOrderTraverse(node.getLeft()); this._inOrderTraverse(node.getLeft());
callback && callback(node); callback && callback(node);
this._inOrderTraverse(node.getRight()); this._inOrderTraverse(node.getRight());
} }
}, }
// 中序遍历(非递归) // 中序遍历(非递归)
nrInOrderTraverse: function (callback) { nrInOrderTraverse(callback) {
var stack = []; const stack = [];
var node = this.root; let node = this.root;
while (node != null || !BI.isEmpty(stack)) { while (node != null || !isEmpty(stack)) {
while (node != null) { while (node != null) {
stack.push(node); stack.push(node);
node = node.getLeft(); node = node.getLeft();
@ -183,28 +320,28 @@
callback && callback(node); callback && callback(node);
node = node.getRight(); node = node.getRight();
} }
}, }
preOrderTraverse: function (callback) { preOrderTraverse(callback) {
this._preOrderTraverse(this.root, callback); this._preOrderTraverse(this.root, callback);
}, }
// 先序遍历(递归) // 先序遍历(递归)
_preOrderTraverse: function (node, callback) { _preOrderTraverse(node, callback) {
if (node != null) { if (node != null) {
callback && callback(node); callback && callback(node);
this._preOrderTraverse(node.getLeft()); this._preOrderTraverse(node.getLeft());
this._preOrderTraverse(node.getRight()); this._preOrderTraverse(node.getRight());
} }
}, }
// 先序遍历(非递归) // 先序遍历(非递归)
nrPreOrderTraverse: function (callback) { nrPreOrderTraverse(callback) {
var stack = []; const stack = [];
var node = this.root; let node = this.root;
while (node != null || !BI.isEmpty(stack)) { while (node != null || !isEmpty(stack)) {
while (node != null) { while (node != null) {
callback && callback(node); callback && callback(node);
@ -214,38 +351,38 @@
node = stack.pop(); node = stack.pop();
node = node.getRight(); node = node.getRight();
} }
}, }
postOrderTraverse: function (callback) { postOrderTraverse(callback) {
this._postOrderTraverse(this.root, callback); this._postOrderTraverse(this.root, callback);
}, }
// 后序遍历(递归) // 后序遍历(递归)
_postOrderTraverse: function (node, callback) { _postOrderTraverse(node, callback) {
if (node != null) { if (node != null) {
this._postOrderTraverse(node.getLeft()); this._postOrderTraverse(node.getLeft());
this._postOrderTraverse(node.getRight()); this._postOrderTraverse(node.getRight());
callback && callback(node); callback && callback(node);
} }
}, }
// 后续遍历(非递归) // 后续遍历(非递归)
nrPostOrderTraverse: function (callback) { nrPostOrderTraverse(callback) {
var stack = []; const stack = [];
var node = this.root; let node = this.root;
var preNode = null;// 表示最近一次访问的节点 let preNode = null;// 表示最近一次访问的节点
while (node != null || !BI.isEmpty(stack)) { while (node != null || !isEmpty(stack)) {
while (node != null) { while (node != null) {
stack.push(node); stack.push(node);
node = node.getLeft(); node = node.getLeft();
} }
node = BI.last(stack); node = last(stack);
if (node.getRight() == null || node.getRight() == preNode) { if (node.getRight() == null || node.getRight() === preNode) {
callback && callback(node); callback && callback(node);
node = stack.pop(); node = stack.pop();
preNode = node; preNode = node;
@ -255,203 +392,72 @@
} }
} }
} }
};
BI.Node = function (id) {
if (BI.isObject(id)) {
BI.extend(this, id);
} else {
this.id = id;
}
this.clear.apply(this, arguments);
};
BI.Node.prototype = {
constructor: BI.Node,
set: function (key, value) {
if (BI.isObject(key)) {
BI.extend(this, key);
return;
}
this[key] = value;
},
get: function (key) {
return this[key];
},
isLeaf: function () {
return BI.isEmpty(this.children);
},
getChildren: function () {
return this.children;
},
getChildrenLength: function () {
return this.children.length;
},
getFirstChild: function () {
return BI.first(this.children);
},
getLastChild: function () {
return BI.last(this.children);
},
setLeft: function (left) {
this.left = left;
},
getLeft: function () {
return this.left;
},
setRight: function (right) {
this.right = right;
},
getRight: function () {
return this.right;
},
setParent: function (parent) {
this.parent = parent;
},
getParent: function () {
return this.parent;
},
getChild: function (index) {
return this.children[index];
},
getChildIndex: function (id) {
return BI.findIndex(this.children, function (i, ch) {
return ch.get("id") === id;
});
},
removeChild: function (id) {
this.removeChildByIndex(this.getChildIndex(id));
},
removeChildByIndex: function (index) {
var before = this.getChild(index - 1);
var behind = this.getChild(index + 1);
if (before != null) {
before.setRight(behind || null);
}
if (behind != null) {
behind.setLeft(before || null);
}
this.children.splice(index, 1);
},
removeAllChilds: function () {
this.children = [];
},
addChild: function (child, index) {
var cur = null;
if (BI.isUndefined(index)) {
cur = this.children.length - 1;
} else {
cur = index - 1;
}
child.setParent(this);
if (cur >= 0) {
this.getChild(cur) && this.getChild(cur).setRight(child);
child.setLeft(this.getChild(cur));
}
if (BI.isUndefined(index)) {
this.children.push(child);
} else {
this.children.splice(index, 0, child);
}
},
equals: function (obj) {
return this === obj || this.id === obj.id;
},
clear: function () { static transformToArrayFormat(nodes, pId, childKey) {
this.parent = null;
this.left = null;
this.right = null;
this.children = [];
}
};
BI.extend(BI.Tree, {
transformToArrayFormat: function (nodes, pId, childKey) {
if (!nodes) return []; if (!nodes) return [];
var r = []; let r = [];
childKey = childKey || "children"; childKey = childKey || "children";
if (BI.isArray(nodes)) { if (isArray(nodes)) {
for (var i = 0, l = nodes.length; i < l; i++) { for (let i = 0, l = nodes.length; i < l; i++) {
var node = BI.clone(nodes[i]); const node = clone(nodes[i]);
node.pId = node.pId == null ? pId : node.pId; node.pId = node.pId == null ? pId : node.pId;
delete node.children; delete node.children;
r.push(node); r.push(node);
if (nodes[i][childKey]) { if (nodes[i][childKey]) {
r = r.concat(BI.Tree.transformToArrayFormat(nodes[i][childKey], node.id)); r = r.concat(Tree.transformToArrayFormat(nodes[i][childKey], node.id));
} }
} }
} else { } else {
var newNodes = BI.clone(nodes); const newNodes = clone(nodes);
newNodes.pId = newNodes.pId == null ? pId : newNodes.pId; newNodes.pId = newNodes.pId == null ? pId : newNodes.pId;
delete newNodes.children; delete newNodes.children;
r.push(newNodes); r.push(newNodes);
if (nodes[childKey]) { if (nodes[childKey]) {
r = r.concat(BI.Tree.transformToArrayFormat(nodes[childKey], newNodes.id)); r = r.concat(Tree.transformToArrayFormat(nodes[childKey], newNodes.id));
} }
} }
return r; return r;
}, }
arrayFormat: function (nodes, pId) { static arrayFormat(nodes, pId) {
if (!nodes) { if (!nodes) {
return []; return [];
} }
var r = []; let r = [];
if (BI.isArray(nodes)) { if (isArray(nodes)) {
for (var i = 0, l = nodes.length; i < l; i++) { for (let i = 0, l = nodes.length; i < l; i++) {
var node = nodes[i]; const node = nodes[i];
node.pId = node.pId == null ? pId : node.pId; node.pId = node.pId == null ? pId : node.pId;
r.push(node); r.push(node);
if (nodes[i]["children"]) { if (nodes[i]["children"]) {
r = r.concat(BI.Tree.arrayFormat(nodes[i]["children"], node.id)); r = r.concat(Tree.arrayFormat(nodes[i]["children"], node.id));
} }
} }
} else { } else {
var newNodes = nodes; const newNodes = nodes;
newNodes.pId = newNodes.pId == null ? pId : newNodes.pId; newNodes.pId = newNodes.pId == null ? pId : newNodes.pId;
r.push(newNodes); r.push(newNodes);
if (nodes["children"]) { if (nodes["children"]) {
r = r.concat(BI.Tree.arrayFormat(nodes["children"], newNodes.id)); r = r.concat(Tree.arrayFormat(nodes["children"], newNodes.id));
} }
} }
return r; return r;
}, }
transformToTreeFormat: function (sNodes) { static transformToTreeFormat(sNodes) {
var i, l; let i, l;
if (!sNodes) { if (!sNodes) {
return []; return [];
} }
if (BI.isArray(sNodes)) { if (isArray(sNodes)) {
var r = []; const r = [];
var tmpMap = {}; const tmpMap = {};
for (i = 0, l = sNodes.length; i < l; i++) { for (i = 0, l = sNodes.length; i < l; i++) {
if (BI.isNull(sNodes[i].id)) { if (isNull(sNodes[i].id)) {
return sNodes; return sNodes;
} }
tmpMap[sNodes[i].id] = BI.clone(sNodes[i]); tmpMap[sNodes[i].id] = clone(sNodes[i]);
} }
for (i = 0, l = sNodes.length; i < l; i++) { for (i = 0, l = sNodes.length; i < l; i++) {
if (tmpMap[sNodes[i].pId] && sNodes[i].id !== sNodes[i].pId) { if (tmpMap[sNodes[i].pId] && sNodes[i].id !== sNodes[i].pId) {
@ -468,19 +474,19 @@
} }
return [sNodes]; return [sNodes];
}, }
treeFormat: function (sNodes) { static treeFormat(sNodes) {
var i, l; let i, l;
if (!sNodes) { if (!sNodes) {
return []; return [];
} }
if (BI.isArray(sNodes)) { if (isArray(sNodes)) {
var r = []; const r = [];
var tmpMap = {}; const tmpMap = {};
for (i = 0, l = sNodes.length; i < l; i++) { for (i = 0, l = sNodes.length; i < l; i++) {
if (BI.isNull(sNodes[i].id)) { if (isNull(sNodes[i].id)) {
return sNodes; return sNodes;
} }
tmpMap[sNodes[i].id] = sNodes[i]; tmpMap[sNodes[i].id] = sNodes[i];
@ -499,19 +505,17 @@
} }
return [sNodes]; return [sNodes];
}, }
traversal: function (array, callback, pNode) { static traversal(array, callback, pNode) {
if (BI.isNull(array)) { if (isNull(array)) {
return; return;
} }
var self = this; some(array, (i, item) => {
BI.some(array, function (i, item) {
if (callback(i, item, pNode) === false) { if (callback(i, item, pNode) === false) {
return true; return true;
} }
self.traversal(item.children, callback, item); this.traversal(item.children, callback, item);
}); });
} }
}); }
})();

49
src/core/structure/vector.js

@ -1,27 +1,29 @@
// 向量操作 // 向量操作
BI.Vector = function (x, y) { export class Vector {
constructor(x, y) {
this.x = x; this.x = x;
this.y = y; this.y = y;
}; }
BI.Vector.prototype = {
constructor: BI.Vector, cross(v) {
cross: function (v) {
return (this.x * v.y - this.y * v.x); return (this.x * v.y - this.y * v.x);
}, }
length: function (v) {
length(v) {
return (Math.sqrt(this.x * v.x + this.y * v.y)); return (Math.sqrt(this.x * v.x + this.y * v.y));
} }
}; }
BI.Region = function (x, y, w, h) {
export class Region {
constructor(x, y, w, h) {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.w = w; this.w = w;
this.h = h; this.h = h;
}; }
BI.Region.prototype = {
constructor: BI.Region,
// 判断两个区域是否相交,若相交,则要么顶点互相包含,要么矩形边界(或对角线)相交 // 判断两个区域是否相交,若相交,则要么顶点互相包含,要么矩形边界(或对角线)相交
isIntersects: function (obj) { isIntersects(obj) {
if (this.isPointInside(obj.x, obj.y) || if (this.isPointInside(obj.x, obj.y) ||
this.isPointInside(obj.x + obj.w, obj.y) || this.isPointInside(obj.x + obj.w, obj.y) ||
this.isPointInside(obj.x, obj.y + obj.h) || this.isPointInside(obj.x, obj.y + obj.h) ||
@ -34,17 +36,18 @@ BI.Region.prototype = {
return true; return true;
} else if (obj.x != null && obj.y != null)// 判断矩形对角线相交 |v1 X v2||v1 X v3| < 0 } else if (obj.x != null && obj.y != null)// 判断矩形对角线相交 |v1 X v2||v1 X v3| < 0
{ {
var vector1 = new BI.Vector(this.w, this.h);// 矩形对角线向量 const vector1 = new Vector(this.w, this.h);// 矩形对角线向量
var vector2 = new BI.Vector(obj.x - this.x, obj.y - this.y); const vector2 = new Vector(obj.x - this.x, obj.y - this.y);
var vector3 = new BI.Vector(vector2.x + obj.w, vector2.y + obj.h); const vector3 = new Vector(vector2.x + obj.w, vector2.y + obj.h);
if ((vector1.cross(vector2) * vector1.cross(vector3)) < 0) { if ((vector1.cross(vector2) * vector1.cross(vector3)) < 0) {
return true; return true;
} }
} }
return false; return false;
}, }
// 判断一个点是否在这个区域内部 // 判断一个点是否在这个区域内部
isPointInside: function (x, y) { isPointInside(x, y) {
if (this.x == null || this.y == null) { if (this.x == null || this.y == null) {
return false; return false;
} }
@ -52,12 +55,14 @@ BI.Region.prototype = {
return true; return true;
} }
return false; return false;
}, }
// 返回区域的重心,因为是矩形所以返回中点 // 返回区域的重心,因为是矩形所以返回中点
getPosition: function () { getPosition() {
var pos = []; const pos = [];
pos.push(this.x + this.w / 2); pos.push(this.x + this.w / 2);
pos.push(this.y + this.h / 2); pos.push(this.y + this.h / 2);
return pos; return pos;
} }
}; }

Loading…
Cancel
Save