@@ -6,123 +6,161 @@ const example = '[0[3216291:t;9219219;4608:s[156546;1612196;219621:~;321965149:4
66export interface ChartPoint {
77 patp: string,
88 dominion: ('l1' | 'l2' | 'spawn'),
9+ picked: boolean,
10+ pickedChildren?: boolean,
11+ pickedSponsees?: boolean,
912 sponsor?: string,
1013 parent?: string,
1114 children?: ChartPoint[],
1215 sponsees?: ChartPoint[],
1316}
1417
15−function parseMetaString(metaString: string): ChartPoint {
16− let idString, subMetaString = '';
17− const colIndex = metaString.indexOf(':');
18− if (colIndex === -1) {
19− idString = metaString;
20− } else {
21− idString = metaString.slice(0, colIndex);
22− subMetaString = metaString.slice(colIndex + 1);
23− }
24− const meta: ChartPoint = {
25− patp: '~' + idString,
26− dominion: 'l1',
18+interface ChartSubs {
19+ children: ChartPoint[],
20+ sponsees: ChartPoint[],
21+}
22+
23+class ChartDataParser {
24+ filter: Set<string>;
25+
26+ constructor(filter: Set<string>) {
27+ this.filter = filter;
2728 }
28− if (subMetaString) {
29− const firstChar = subMetaString[0];
30− if (firstChar === 't') {
31− meta.dominion = 'l2';
32− subMetaString = subMetaString.slice(1);
33− } else if (firstChar === 's') {
34− meta.dominion = 'spawn';
35− subMetaString = subMetaString.slice(1);
29+
30+ parseMetaString(metaString: string): ChartPoint {
31+ let idString, subMetaString = '';
32+ const colIndex = metaString.indexOf(':');
33+ if (colIndex === -1) {
34+ idString = metaString;
35+ } else {
36+ idString = metaString.slice(0, colIndex);
37+ subMetaString = metaString.slice(colIndex + 1);
38+ }
39+ const patp = '~' + idString;
40+ const meta: ChartPoint = {
41+ patp,
42+ picked: !this.filter ? true : (this.filter.has(patp)),
43+ dominion: 'l1',
3644 }
3745 if (subMetaString) {
38− if (subMetaString[0] === '~') {
39− meta.sponsor = null;
40− } else {
41− let [sponsor, parent] = subMetaString.slice(1).split('!');
42− meta.sponsor = '~' + sponsor;
43− meta.parent = '~' + parent;
46+ const firstChar = subMetaString[0];
47+ if (firstChar === 't') {
48+ meta.dominion = 'l2';
49+ subMetaString = subMetaString.slice(1);
50+ } else if (firstChar === 's') {
51+ meta.dominion = 'spawn';
52+ subMetaString = subMetaString.slice(1);
53+ }
54+ if (subMetaString) {
55+ if (subMetaString[0] === '~') {
56+ meta.sponsor = null;
57+ } else {
58+ let [sponsor, parent] = subMetaString.slice(1).split('!');
59+ meta.sponsor = '~' + sponsor;
60+ meta.parent = '~' + parent;
61+ }
4462 }
4563 }
64+ return meta;
4665 }
47− return meta;
48−}
4966
50−function extractMeta(data: string): [ChartPoint, string] {
51− const index = data.search(/[[;]/);
52− if (index === -1) {
53− throw new Error(`No point meta present in ${data}`);
67+ extractMeta(data: string): [ChartPoint, string] {
68+ const index = data.search(/[[;]/);
69+ if (index === -1) {
70+ throw new Error(`No point meta present in ${data}`);
71+ }
72+ const metaString = data.slice(0, index);
73+ data = data.slice(index);
74+ return [this.parseMetaString(metaString), data];
5475 }
55− const metaString = data.slice(0, index);
56− data = data.slice(index);
57− return [parseMetaString(metaString), data];
58−}
5976
60−function extractChildren(data: string, sup: string = undefined): [ChartPoint[], ChartPoint[], string] {
61− if (data[0] === ';') return [[], [], data.slice(1)];
62− if (data[0] !== '[') throw new Error('Invalid children in data: ' + data.slice(0, 20));
77+ extractChildren(data: string, sup: string = undefined): [ChartSubs, string] {
78+ if (data[0] === ';')
79+ return [{
80+ children: [],
81+ sponsees: [],
82+ }, data.slice(1)];
83+ if (data[0] !== '[') throw new Error('Invalid children in data: ' + data.slice(0, 20));
6384
64− let endFound = false;
65− let counter = 0;
66− data = data.slice(1);
67− const children = [];
68− const sponsees = [];
69− while (!endFound && data.length && counter < 20000) {
70− if (data[0] === ']') {
71− endFound = true;
72− data = data.slice(1);
73− } else {
74− let sub;
75− [sub, data] = extractChartPoint(data);
76− if (!sub.parent || sub.parent === sup)
77− children.push(sub);
78− if (sub.sponsor === undefined || sub.sponsor === sup)
79− sponsees.push(sub);
85+ let endFound = false;
86+ let counter = 0;
87+ data = data.slice(1);
88+ const children = [];
89+ const sponsees = [];
90+ while (!endFound && data.length && counter < 20000) {
91+ if (data[0] === ']') {
92+ endFound = true;
93+ data = data.slice(1);
94+ } else {
95+ let sub;
96+ [sub, data] = this.extractChartPoint(data);
97+ if (!sub.parent || sub.parent === sup)
98+ children.push(sub);
99+ if (sub.sponsor === undefined || sub.sponsor === sup)
100+ sponsees.push(sub);
101+ }
102+ counter++;
80103 }
81− counter++;
104+ return [{ children, sponsees }, data];
82105 }
83− return [children, sponsees, data];
84−}
85106
86−function extractChartPoint(data: string): [ChartPoint, string] {
87− let point, children, sponsees;
88− [point, data] = extractMeta(data);
89− [children, sponsees, data] = extractChildren(data, point.patp);
90− point.children = children;
91− point.sponsees = sponsees;
92− return [point, data];
93−}
107+ extractChartPoint(data: string): [ChartPoint, string] {
108+ let point, subs;
109+ [point, data] = this.extractMeta(data);
110+ [subs, data] = this.extractChildren(data, point.patp);
111+ point = {
112+ ...point,
113+ ...subs,
114+ };
115+ return [point, data];
116+ }
94117
95−function linkChartData(points: ChartPoint[], store: any): ChartPoint[] {
96− if (!points) return points;
97− return points.map(point => {
98− if (!store[point.patp]) return point;
99− if (!point.children?.length) {
100− point.children = linkChartData(store[point.patp].children, store);
101− }
102− if (!point.sponsees?.length) {
103− point.sponsees = linkChartData(store[point.patp].sponsees, store);
104− }
105− return point;
106− });
107−}
118+ linkChartData(points: ChartPoint[], store: any): ChartPoint[] {
119+ if (!points) return points;
120+ return points.map(point => {
121+ if (!store[point.patp]) return point;
122+ if (!point.children?.length) {
123+ point.children = this.linkChartData(store[point.patp].children, store);
124+ let picked = point.children.filter(child => child.picked || child.pickedChildren);
125+ point.pickedChildren = picked.length > 0;
126+ }
127+ if (!point.sponsees?.length) {
128+ point.sponsees = this.linkChartData(store[point.patp].sponsees, store);
129+ let picked = point.sponsees.filter(child => child.picked || child.pickedSponsees);
130+ point.pickedSponsees = picked.length > 0;
131+ }
132+ return point;
133+ });
134+ }
108135
109−function _parseChartData(str: string): ChartPoint[] {
110− if (!str) return [];
111− let [baseChildren, _] = extractChildren(str);
112− let store = {};
113− baseChildren.forEach(child => {
114− store[child.patp] = {
115− children: child.children,
116− sponsees: child.sponsees,
117− };
118− });
136+ parse(str: string): ChartSubs {
137+ if (!str) return { children: [], sponsees: [] };
138+ let [{ children: baseChildren }, _] = this.extractChildren(str, undefined);
139+ let store = {};
140+ baseChildren.forEach(child => {
141+ store[child.patp] = {
142+ children: child.children,
143+ sponsees: child.sponsees,
144+ };
145+ });
146+ let base: ChartPoint = {
147+ patp: '~base',
148+ dominion: 'l1',
149+ picked: true,
150+ }
119151
120− return linkChartData(store['~base'].children, store);
152+ let points = this.linkChartData([base], store);
153+ return {
154+ children: points[0].children || [],
155+ sponsees: points[0].sponsees || [],
156+ }
157+ }
121158}
122159
123−export function parseChartData(data: string): ChartPoint[] {
160+export function parseChartData(data: string, filter: Set<string>): ChartSubs {
124161 let start = Date.now();
125− let parsed = _parseChartData(data);
162+ let parser = new ChartDataParser(filter);
163+ let parsed = parser.parse(data);
126164 // console.log(`finished parsing chart data to js object in ${Date.now() - start} ms`);
127165 return parsed;
128166}
@@ -188,16 +226,23 @@ export function arrangePointsInSpirals(
188226 minDistanceBetween,
189227 };
190228}
191−
192−export function populateGraph(g: Graph, chartData: ChartPoint[], bySponsor: boolean, callback?): Graph {
193− if (!(chartData instanceof Array)) return;
229+type childKey = ('sponsees' | 'children');
230+export function populateGraph(g: Graph, chartSubs: ChartSubs, subsKey: childKey, callback?): Graph {
231+ let pickedSubsKey = subsKey == 'children' ? 'pickedChildren' : 'pickedSponsees';
232+ function pickedColor(point: ChartPoint, normal: string) {
233+ return point.picked ? normal : (point[pickedSubsKey] ? colors.SUB_PICKED : colors.NOT_PICKED);
234+ }
235+ function pickedArmColor(point: ChartPoint, normal: string) {
236+ return point[pickedSubsKey] ? normal : colors.NOT_PICKED;
237+ }
238+ let points = chartSubs[subsKey];
239+ if (!(points instanceof Array)) return;
194240 if (!g) {
195241 g = new Graph();
196242 } else {
197243 g.clear();
198244 }
199245
200− let subsKey = bySponsor ? 'sponsees' : 'children';
201246 let sponsorEdges = [];
202247
203248 let offsetX = 0;
@@ -207,7 +252,7 @@ export function populateGraph(g: Graph, chartData: ChartPoint[], bySponsor: bool
207252 let b = 9000000;
208253 let theta = 0;
209254
210− chartData.forEach((galaxy, gi) => {
255+ points.forEach((galaxy, gi) => {
211256 offsetX = 0 + (a + b * theta) * Math.cos(theta);
212257 offsetY = 0 + (a + b * theta) * Math.sin(theta);
213258
@@ -217,7 +262,7 @@ export function populateGraph(g: Graph, chartData: ChartPoint[], bySponsor: bool
217262 g.addNode(gPatp, {
218263 label: gPatp,
219264 size: 3,
220− color: itsYou ? colors.YOU : colors.WHITE,
265+ color: itsYou ? colors.YOU : pickedColor(galaxy, colors.WHITE),
221266 x: offsetX,
222267 y: offsetY,
223268 zIndex: 10,
@@ -242,6 +287,7 @@ export function populateGraph(g: Graph, chartData: ChartPoint[], bySponsor: bool
242287 });
243288 let lastStarArm = null;
244289 let lastStarPatp = null;
290+ let GSarmColor = pickedArmColor(galaxy, colors.LGREY)
245291 stars.forEach((star, si) => {
246292 const sPatp = star.patp;
247293
@@ -256,20 +302,20 @@ export function populateGraph(g: Graph, chartData: ChartPoint[], bySponsor: bool
256302 g.addNode(sPatp, {
257303 label: sPatp,
258304 size: starSize,
259− color: itsYou ? colors.YOU : colors.GOLDT2,
305+ color: itsYou ? colors.YOU : pickedColor(star, colors.GOLDT2),
260306 x: starX,
261307 y: starY,
262308 zIndex: 8,
263309 });
264310 if (lastStarArm == arm) {
265311 g.addEdge(sPatp, lastStarPatp, {
266− color: colors.LGREY,
312+ color: GSarmColor,
267313 size: 0.1,
268314 zIndex: 7,
269315 });
270316 } else {
271317 g.addEdge(sPatp, gPatp, {
272− color: colors.LGREY,
318+ color: GSarmColor,
273319 size: 0.2,
274320 zIndex: 9,
275321 });
@@ -304,7 +350,8 @@ export function populateGraph(g: Graph, chartData: ChartPoint[], bySponsor: bool
304350 });
305351 let lastPlanetArm = null;
306352 let lastPlanetPatp = null;
307− planets.forEach((planet, pi) => {
353+ let SParmColor = pickedArmColor(star, colors.DGREY)
354+ planets.forEach((planet, pi) => {
308355 const pPatp = planet.patp;
309356 const [planetX, planetY] = planetCoords[pi].coords;
310357 const arm = planetCoords[pi].arm;
@@ -319,21 +366,21 @@ export function populateGraph(g: Graph, chartData: ChartPoint[], bySponsor: bool
319366 g.addNode(pPatp, {
320367 label: pPatp,
321368 size: planetSize,
322− color: itsYou ? colors.YOU : (planet.dominion == 'l2' ? colors.GREEN : colors.BLUE),
369+ color: itsYou ? colors.YOU : pickedColor(planet, planet.dominion == 'l2' ? colors.GREEN : colors.BLUE),
323370 x: planetX,
324371 y: planetY,
325372 zIndex: 6,
326373 });
327374 if (lastPlanetArm == arm) {
328375 g.addEdge(pPatp, lastPlanetPatp, {
329− color: colors.DGREY,
376+ color: SParmColor,
330377 size: planetEdgeSize,
331378 zIndex: 5,
332379 });
333380 } else {
334381 if (numPlanetArms == 1) {
335382 g.addEdge(pPatp, sPatp, {
336− color: colors.DGREY,
383+ color: SParmColor,
337384 size: planetEdgeSize,
338385 zIndex: 5,
339386 });