aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbackend/histplorer.py2
-rw-r--r--src/App.vue14
-rw-r--r--src/components/TimeLine.vue2
-rw-r--r--src/rbtree.ts83
4 files changed, 58 insertions, 43 deletions
diff --git a/backend/histplorer.py b/backend/histplorer.py
index e51a9ff..5282592 100755
--- a/backend/histplorer.py
+++ b/backend/histplorer.py
@@ -27,7 +27,7 @@ from hist_data.cal import gregorianToJdn, jdnToGregorian, jdnToJulian
DB_FILE = 'hist_data/data.db'
MAX_REQ_EVENTS = 100
-DEFAULT_REQ_EVENTS = 10
+DEFAULT_REQ_EVENTS = 20
MAX_REQ_EXCLS = 100
MAX_REQ_SUGGS = 50
DEFAULT_REQ_SUGGS = 5
diff --git a/src/App.vue b/src/App.vue
index abbe2b4..334d75e 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -28,7 +28,7 @@
</template>
<script setup lang="ts">
-import {ref, computed, onMounted, onUnmounted, Ref} from 'vue';
+import {ref, computed, onMounted, onUnmounted, Ref, shallowRef, ShallowRef} from 'vue';
// Components
import TimeLine from './components/TimeLine.vue';
import BaseLine from './components/BaseLine.vue';
@@ -40,7 +40,7 @@ import HelpIcon from './components/icon/HelpIcon.vue';
// Other
import {HistDate, TimelineState, HistEvent, queryServer, HistEventJson, jsonToHistEvent, cmpHistEvent} from './lib';
import {useStore} from './store';
-import {RBTree} from './rbtree';
+import {RBTree, rbtree_shallow_copy} from './rbtree';
// Refs
const contentAreaRef = ref(null as HTMLElement | null);
@@ -100,7 +100,7 @@ function onTimelineRemove(idx: number){
}
// Event data
-const eventTree: Ref<RBTree<HistEvent>> = ref(new RBTree(cmpHistEvent)); // Used to look up events by date range
+const eventTree: ShallowRef<RBTree<HistEvent>> = shallowRef(new RBTree(cmpHistEvent)); // Used to look up events by date range
async function onEventReq(startDate: HistDate, endDate: HistDate){
// Get events from server
let urlParams = new URLSearchParams({type: 'events', range: `${startDate}.${endDate}`, limit: '10'});
@@ -109,9 +109,15 @@ async function onEventReq(startDate: HistDate, endDate: HistDate){
return;
}
// Add to map
+ let added = false;
for (let eventObj of responseObj){
let event = jsonToHistEvent(eventObj);
- eventTree.value.insert(event);
+ let success = eventTree.value.insert(event);
+ added = added || success;
+ }
+ // Notify components if new events were added
+ if (added){
+ eventTree.value = rbtree_shallow_copy(eventTree.value); // Note: triggerRef(eventTree) does not work here
}
}
diff --git a/src/components/TimeLine.vue b/src/components/TimeLine.vue
index 3a5de5b..62780c8 100644
--- a/src/components/TimeLine.vue
+++ b/src/components/TimeLine.vue
@@ -261,7 +261,7 @@ const idToEvent = computed(() => { // Maps visible event IDs to HistEvent, x-pos
// Find events to display, and do basic layouting
let iter = props.eventTree.lowerBound(new HistEvent(0, '', startDate.value));
while (iter.data() != null){
- let event = iter.data();
+ let event = iter.data()!;
iter.next();
if (endDate.value.isEarlier(event.start)){
break;
diff --git a/src/rbtree.ts b/src/rbtree.ts
index b857086..8422dec 100644
--- a/src/rbtree.ts
+++ b/src/rbtree.ts
@@ -40,7 +40,7 @@ class Iterator<T> {
// otherwise, returns next node
next(): T | null{
if (this._cursor === null) {
- let root = this._tree._root;
+ const root = this._tree._root;
if (root !== null) {
this._minNode(root);
}
@@ -68,12 +68,12 @@ class Iterator<T> {
}
}
return this._cursor !== null ? this._cursor.data : null;
- };
+ }
// if null-iterator, returns last node
// otherwise, returns previous node
prev(): T | null {
if(this._cursor === null) {
- let root = this._tree._root;
+ const root = this._tree._root;
if(root !== null) {
this._maxNode(root);
}
@@ -98,21 +98,21 @@ class Iterator<T> {
}
}
return this._cursor !== null ? this._cursor.data : null;
- };
+ }
_minNode(start: Node<T>) {
while(start.left !== null) {
this._ancestors.push(start);
start = start.left;
}
this._cursor = start;
- };
+ }
_maxNode(start: Node<T>) {
while(start.right !== null) {
this._ancestors.push(start);
start = start.right;
}
this._cursor = start;
- };
+ }
}
export class RBTree<T> {
@@ -133,7 +133,7 @@ export class RBTree<T> {
find(data: T): T | null{
let res = this._root;
while (res !== null) {
- let c = this._comparator(data, res.data);
+ const c = this._comparator(data, res.data);
if(c === 0) {
return res.data;
}
@@ -146,9 +146,9 @@ export class RBTree<T> {
// returns iterator to node if found, null otherwise
findIter(data: T): Iterator<T> | null {
let res = this._root;
- let iter = this.iterator();
+ const iter = this.iterator();
while(res !== null) {
- let c = this._comparator(data, res.data);
+ const c = this._comparator(data, res.data);
if(c === 0) {
iter._cursor = res;
return iter;
@@ -159,14 +159,14 @@ export class RBTree<T> {
}
}
return null;
- };
+ }
// Returns an iterator to the tree node at or immediately after the item
lowerBound(item: T): Iterator<T> {
let cur = this._root;
- let iter = this.iterator();
- let cmp = this._comparator;
+ const iter = this.iterator();
+ const cmp = this._comparator;
while(cur !== null) {
- let c = cmp(item, cur.data);
+ const c = cmp(item, cur.data);
if(c === 0) {
iter._cursor = cur;
return iter;
@@ -184,16 +184,16 @@ export class RBTree<T> {
}
iter._ancestors.length = 0;
return iter;
- };
+ }
// Returns an iterator to the tree node immediately after the item
upperBound(item: T): Iterator<T> {
- let iter = this.lowerBound(item);
- let cmp = this._comparator;
+ const iter = this.lowerBound(item);
+ const cmp = this._comparator;
while(iter.data() !== null && cmp(iter.data()!, item) === 0) {
iter.next();
}
return iter;
- };
+ }
// returns null if tree is empty
min(): T | null {
let res = this._root;
@@ -204,7 +204,7 @@ export class RBTree<T> {
res = res.left;
}
return res.data;
- };
+ }
// returns null if tree is empty
max(): T | null {
let res = this._root;
@@ -215,30 +215,32 @@ export class RBTree<T> {
res = res.right;
}
return res.data;
- };
+ }
// returns a null iterator
// call next() or prev() to point to an element
iterator() {
return new Iterator(this);
- };
+ }
// calls cb on each node's data, in order
each(cb: (x: T) => boolean) {
- let it=this.iterator(), data;
+ const it = this.iterator();
+ let data: T | null;
while((data = it.next()) !== null) {
if(cb(data) === false) {
return;
}
}
- };
+ }
// calls cb on each node's data, in reverse order
reach(cb: (x: T) => boolean) {
- var it=this.iterator(), data;
+ const it=this.iterator();
+ let data: T | null;
while((data = it.prev()) !== null) {
if(cb(data) === false) {
return;
}
}
- };
+ }
// returns true if inserted, false if duplicate
insert(data: T): boolean {
let ret = false;
@@ -249,7 +251,7 @@ export class RBTree<T> {
this.size++;
}
else {
- let head = new Node(undefined) as Node<T>; // fake tree root
+ const head = new Node(undefined) as Node<T>; // fake tree root
let dir = false;
let last = false;
// setup
@@ -275,7 +277,7 @@ export class RBTree<T> {
}
// fix red violation
if(is_red(node) && is_red(p)) {
- let dir2 = ggp.right === gp;
+ const dir2 = ggp.right === gp;
if(node === p!.get_child(last)) {
ggp.set_child(dir2, single_rotate(gp!, !last));
}
@@ -283,7 +285,7 @@ export class RBTree<T> {
ggp.set_child(dir2, double_rotate(gp!, !last));
}
}
- let cmp = this._comparator(node.data, data);
+ const cmp = this._comparator(node.data, data);
// stop if found
if(cmp === 0) {
break;
@@ -304,13 +306,13 @@ export class RBTree<T> {
// make root black
this._root!.red = false;
return ret;
- };
+ }
// returns true if removed, false if not found
remove(data: T): boolean {
if(this._root === null) {
return false;
}
- let head = new Node(undefined) as Node<T>; // fake tree root
+ const head = new Node(undefined) as Node<T>; // fake tree root
let node = head;
node.right = this._root;
let p: Node<T> | null = null; // parent
@@ -318,12 +320,12 @@ export class RBTree<T> {
let found: Node<T> | null = null; // found item
let dir = true;
while(node.get_child(dir) !== null) {
- let last = dir;
+ const last = dir;
// update helpers
gp = p;
p = node;
node = node.get_child(dir)!;
- let cmp = this._comparator(data, node.data);
+ const cmp = this._comparator(data, node.data);
dir = cmp > 0;
// save found node
if (cmp === 0) {
@@ -332,12 +334,12 @@ export class RBTree<T> {
// push the red node down
if (!is_red(node) && !is_red(node.get_child(dir))) {
if(is_red(node.get_child(!dir))) {
- let sr = single_rotate(node, dir);
+ const sr = single_rotate(node, dir);
p.set_child(last, sr);
p = sr;
}
else if(!is_red(node.get_child(!dir))) {
- let sibling = p.get_child(!last);
+ const sibling = p.get_child(!last);
if(sibling !== null) {
if(!is_red(sibling.get_child(!last)) && !is_red(sibling.get_child(last))) {
// color flip
@@ -346,7 +348,7 @@ export class RBTree<T> {
node.red = true;
}
else {
- let dir2 = gp!.right === p;
+ const dir2 = gp!.right === p;
if(is_red(sibling.get_child(last))) {
gp!.set_child(dir2, double_rotate(p, last));
}
@@ -354,7 +356,7 @@ export class RBTree<T> {
gp!.set_child(dir2, single_rotate(p, last));
}
// ensure correct coloring
- let gpc = gp!.get_child(dir2)!;
+ const gpc = gp!.get_child(dir2)!;
gpc.red = true;
node.red = true;
gpc.left!.red = false;
@@ -376,7 +378,7 @@ export class RBTree<T> {
this._root.red = false;
}
return found !== null;
- };
+ }
}
function is_red<T>(node: Node<T> | null): boolean {
@@ -384,7 +386,7 @@ function is_red<T>(node: Node<T> | null): boolean {
}
function single_rotate<T>(root: Node<T>, dir: boolean): Node<T> {
- let save = root.get_child(!dir)!;
+ const save = root.get_child(!dir)!;
root.set_child(!dir, save.get_child(dir));
save.set_child(dir, root);
root.red = true;
@@ -396,3 +398,10 @@ function double_rotate<T>(root: Node<T>, dir: boolean): Node<T> {
root.set_child(!dir, single_rotate(root.get_child(!dir)!, !dir));
return single_rotate(root, dir);
}
+
+export function rbtree_shallow_copy<T>(tree: RBTree<T>): RBTree<T> {
+ const newTree = new RBTree(tree._comparator);
+ newTree._root = tree._root;
+ newTree.size = tree.size;
+ return newTree;
+}