jekyll-bonsai 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +676 -0
  3. data/README.md +2 -6
  4. data/_config.yml +173 -76
  5. data/_data/emoji.yml +45 -0
  6. data/_data/themes.yml +145 -0
  7. data/_includes/anchor-headings.html +5 -1
  8. data/_includes/btn_state.html +14 -0
  9. data/_includes/connect.html +11 -9
  10. data/_includes/cookie-consent.html +79 -0
  11. data/_includes/dates.html +22 -0
  12. data/_includes/hp-tooltip.html +106 -0
  13. data/_includes/img/bullet-net-web.svg +1 -1
  14. data/_includes/img/bullet-tree.svg +1 -1
  15. data/_includes/img/pencil-filter.svg +17 -0
  16. data/_includes/share.html +10 -8
  17. data/_includes/site-nav.html +83 -37
  18. data/_includes/themes.scss.liquid +80 -0
  19. data/_includes/toc.html +187 -0
  20. data/_layouts/404.html +10 -0
  21. data/_layouts/about.html +14 -0
  22. data/_layouts/archive.html +77 -0
  23. data/_layouts/base.html +68 -0
  24. data/_layouts/book.html +49 -0
  25. data/_layouts/entry.html +221 -93
  26. data/_layouts/home.html +96 -0
  27. data/_layouts/post.html +40 -22
  28. data/_layouts/privacy.html +15 -0
  29. data/_layouts/recent.html +65 -0
  30. data/_layouts/state.html +54 -43
  31. data/_sass/base/_code.scss +133 -0
  32. data/_sass/base/_layout.scss +30 -29
  33. data/_sass/base/_link.scss +105 -0
  34. data/_sass/base/_main.scss +19 -126
  35. data/_sass/base/_markdown.scss +281 -0
  36. data/_sass/base/_typography.scss +81 -67
  37. data/_sass/base/code_themes/_gruvbox.scss +92 -0
  38. data/_sass/base/code_themes/_monokai.scss +217 -0
  39. data/_sass/base/code_themes/_solarized.scss +84 -0
  40. data/_sass/components/_btn.scss +95 -0
  41. data/_sass/components/_infobox.scss +48 -0
  42. data/_sass/components/_item.scss +28 -0
  43. data/_sass/components/_search.scss +61 -0
  44. data/_sass/components/_tag_pills.scss +24 -0
  45. data/_sass/components/_visited.scss +42 -0
  46. data/_sass/includes/_anchor_headings.scss +36 -0
  47. data/_sass/includes/_connect.scss +8 -0
  48. data/_sass/includes/_cookie_consent.scss +46 -0
  49. data/_sass/includes/_dates.scss +6 -0
  50. data/_sass/includes/_hp_tooltip.scss +41 -0
  51. data/_sass/includes/_share.scss +10 -0
  52. data/_sass/includes/_site_nav.scss +26 -150
  53. data/_sass/includes/_svg.scss +89 -0
  54. data/_sass/includes/_toc.scss +38 -0
  55. data/_sass/layouts/_404.scss +3 -0
  56. data/_sass/layouts/_about.scss +3 -0
  57. data/_sass/layouts/_archive.scss +26 -0
  58. data/_sass/layouts/_book.scss +17 -0
  59. data/_sass/layouts/_entry.scss +140 -0
  60. data/_sass/layouts/_home.scss +75 -0
  61. data/_sass/layouts/_post.scss +17 -0
  62. data/_sass/layouts/_privacy.scss +3 -0
  63. data/_sass/layouts/_recent.scss +77 -0
  64. data/_sass/layouts/_state.scss +98 -0
  65. data/_sass/main.scss +72 -0
  66. data/_sass/{support → util}/_functions.scss +0 -0
  67. data/_sass/{support → util}/_variables.scss +21 -87
  68. data/_sass/{support → util}/mixins/_buttons.scss +0 -0
  69. data/_sass/util/mixins/_layout.scss +81 -0
  70. data/_sass/{support → util}/mixins/_typography.scss +0 -0
  71. data/assets/css/styles.scss +29 -6
  72. data/assets/img/bonsai-star.png +0 -0
  73. data/assets/img/bonsai-star.svg +1 -0
  74. data/assets/img/nav-base-star.svg +1 -0
  75. data/assets/img/nav-bonsai-star.svg +1 -0
  76. data/assets/js/entry.js +33 -5
  77. data/assets/js/graph.js +21 -509
  78. data/assets/js/scripts.js +41 -57
  79. data/assets/js/search.js +164 -0
  80. data/assets/js/site-nav.js +99 -99
  81. data/assets/js/theme-colors.js +23 -37
  82. data/assets/js/vendor/lunr.js +3475 -0
  83. data/assets/js/vendor/lunr.min.js +6 -0
  84. data/assets/js/visited-nav.js +65 -0
  85. metadata +143 -150
  86. data/_entries/digital-garden.bonsai.md +0 -36
  87. data/_entries/digital-garden.field-logs.md +0 -10
  88. data/_entries/digital-garden.fork.md +0 -10
  89. data/_entries/digital-garden.md +0 -17
  90. data/_entries/digital-garden.path.md +0 -11
  91. data/_entries/digital-garden.plants.md +0 -12
  92. data/_entries/digital-garden.pollinate.md +0 -10
  93. data/_entries/digital-garden.steps.md +0 -10
  94. data/_entries/digital-garden.stream.md +0 -12
  95. data/_entries/digital-garden.sweep.md +0 -12
  96. data/_entries/digital-garden.weather.md +0 -12
  97. data/_entries/features.md +0 -10
  98. data/_entries/features.notes.hover-preview.md +0 -10
  99. data/_entries/features.notes.md +0 -12
  100. data/_entries/features.notes.note-body.md +0 -12
  101. data/_entries/features.notes.note-body.share.md +0 -10
  102. data/_entries/features.notes.note-body.sidenotes.md +0 -52
  103. data/_entries/features.notes.note-foot.links.md +0 -10
  104. data/_entries/features.notes.note-foot.md +0 -11
  105. data/_entries/features.notes.note-foot.posts.md +0 -10
  106. data/_entries/features.notes.note-foot.webmentions.md +0 -10
  107. data/_entries/features.notes.note-head.md +0 -10
  108. data/_entries/features.pages.field-blogs.md +0 -10
  109. data/_entries/features.pages.md +0 -12
  110. data/_entries/features.pages.recent.md +0 -10
  111. data/_entries/features.pages.status-tags.md +0 -10
  112. data/_entries/features.site-nav.graph.links.md +0 -10
  113. data/_entries/features.site-nav.graph.links.namespacing.md +0 -14
  114. data/_entries/features.site-nav.graph.links.wikilinks.md +0 -25
  115. data/_entries/features.site-nav.graph.md +0 -12
  116. data/_entries/features.site-nav.graph.nodes.current-note.md +0 -10
  117. data/_entries/features.site-nav.graph.nodes.md +0 -12
  118. data/_entries/features.site-nav.graph.nodes.mia.missing-note.md +0 -20
  119. data/_entries/features.site-nav.graph.nodes.visited-status.md +0 -10
  120. data/_entries/features.site-nav.graph.toggle-graph.md +0 -13
  121. data/_entries/features.site-nav.graph.type.md +0 -16
  122. data/_entries/features.site-nav.graph.type.net-web.md +0 -10
  123. data/_entries/features.site-nav.graph.type.tree.md +0 -12
  124. data/_entries/features.site-nav.md +0 -10
  125. data/_entries/features.site-nav.visited.md +0 -14
  126. data/_entries/features.tags.md +0 -13
  127. data/_entries/features.themes.dark.md +0 -12
  128. data/_entries/features.themes.light.md +0 -10
  129. data/_entries/features.themes.md +0 -12
  130. data/_entries/features.visited.delete-data.md +0 -10
  131. data/_entries/features.visited.md +0 -12
  132. data/_entries/features.visitor-preferences.md +0 -27
  133. data/_entries/feedback.md +0 -10
  134. data/_entries/people.creator.md +0 -12
  135. data/_entries/people.md +0 -13
  136. data/_entries/people.visitors.md +0 -12
  137. data/_entries/plugins.jekyll-wikilinks.md +0 -10
  138. data/_entries/plugins.md +0 -10
  139. data/_entries/root.md +0 -26
  140. data/_includes/entry-attrs.html +0 -27
  141. data/_includes/head.html +0 -23
  142. data/_includes/hover-preview.html +0 -84
  143. data/_includes/metrics.html +0 -10
  144. data/_includes/styles.scss.liquid +0 -3
  145. data/_layouts/default.html +0 -39
  146. data/_pages/about.md +0 -7
  147. data/_pages/posts.html +0 -19
  148. data/_pages/recent.html +0 -48
  149. data/_plugins/doc_filters.rb +0 -44
  150. data/_plugins/prep_entry.rb +0 -43
  151. data/_plugins/sidenote.rb +0 -123
  152. data/_plugins/tags.rb +0 -52
  153. data/_sass/base/base.scss +0 -3
  154. data/_sass/color/dark.scss +0 -58
  155. data/_sass/color/light.scss +0 -58
  156. data/_sass/includes/_btn.scss +0 -106
  157. data/_sass/includes/_graph.scss +0 -69
  158. data/_sass/includes/_nav.scss +0 -89
  159. data/_sass/includes/_tooltip.scss +0 -29
  160. data/_sass/includes/includes.scss +0 -9
  161. data/_sass/markdown/_code.scss +0 -340
  162. data/_sass/markdown/_content.scss +0 -400
  163. data/_sass/markdown/_tables.scss +0 -60
  164. data/_sass/markdown/markdown.scss +0 -7
  165. data/_sass/modules.scss +0 -14
  166. data/_sass/pages/_index.scss +0 -72
  167. data/_sass/pages/_posts.scss +0 -17
  168. data/_sass/pages/_recent.scss +0 -26
  169. data/_sass/pages/_state.scss +0 -72
  170. data/_sass/pages/pages.scss +0 -4
  171. data/_sass/support/mixins/_layout.scss +0 -56
  172. data/_sass/support/mixins/mixins.scss +0 -3
  173. data/_sass/support/support.scss +0 -3
  174. data/_states/bamboo.md +0 -8
  175. data/_states/berry.md +0 -8
  176. data/_states/bloom.md +0 -8
  177. data/_states/bud.md +0 -6
  178. data/_states/fruit.md +0 -8
  179. data/_states/melon.md +0 -8
  180. data/_states/pot-bamboo.md +0 -8
  181. data/_states/seed.md +0 -8
  182. data/_states/sprout.md +0 -8
  183. data/_states/tags.md +0 -8
  184. data/_states/tea.md +0 -8
  185. data/assets/css/styles-dark.scss +0 -3
  186. data/assets/css/styles-light.scss +0 -3
  187. data/assets/img/nav-dot-dark.svg +0 -1
  188. data/assets/img/nav-dot-light.svg +0 -1
  189. data/assets/img/nav-wiki-links-dark.svg +0 -1
  190. data/assets/img/nav-wiki-links-light.svg +0 -1
  191. data/index.html +0 -82
data/assets/js/graph.js CHANGED
@@ -1,66 +1,51 @@
1
1
  ---
2
2
  ---
3
+ import JekyllGraph from './jekyll-graph.js';
3
4
 
4
- export default class GraphNav {
5
+ export default class GraphNav extends JekyllGraph {
5
6
 
6
7
  constructor() {
7
- // this.graphType set in initGraphType();
8
- this.svgWrapper = document.getElementById('svg-graph');
8
+ super(); // 'this.graph' + 'this.graphDiv' set in JekyllGraph
9
9
  this.graphTypeCheckBox = document.getElementById('graph-type-checkbox');
10
10
  this.graphTypeEmojiSpan = document.getElementById('graph-type-emoji-span');
11
- this.init();
11
+ this.init(); // this.graphType set in initGraphType();
12
12
  }
13
13
 
14
14
  init() {
15
15
  this.initGraphType();
16
16
  this.bindEvents();
17
- this.drawD3Nav();
17
+ this.draw();
18
18
  }
19
19
 
20
20
  bindEvents() {
21
- // listen for draw event (esp. from theme colors)
22
- this.svgWrapper.addEventListener('draw', () => {
23
- this.updateGraphType();
24
- this.drawD3Nav();
25
- });
26
21
  this.graphTypeCheckBox.addEventListener('click', () => {
27
22
  this.updateGraphType();
28
- this.drawD3Nav();
23
+ this.draw();
29
24
  });
30
25
  }
26
+
27
+ // draw
31
28
 
32
- // how to checkbox: https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_display_checkbox_text
33
- drawD3Nav() {
34
- // destroy old chart
35
- d3.select(this.svgWrapper).selectAll('svg > *').remove();
36
-
37
- let theme_attrs = {};
38
- // set theme-dependent graph attributes.
39
- if (document.getElementById('theme-colors-checkbox').checked) {
40
- theme_attrs = {
41
- "name": "dark",
42
- "radius": 2.5,
43
- "missing-radius": 2.5,
44
- }
45
- } else {
46
- theme_attrs = {
47
- "name": "light",
48
- "radius": 3,
49
- "missing-radius": 1.5,
50
- }
51
- }
29
+ draw() {
52
30
  // redraw new chart
53
31
  if (this.graphTypeCheckBox.checked) {
54
- this.drawTree(theme_attrs);
32
+ this.drawTree();
55
33
  } else {
56
- this.drawNetWeb(theme_attrs);
34
+ this.drawNetWeb();
57
35
  }
58
36
  }
37
+
38
+ redraw() {
39
+ this.updateGraphType();
40
+ this.draw();
41
+ }
42
+
43
+ // type
59
44
 
60
45
  initGraphType() {
61
46
  this.graphType = localStorage.getItem('graph-type');
62
47
  if (this.graphType !== "tree" && this.graphType !== "net-web") {
63
- this.graphType = '{{ site.graph_type }}';
48
+ this.graphType = '{{ site.bonsai.nav.graph.type }}';
64
49
  }
65
50
  this.graphTypeCheckBox.checked = (this.graphType === "tree");
66
51
  this.updateGraphType();
@@ -68,485 +53,12 @@ export default class GraphNav {
68
53
 
69
54
  updateGraphType() {
70
55
  if (this.graphTypeCheckBox.checked) {
71
- this.graphTypeEmojiSpan.innerText = "🕸";
56
+ this.graphTypeEmojiSpan.innerText = "{{ site.data.emoji.net-web }}";
72
57
  this.graphType = "tree";
73
58
  } else {
74
- this.graphTypeEmojiSpan.innerText = "🌳";
59
+ this.graphTypeEmojiSpan.innerText = "{{ site.data.emoji.tree }}";
75
60
  this.graphType = "net-web";
76
61
  }
77
62
  localStorage.setItem('graph-type', this.graphType);
78
63
  }
79
-
80
- // d3
81
- drawNetWeb (theme_attrs) {
82
- // d3.json has been async'd: https://stackoverflow.com/questions/49768165/code-within-d3-json-callback-is-not-executed
83
- d3.json("{{ site.baseurl }}/assets/graph-net-web.json")
84
- .then(function(data) {
85
- // console.log('d3 is building a tree');
86
- // console.log(data);
87
- const svgWrapper = document.getElementById('svg-graph');
88
- const width = +svgWrapper.getBoundingClientRect().width / 2;
89
- const height = +svgWrapper.getBoundingClientRect().height / 2;
90
- const svg = d3.select(svgWrapper)
91
- .attr("viewBox", [-width / 2, -height / 2, width, height]);
92
-
93
- const simulation = d3.forceSimulation()
94
- .nodes(data.nodes)
95
- .force("link", d3.forceLink()
96
- .id(function(d) {return d.id;})
97
- .distance(30)
98
- .iterations(1)
99
- .links(data.links))
100
- .force("charge", d3.forceManyBody().strength(-50))
101
- .force("collide", d3.forceCollide())
102
- .force("center", d3.forceCenter())
103
- // see: https://stackoverflow.com/questions/9573178/d3-force-directed-layout-with-bounding-box?answertab=votes#tab-top
104
- // 'center of gravity'
105
- .force("forceX", d3.forceX()
106
- .strength(.3)
107
- .x(.75))
108
- .force("forceY", d3.forceY()
109
- .strength(.1)
110
- .y(.9));
111
-
112
- const link = svg.append("g")
113
- .attr("class", "links")
114
- .selectAll("line")
115
- .data(data.links)
116
- .enter().append("line");
117
-
118
- const node = svg.append('g')
119
- .attr('class', 'nodes')
120
- .selectAll('g')
121
- .data(data.nodes)
122
- .join("g");
123
- // .attr("active", (d) => isCurrentEntryInNetWeb(d) ? true : null)
124
-
125
- node.append('circle')
126
- //svg 2.0 not well-supported: https://stackoverflow.com/questions/47381187/svg-not-working-in-firefox
127
- // add attributes in javascript instead of css.
128
- .attr("r", (d) => isMissingEntryInNetWeb(d) ? theme_attrs["missing-radius"] : theme_attrs["radius"])
129
- .attr("class", nodeTypeInNetWeb)
130
- .on("click", goToEntryFromNetWeb)
131
- .on("mouseover", onMouseover)
132
- .on("mouseout", onMouseout)
133
- .call(d3.drag()
134
- .on("start", dragstarted)
135
- .on("drag", dragged)
136
- .on("end", dragended)
137
- .touchable(true));
138
-
139
- // from: https://stackoverflow.com/questions/28415005/d3-js-selection-conditional-rendering
140
- // use filtering to deal with specific nodes
141
- // from: https://codepen.io/blackjacques/pen/BaaqKpO
142
- // add node pulse on the current node
143
- node.filter( function(d,i) { return isCurrentEntryInNetWeb(d); })
144
- .append("circle")
145
- .attr("r", theme_attrs["radius"])
146
- .classed("pulse", (d) => isCurrentEntryInNetWeb(d) ? true : null)
147
- .on("mouseover", onMouseover)
148
- .on("mouseout", onMouseout)
149
- .call(d3.drag()
150
- .on("start", dragstarted)
151
- .on("drag", dragged)
152
- .on("end", dragended)
153
- .touchable(true));
154
-
155
- node.filter( function(d,i) { return isPostTaggedInNetWeb(d); })
156
- .append("circle")
157
- .attr("r", theme_attrs["radius"])
158
- .classed("pulse-sem-tag", (d) => isPostTaggedInNetWeb(d) ? true : null)
159
- .on("mouseover", onMouseover)
160
- .on("mouseout", onMouseout)
161
- .call(d3.drag()
162
- .on("start", dragstarted)
163
- .on("drag", dragged)
164
- .on("end", dragended)
165
- .touchable(true));
166
-
167
- const text = svg.append('g')
168
- .attr('class', 'text')
169
- .selectAll('text')
170
- .data(data.nodes)
171
- .join("text")
172
- .attr("font-size", "20%")
173
- .attr("dx", 5)
174
- .attr("dy", ".05em")
175
- .text((d) => isMissingEntryInNetWeb(d) ? "Missing Entry" : d.label)
176
- .on("mouseover", onMouseover)
177
- .on("mouseout", onMouseout);
178
-
179
- simulation.on("tick", () => {
180
- link
181
- .attr("x1", function(d) { return d.source.x; })
182
- .attr("y1", function(d) { return d.source.y; })
183
- .attr("x2", function(d) { return d.target.x; })
184
- .attr("y2", function(d) { return d.target.y; });
185
- node
186
- .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
187
- text
188
- .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
189
- });
190
-
191
- //
192
- // helpers
193
- //
194
-
195
- function isCurrentEntryInNetWeb(node) {
196
- return !isMissingEntryInNetWeb(node) && window.location.pathname.includes(node.url);
197
- }
198
-
199
- function isPostTaggedInNetWeb(node) {
200
- // const isPostPage = window.location.pathname.includes("post");
201
- // if (!isPostPage) return false;
202
- const semTags = Array.from(document.getElementsByClassName("sem-tag"));
203
- const tagged = semTags.filter((semTag) =>
204
- !isMissingEntryInNetWeb(node) && semTag.href.includes(node.url)
205
- );
206
- return tagged.length !== 0;
207
- }
208
-
209
- function nodeTypeInNetWeb(node) {
210
- const isVisited = isVisitedEntryInNetWeb(node);
211
- const isMissing = isMissingEntryInNetWeb(node);
212
- if (isVisited) {
213
- return "visited";
214
- } else if (!isVisited && !isMissing) {
215
- return "unvisited";
216
- } else if (isMissing) {
217
- return "missing";
218
- } else {
219
- console.log("WARN: Not a valid node type.");
220
- return null;
221
- }
222
- }
223
-
224
- function isVisitedEntryInNetWeb(node) {
225
- if (!isMissingEntryInNetWeb(node)) {
226
- var visited = JSON.parse(localStorage.getItem('visited'));
227
- for (let i = 0; i < visited.length; i++) {
228
- if (visited[i]['url'] === node.url) return true;
229
- }
230
- }
231
- return false;
232
- }
233
-
234
- function isMissingEntryInNetWeb(node) {
235
- return node.url === '';
236
- }
237
-
238
- // from: https://stackoverflow.com/questions/63693132/unable-to-get-node-datum-on-mouseover-in-d3-v6
239
- // d6 now passes events in vanilla javascript fashion
240
- function goToEntryFromNetWeb (e, d) {
241
- if (!isMissingEntryInNetWeb(d)) {
242
- window.location.href = d.url;
243
- } else {
244
- return null;
245
- }
246
- };
247
-
248
- function onMouseover(e, d) {
249
- const linkedNodesSet = new Set();
250
- data.links
251
- .filter((n) => n.target.id == d.id || n.source.id == d.id)
252
- .forEach((n) => {
253
- linkedNodesSet.add(n.target.id);
254
- linkedNodesSet.add(n.source.id);
255
- });
256
-
257
- node.attr("class", (node_d) => {
258
- if (node_d.id !== d.id && !linkedNodesSet.has(node_d.id)) {
259
- return "inactive";
260
- }
261
- return "active";
262
- });
263
-
264
- link.attr("class", (link_d) => {
265
- if (link_d.source.id !== d.id && link_d.target.id !== d.id) {
266
- return "inactive";
267
- }
268
- return "active";
269
- });
270
-
271
- text.attr("class", (text_d) => {
272
- if (text_d.id !== d.id) {
273
- return "inactive";
274
- }
275
- return "active";
276
- });
277
- };
278
-
279
- function onMouseout(d) {
280
- node.attr("class", "");
281
- link.attr("class", "");
282
- text.attr("class", "");
283
- };
284
-
285
- function dragstarted(event, d) {
286
- if (!event.active) simulation.alphaTarget(0.3).restart();
287
- d.fx = d.x;
288
- d.fy = d.y;
289
- }
290
-
291
- function dragged(event, d) {
292
- d.fx = event.x;
293
- d.fy = event.y;
294
- }
295
-
296
- function dragended(event, d) {
297
- if (!event.active) simulation.alphaTarget(0);
298
- d.fx = null;
299
- d.fy = null;
300
- }
301
- })
302
- .catch(function(error) {
303
- console.log(error);
304
- });
305
- }
306
-
307
- drawTree (theme_attrs) {
308
- // d3.json has been async'd: https://stackoverflow.com/questions/49768165/code-within-d3-json-callback-is-not-executed
309
- d3.json("{{ site.baseurl }}/assets/graph-tree.json")
310
- .then(function(data) {
311
- // console.log('d3 is building a tree');
312
- // console.log(data);
313
- const svgWrapper = document.getElementById('svg-graph');
314
- const width = +svgWrapper.getBoundingClientRect().width / 2;
315
- const height = +svgWrapper.getBoundingClientRect().height / 2;
316
- const svg = d3.select(svgWrapper)
317
- .attr("viewBox", [-width / 2, -height / 2, width, height]);
318
-
319
- const root = d3.hierarchy(data);
320
- const links = root.links();
321
- flatten(root);
322
- const nodes = root.descendants();
323
-
324
- const simulation = d3.forceSimulation(nodes)
325
- .force("link", d3.forceLink(links).id(d => d.id).distance(0).strength(1))
326
- .force("charge", d3.forceManyBody().strength(-50))
327
- .force("collide", d3.forceCollide())
328
- .force("center", d3.forceCenter())
329
- // see: https://stackoverflow.com/questions/9573178/d3-force-directed-layout-with-bounding-box?answertab=votes#tab-top
330
- // 'center of gravity'
331
- .force("forceX", d3.forceX()
332
- .strength(.3)
333
- .x(.9))
334
- .force("forceY", d3.forceY()
335
- .strength(.1)
336
- .y(.9));
337
-
338
- const link = svg.append("g")
339
- .attr("class", "links")
340
- .selectAll("line")
341
- .data(links)
342
- .join("line");
343
-
344
- const node = svg.append('g')
345
- .attr('class', 'nodes')
346
- .selectAll('g')
347
- .data(nodes)
348
- .join("g");
349
-
350
- node.append('circle')
351
- //svg 2.0 not well-supported: https://stackoverflow.com/questions/47381187/svg-not-working-in-firefox
352
- // add attributes in javascript instead of css.
353
- .attr("r", (d) => isMissingEntryInTree(d.data.id) ? theme_attrs["missing-radius"] : theme_attrs["radius"])
354
- .attr("class", nodeTypeInTree)
355
- .on("click", goToEntryFromTree)
356
- .on("mouseover", onMouseover)
357
- .on("mouseout", onMouseout)
358
- // 🐛 bug: this does not work -- it overtakes clicks (extra lines in "tick" are related).
359
- .call(d3.drag()
360
- .on("start", dragstarted)
361
- .on("drag", dragged)
362
- .on("end", dragended)
363
- .touchable(true));
364
-
365
- // from: https://stackoverflow.com/questions/28415005/d3-js-selection-conditional-rendering
366
- // use filtering to deal with specific nodes
367
- // from: https://codepen.io/blackjacques/pen/BaaqKpO
368
- // add node pulse on the current node
369
- node.filter( function(d,i) { return isCurrentEntryInTree(d); })
370
- .append("circle")
371
- .attr("r", (d) => theme_attrs["radius"])
372
- .classed("pulse", true)
373
- .on("mouseover", onMouseover)
374
- .on("mouseout", onMouseout)
375
- .call(d3.drag()
376
- .on("start", dragstarted)
377
- .on("drag", dragged)
378
- .on("end", dragended)
379
- .touchable(true));
380
-
381
- node.filter( function(d,i) { return isPostTaggedInTree(d); })
382
- .append("circle")
383
- .attr("r", theme_attrs["radius"])
384
- .classed("pulse-sem-tag", (d) => isPostTaggedInTree(d) ? true : null)
385
- .on("click", goToEntryFromTree)
386
- .on("mouseover", onMouseover)
387
- .on("mouseout", onMouseout)
388
- .call(d3.drag()
389
- .on("start", dragstarted)
390
- .on("drag", dragged)
391
- .on("end", dragended)
392
- .touchable(true));
393
-
394
- const text = svg.append('g')
395
- .attr('class', 'text')
396
- .selectAll('text')
397
- .data(nodes)
398
- .join("text")
399
- .attr("font-size", "20%")
400
- .attr("dx", 5)
401
- .attr("dy", ".05em")
402
- .text((d) => isMissingEntryInTree(d.data.id) ? "Missing Entry" : d.data.label)
403
- .on("mouseover", onMouseover)
404
- .on("mouseout", onMouseout);
405
-
406
- simulation.on("tick", () => {
407
- // from: https://mbostock.github.io/d3/talk/20110921/parent-foci.html
408
- // preserve hierarchical shape via link positioning
409
- var kx = .2 * simulation.alpha();
410
- var ky = 1.3 * simulation.alpha();
411
- links.forEach(function(d, i) {
412
- d.target.x += (d.source.x - d.target.x) * kx;
413
- d.target.y += (d.source.y + (height * .35) - d.target.y) * ky;
414
- });
415
-
416
- link
417
- .attr("x1", d => d.source.x)
418
- .attr("y1", d => d.source.y)
419
- .attr("x2", d => d.target.x)
420
- .attr("y2", d => d.target.y);
421
- node
422
- .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
423
- text
424
- .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
425
- });
426
-
427
- //
428
- // helpers
429
- //
430
- function isCurrentEntryInTree(node) {
431
- return !isMissingEntryInTree(node.data.id) && window.location.pathname.includes(node.data.url);
432
- }
433
-
434
- function isPostTaggedInTree(node) {
435
- // const isPostPage = window.location.pathname.includes("post");
436
- // if (!isPostPage) return false;
437
- const semTags = Array.from(document.getElementsByClassName("sem-tag"));
438
- const tagged = semTags.filter((semTag) =>
439
- !isMissingEntryInTree(node.data.id) && semTag.href.includes(node.data.url)
440
- );
441
- return tagged.length !== 0;
442
- }
443
-
444
- function nodeTypeInTree(node) {
445
- const isVisited = isVisitedEntryInTree(node);
446
- const isMissing = isMissingEntryInTree(node.data.id);
447
- if (isVisited) {
448
- return "visited";
449
- } else if (!isVisited && !isMissing) {
450
- return "unvisited";
451
- } else if (isMissing) {
452
- return "missing";
453
- } else {
454
- console.log("WARN: Not a valid node type.");
455
- return null;
456
- }
457
- }
458
-
459
- function isVisitedEntryInTree(node) {
460
- var visited = JSON.parse(localStorage.getItem('visited'));
461
- for (let i = 0; i < visited.length; i++) {
462
- if (visited[i]['url'] === node.data.url) {
463
- return true;
464
- }
465
- }
466
- return false;
467
- }
468
-
469
- function isMissingEntryInTree(nodeId) {
470
- return nodeId === "";
471
- }
472
-
473
- // from: https://stackoverflow.com/questions/63693132/unable-to-get-node-datum-on-mouseover-in-d3-v6
474
- // d6 now passes events in vanilla javascript fashion
475
- function goToEntryFromTree(e, d) {
476
- if (!isMissingEntryInTree(d.data.id)) {
477
- window.location.href = d.data.url;
478
- return true;
479
- } else {
480
- return false;
481
- }
482
- };
483
-
484
- function onMouseover(e, d) {
485
- const linkedNodesSet = new Set();
486
- links
487
- .filter((n) => n.target.data.id == d.data.id || n.source.data.id == d.data.id)
488
- .forEach((n) => {
489
- linkedNodesSet.add(n.target.data.id);
490
- linkedNodesSet.add(n.source.data.id);
491
- });
492
-
493
- node.attr("class", (node_d) => {
494
- if (node_d.data.id !== d.data.id && !linkedNodesSet.has(node_d.data.id)) {
495
- return "inactive";
496
- }
497
- return "active";
498
- });
499
-
500
- link.attr("class", (link_d) => {
501
- if (link_d.source.data.id !== d.data.id && link_d.target.data.id !== d.data.id) {
502
- return "inactive";
503
- }
504
- return "active";
505
- });
506
-
507
- text.attr("class", (text_d) => {
508
- if (text_d.data.id !== d.data.id) {
509
- return "inactive";
510
- }
511
- return "active";
512
- });
513
- };
514
-
515
- function onMouseout(d) {
516
- node.attr("class", "");
517
- link.attr("class", "");
518
- text.attr("class", "");
519
- };
520
-
521
- function dragstarted(event, d) {
522
- if (!event.active) simulation.alphaTarget(0.3).restart();
523
- d.fx = d.x;
524
- d.fy = d.y;
525
- }
526
-
527
- function dragged(event, d) {
528
- d.fx = event.x;
529
- d.fy = event.y;
530
- }
531
-
532
- function dragended(event, d) {
533
- if (!event.active) simulation.alphaTarget(0);
534
- d.fx = null;
535
- d.fy = null;
536
- }
537
-
538
- function flatten(root) {
539
- var nodes = [];
540
- function recurse(node) {
541
- if (node.descendents) node.descendents.forEach(recurse);
542
- nodes.push(node);
543
- }
544
- recurse(root);
545
- return nodes;
546
- }
547
- })
548
- .catch(function(error) {
549
- console.log(error);
550
- });
551
- }
552
64
  }