decidim-assemblies 0.24.3 → 0.25.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/assemblies/assembly_m_cell.rb +1 -1
  3. data/app/cells/decidim/assemblies/assembly_member/show.erb +1 -1
  4. data/app/cells/decidim/assemblies/content_blocks/highlighted_assemblies/show.erb +1 -1
  5. data/app/commands/decidim/assemblies/admin/copy_assembly.rb +11 -3
  6. data/app/commands/decidim/assemblies/admin/create_assembly.rb +2 -1
  7. data/app/commands/decidim/assemblies/admin/create_assembly_member.rb +5 -1
  8. data/app/commands/decidim/assemblies/admin/update_assembly.rb +7 -11
  9. data/app/controllers/decidim/assemblies/admin/assemblies_controller.rb +1 -5
  10. data/app/forms/decidim/assemblies/admin/assembly_form.rb +3 -2
  11. data/app/forms/decidim/assemblies/admin/assembly_import_form.rb +1 -0
  12. data/app/forms/decidim/assemblies/admin/assembly_member_form.rb +1 -1
  13. data/app/helpers/decidim/assemblies/admin/assemblies_admin_menu_helper.rb +0 -5
  14. data/app/models/decidim/assembly.rb +5 -5
  15. data/app/models/decidim/assembly_member.rb +1 -1
  16. data/app/packs/entrypoints/decidim_assemblies.js +5 -0
  17. data/app/packs/entrypoints/decidim_assemblies_admin.js +3 -0
  18. data/app/{assets/images/decidim/assemblies/assembly.svg → packs/images/decidim/assemblies/decidim_assemblies.svg} +0 -0
  19. data/app/packs/src/decidim/assemblies/admin/assemblies.js +63 -0
  20. data/app/{assets/javascripts/decidim/assemblies/admin/assembly_members.js.es6 → packs/src/decidim/assemblies/admin/assembly_members.js} +3 -3
  21. data/app/packs/src/decidim/assemblies/assemblies.js +14 -0
  22. data/app/packs/src/decidim/assemblies/orgchart.js +695 -0
  23. data/app/presenters/decidim/assemblies/assembly_presenter.rb +2 -12
  24. data/app/presenters/decidim/assemblies/assembly_stats_presenter.rb +3 -13
  25. data/app/queries/decidim/assemblies/admin/admin_users.rb +24 -11
  26. data/app/serializers/decidim/assemblies/assembly_importer.rb +3 -2
  27. data/app/serializers/decidim/assemblies/assembly_serializer.rb +4 -2
  28. data/app/views/decidim/assemblies/admin/assemblies/_form.html.erb +6 -3
  29. data/app/views/decidim/assemblies/admin/assembly_copies/_form.html.erb +1 -1
  30. data/app/views/decidim/assemblies/admin/assembly_imports/_form.html.erb +1 -1
  31. data/app/views/decidim/assemblies/admin/assembly_members/_form.html.erb +2 -2
  32. data/app/views/decidim/assemblies/assemblies/_promoted_assembly.html.erb +1 -1
  33. data/app/views/decidim/assemblies/assemblies/index.html.erb +2 -2
  34. data/app/views/decidim/assemblies/assemblies/show.html.erb +6 -4
  35. data/app/views/layouts/decidim/_assembly_header.html.erb +1 -1
  36. data/app/views/layouts/decidim/admin/assemblies.html.erb +1 -1
  37. data/app/views/layouts/decidim/admin/assembly.html.erb +4 -73
  38. data/app/views/layouts/decidim/assembly.html.erb +2 -2
  39. data/config/assets.rb +9 -0
  40. data/config/locales/ar.yml +0 -17
  41. data/config/locales/ca.yml +4 -38
  42. data/config/locales/cs.yml +4 -38
  43. data/config/locales/de.yml +4 -38
  44. data/config/locales/el.yml +0 -31
  45. data/config/locales/en.yml +5 -39
  46. data/config/locales/es-MX.yml +4 -38
  47. data/config/locales/es-PY.yml +4 -38
  48. data/config/locales/es.yml +4 -38
  49. data/config/locales/eu.yml +0 -17
  50. data/config/locales/fi-plain.yml +5 -39
  51. data/config/locales/fi.yml +5 -39
  52. data/config/locales/fr-CA.yml +1 -39
  53. data/config/locales/fr-LU.yml +449 -0
  54. data/config/locales/fr.yml +0 -38
  55. data/config/locales/gl.yml +4 -38
  56. data/config/locales/hu.yml +0 -31
  57. data/config/locales/id-ID.yml +0 -17
  58. data/config/locales/is-IS.yml +0 -14
  59. data/config/locales/it.yml +6 -39
  60. data/config/locales/ja.yml +4 -33
  61. data/config/locales/lb-LU.yml +1 -0
  62. data/config/locales/lv.yml +0 -30
  63. data/config/locales/nl.yml +5 -39
  64. data/config/locales/no.yml +0 -38
  65. data/config/locales/pl.yml +4 -41
  66. data/config/locales/pt-BR.yml +82 -17
  67. data/config/locales/pt.yml +0 -31
  68. data/config/locales/ro-RO.yml +5 -36
  69. data/config/locales/ru.yml +0 -17
  70. data/config/locales/sk.yml +0 -16
  71. data/config/locales/sl.yml +0 -17
  72. data/config/locales/sr-CS.yml +0 -16
  73. data/config/locales/sv.yml +3 -36
  74. data/config/locales/tr-TR.yml +0 -31
  75. data/config/locales/uk.yml +0 -17
  76. data/config/locales/zh-CN.yml +0 -31
  77. data/db/migrate/20210507063604_add_announcement_to_assemblies.rb +7 -0
  78. data/lib/decidim/api/assembly_type.rb +10 -1
  79. data/lib/decidim/assemblies/admin_engine.rb +122 -30
  80. data/lib/decidim/assemblies/engine.rb +6 -9
  81. data/lib/decidim/assemblies/participatory_space.rb +46 -8
  82. data/lib/decidim/assemblies/test/factories.rb +1 -0
  83. data/lib/decidim/assemblies/version.rb +1 -1
  84. metadata +22 -23
  85. data/app/assets/config/admin/decidim_assemblies_manifest.js +0 -2
  86. data/app/assets/config/decidim_assemblies_manifest.js +0 -2
  87. data/app/assets/javascripts/decidim/assemblies/admin/assemblies.js.es6 +0 -67
  88. data/app/assets/javascripts/decidim/assemblies/assemblies.js.es6 +0 -18
  89. data/app/assets/javascripts/decidim/assemblies/orgchart.js.es6 +0 -698
  90. data/app/cells/decidim/assemblies/statistic/show.erb +0 -9
  91. data/app/cells/decidim/assemblies/statistic_cell.rb +0 -20
  92. data/app/cells/decidim/assemblies/statistics/show.erb +0 -17
  93. data/app/cells/decidim/assemblies/statistics_cell.rb +0 -18
  94. data/config/locales/ja-JP.yml +0 -471
@@ -1,2 +0,0 @@
1
- //= link decidim/assemblies/admin/assemblies.js
2
- //= link decidim/assemblies/admin/assembly_members.js
@@ -1,2 +0,0 @@
1
- //= link_directory ../images/decidim/assemblies
2
- //= link_directory ../javascripts/decidim/assemblies
@@ -1,67 +0,0 @@
1
- $(() => {
2
- ((exports) => {
3
- const $assemblyScopeEnabled = $("#assembly_scopes_enabled");
4
- const $assemblyScopeId = $("#assembly_scope_id");
5
-
6
- if ($(".edit_assembly, .new_assembly").length > 0) {
7
- $assemblyScopeEnabled.on("change", (event) => {
8
- const checked = event.target.checked;
9
- exports.theDataPicker.enabled($assemblyScopeId, checked);
10
- })
11
- exports.theDataPicker.enabled($assemblyScopeId, $assemblyScopeEnabled.prop("checked"));
12
- }
13
-
14
-
15
- const $form = $(".assembly_form_admin");
16
-
17
- if ($form.length > 0) {
18
-
19
- const $privateSpace = $form.find("#private_space");
20
- const $isTransparent = $form.find("#is_transparent");
21
- const $specialFeatures = $form.find("#special_features");
22
-
23
-
24
- const toggleDisabledHiddenFields = () => {
25
- const enabledPrivateSpace = $privateSpace.find("input[type='checkbox']").prop("checked");
26
- $isTransparent.find("input[type='checkbox']").attr("disabled", "disabled");
27
- $specialFeatures.hide();
28
-
29
- if (enabledPrivateSpace) {
30
- $isTransparent.find("input[type='checkbox']").attr("disabled", !enabledPrivateSpace);
31
- $specialFeatures.show();
32
- }
33
- };
34
-
35
- $privateSpace.on("change", toggleDisabledHiddenFields);
36
- toggleDisabledHiddenFields();
37
-
38
- const $assemblyType = $form.find("#assembly_assembly_type");
39
- const $assemblyTypeOther = $form.find("#assembly_type_other");
40
-
41
- const $assemblyCreatedBy = $form.find("#assembly_created_by");
42
- const $assemblyCreatedByOther = $form.find("#created_by_other");
43
-
44
- const toggleDependsOnSelect = ($target, $showDiv) => {
45
- const value = $target.val();
46
- $showDiv.hide();
47
- if (value === "others") {
48
- $showDiv.show();
49
- }
50
- };
51
-
52
- $assemblyType.on("change", (ev) => {
53
- const $target = $(ev.target);
54
- toggleDependsOnSelect($target, $assemblyTypeOther);
55
- });
56
-
57
- $assemblyCreatedBy.on("change", (ev) => {
58
- const $target = $(ev.target);
59
- toggleDependsOnSelect($target, $assemblyCreatedByOther);
60
- });
61
-
62
- toggleDependsOnSelect($assemblyType, $assemblyTypeOther);
63
- toggleDependsOnSelect($assemblyCreatedBy, $assemblyCreatedByOther);
64
- }
65
-
66
- })(window);
67
- });
@@ -1,18 +0,0 @@
1
- (function() {
2
- $(() => {
3
-
4
- $(".show-more").on("click", function() {
5
- /* eslint-disable no-invalid-this */
6
- $(this).hide();
7
- $(".show-more-panel").removeClass("hide");
8
- $(".hide-more").show();
9
- });
10
-
11
- $(".hide-more").on("click", function() {
12
- $(this).hide();
13
- $(".show-more-panel").addClass("hide");
14
- $(".show-more").show();
15
- });
16
-
17
- })
18
- }(window));
@@ -1,698 +0,0 @@
1
- /* eslint-disable require-jsdoc, max-lines, no-return-assign, func-style, id-length, no-plusplus, no-use-before-define, no-negated-condition, init-declarations, no-invalid-this, no-param-reassign, no-ternary, multiline-ternary, no-nested-ternary, no-eval, no-extend-native, prefer-reflect */
2
- /* eslint dot-location: ["error", "property"], no-negated-condition: "error" */
3
- /* eslint no-unused-expressions: ["error", { "allowTernary": true }] */
4
- /* eslint no-unused-vars: ["error", { "args": "none" }] */
5
- /* global d3 */
6
-
7
- // = require_self
8
- // = require d3
9
- ((exports) => {
10
- const { Decidim: { Visualizations: render } } = exports;
11
-
12
- // lib
13
- const renderOrgCharts = () => {
14
- const $orgChartContainer = $(".js-orgchart")
15
- const $btnReset = $(".js-reset-orgchart")
16
-
17
- let dataDepicted = null
18
- let fake = false
19
- let orgchart = {}
20
-
21
- // lib - https://bl.ocks.org/bumbeishvili/b96ba47ea21d14dfce6ebb859b002d3a
22
- const renderChartCollapsibleNetwork = (params) => {
23
-
24
- // exposed variables
25
- let attrs = {
26
- id: `id${Math.floor(Math.random() * 1000000)}`,
27
- svgWidth: 960,
28
- svgHeight: 600,
29
- marginTop: 0,
30
- marginBottom: 5,
31
- marginRight: 0,
32
- marginLeft: 30,
33
- container: "body",
34
- distance: 150,
35
- hiddenChildLevel: 1,
36
- hoverOpacity: 0.2,
37
- maxTextDisplayZoomLevel: 1,
38
- lineStrokeWidth: 1.5,
39
- fakeRoot: false,
40
- nodeGutter: { x: 16, y: 8 },
41
- childrenIndicatorRadius: 15,
42
- fakeBorderWidth: 32,
43
- data: null
44
- }
45
-
46
- /* ############### IF EXISTS OVERWRITE ATTRIBUTES FROM PASSED PARAM ####### */
47
-
48
- let attrKeys = Object.keys(attrs)
49
- attrKeys.forEach(function (key) {
50
- if (params && params[key]) {
51
- attrs[key] = params[key]
52
- }
53
- })
54
-
55
- // innerFunctions which will update visuals
56
- let updateData
57
- let collapse, expand
58
- let filter
59
- let hierarchy = {}
60
-
61
- // main chart object
62
- let main = function (selection) {
63
- selection.each(function scope() {
64
-
65
- // calculated properties
66
- let calc = {}
67
- calc.chartLeftMargin = attrs.marginLeft
68
- calc.chartTopMargin = attrs.marginTop
69
- calc.chartWidth = attrs.svgWidth - attrs.marginRight - calc.chartLeftMargin
70
- calc.chartHeight = attrs.svgHeight - attrs.marginBottom - calc.chartTopMargin
71
-
72
- // ########################## HIERARCHY STUFF #########################
73
- hierarchy.root = d3.hierarchy(attrs.data.root)
74
-
75
- // ########################### BEHAVIORS #########################
76
- let behaviors = {}
77
- // behaviors.zoom = d3.zoom().scaleExtent([0.75, 100, 8]).on("zoom", zoomed)
78
- behaviors.drag = d3.drag().on("start", dragstarted).on("drag", dragged).on("end", dragended)
79
-
80
- // ########################### LAYOUTS #########################
81
- let layouts = {}
82
-
83
- // custom radial layout
84
- layouts.radial = d3.radial()
85
-
86
- // ########################### FORCE STUFF #########################
87
- let force = {}
88
- force.link = d3.forceLink().id((d) => d.id)
89
- force.charge = d3.forceManyBody().strength(-240)
90
- force.center = d3.forceCenter(calc.chartWidth / 2, calc.chartHeight / 2)
91
-
92
- // prevent collide
93
- force.collide = d3.forceCollide().radius((d) => {
94
- // Creates an invented radius based on element measures: diagonal = 2 * radius = sqrt(width^2, height^2)
95
- let base = (d.bbox || {}).width + (attrs.nodeGutter.x * 2)
96
- let height = (d.bbox || {}).height + (attrs.nodeGutter.y * 2)
97
- let diagonal = Math.sqrt(Math.pow(base, 2) + Math.pow(height, 2))
98
- let fakeRadius = (diagonal / 2)
99
-
100
- // return d3.max([attrs.nodeDistance * 3, fakeRadius])
101
- return fakeRadius * 1.5
102
- })
103
-
104
- // manually set x positions (which is calculated using custom radial layout)
105
- force.x = d3.forceX()
106
- .strength(0.5)
107
- .x(function (d) {
108
-
109
- // if node does not have children and is channel (depth=2) , then position it on parent's coordinate
110
- if (!d.children && d.depth > 2) {
111
- if (d.parent) {
112
- d = d.parent
113
- }
114
- }
115
-
116
- // custom circle projection - radius will be - (d.depth - 1) * 150
117
- return projectCircle(d.proportion, (d.depth - 1) * attrs.distance)[0]
118
- })
119
-
120
- // manually set y positions (which is calculated using d3.cluster)
121
- force.y = d3.forceY()
122
- .strength(0.5)
123
- .y(function (d) {
124
-
125
- // if node does not have children and is channel (depth=2) , then position it on parent's coordinate
126
- if (!d.children && d.depth > 2) {
127
- if (d.parent) {
128
- d = d.parent
129
- }
130
- }
131
-
132
- // custom circle projection - radius will be - (d.depth - 1) * 150
133
- return projectCircle(d.proportion, (d.depth - 1) * attrs.distance)[1]
134
- })
135
-
136
- // --------------------------------- INITIALISE FORCE SIMULATION ----------------------------
137
-
138
- // get based on top parameter simulation
139
- force.simulation = d3.forceSimulation()
140
- .force("link", force.link)
141
- .force("charge", force.charge)
142
- .force("center", force.center)
143
- .force("collide", force.collide)
144
- .force("x", force.x)
145
- .force("y", force.y)
146
-
147
- // ########################### HIERARCHY STUFF #########################
148
-
149
- // flatten root
150
- let arr = flatten(hierarchy.root)
151
-
152
- // hide members based on their depth
153
- arr.forEach((d) => {
154
- // Hide fake root node
155
- if ((attrs.fakeRoot) && (d.depth === 1)) {
156
- d.hidden = true
157
- }
158
-
159
- if (d.depth > attrs.hiddenChildLevel) {
160
- d._children = d.children
161
- d.children = null
162
- }
163
- })
164
-
165
- // #################################### DRAWINGS #######################
166
-
167
- // drawing containers
168
- let container = d3.select(this)
169
-
170
- // add svg
171
- let svg = container.patternify({ tag: "svg", selector: "svg-chart-container" })
172
- .attr("width", attrs.svgWidth)
173
- .attr("height", attrs.svgHeight)
174
- // .call(behaviors.zoom)
175
-
176
- // add container g element
177
- let chart = svg.patternify({ tag: "g", selector: "chart" })
178
- .attr("transform", `translate(${calc.chartLeftMargin},${calc.chartTopMargin})`)
179
-
180
- // ################################ Chart Content Drawing ##################################
181
-
182
- // link wrapper
183
- let linksWrapper = chart.patternify({ tag: "g", selector: "links-wrapper" })
184
-
185
- // node wrapper
186
- let nodesWrapper = chart.patternify({ tag: "g", selector: "nodes-wrapper" })
187
- let links, nodes
188
-
189
- // reusable function which updates visual based on data change
190
- update()
191
-
192
- // update visual based on data change
193
- function update(clickedNode) {
194
-
195
- // Show/hide reset button
196
- (clickedNode) ? $btnReset.removeClass("invisible") : $btnReset.addClass("invisible")
197
-
198
- // set xy and proportion properties with custom radial layout
199
- layouts.radial(hierarchy.root)
200
-
201
- // nodes and links array
202
- let nodesArr = flatten(hierarchy.root, true)
203
- .orderBy((d) => d.depth)
204
- .filter((d) => !d.hidden)
205
-
206
- let linksArr = hierarchy.root.links()
207
- .filter((d) => !d.source.hidden)
208
- .filter((d) => !d.target.hidden)
209
-
210
- // make new nodes to appear near the parents
211
- nodesArr.forEach(function (d) {
212
- if (clickedNode && clickedNode.id === (d.parent && d.parent.id)) {
213
- d.x = d.parent.x
214
- d.y = d.parent.y
215
- }
216
- })
217
-
218
- // links
219
- links = linksWrapper.selectAll(".link")
220
- .data(linksArr, (d) => d.target.id)
221
- links.exit().remove()
222
-
223
- links = links.enter()
224
- .append("line")
225
- .attr("class", "link")
226
- .merge(links)
227
-
228
- // node groups
229
- nodes = nodesWrapper.selectAll(".node")
230
- .data(nodesArr, (d) => d.id)
231
- nodes.exit().remove()
232
-
233
- let enteredNodes = nodes.enter()
234
- .append("g")
235
- .attr("class", "node")
236
-
237
- // bind event handlers
238
- enteredNodes
239
- .on("click", nodeClick)
240
- .on("mouseenter", nodeMouseEnter)
241
- .on("mouseleave", nodeMouseLeave)
242
- .call(behaviors.drag)
243
-
244
- // channels grandchildren
245
- enteredNodes.append("rect")
246
- .attr("class", "as-card")
247
- .attr("rx", 4)
248
- .attr("ry", 4)
249
-
250
- enteredNodes.append("text")
251
- .attr("class", "as-text")
252
- .text((d) => d.data.name)
253
-
254
- enteredNodes.selectAll("text").each(function(d) {
255
- d.bbox = this.getBBox()
256
- })
257
-
258
- enteredNodes.selectAll("rect")
259
- .attr("x", (d) => d.bbox.x - attrs.nodeGutter.x)
260
- .attr("y", (d) => d.bbox.y - attrs.nodeGutter.y)
261
- .attr("width", (d) => d.bbox.width + (2 * attrs.nodeGutter.x))
262
- .attr("height", (d) => d.bbox.height + (2 * attrs.nodeGutter.y))
263
-
264
- // append circle & text only when there are children
265
- enteredNodes
266
- .append("circle")
267
- .filter((d) => Boolean(d.children) || Boolean(d._children))
268
- .attr("class", "as-circle")
269
- .attr("r", attrs.childrenIndicatorRadius)
270
- .attr("cx", (d) => d.bbox.x + d.bbox.width + attrs.nodeGutter.x)
271
- .attr("cy", (d) => d.bbox.y + d.bbox.height + attrs.nodeGutter.y)
272
-
273
- enteredNodes
274
- .append("text")
275
- .filter((d) => Boolean(d.children) || Boolean(d._children))
276
- .attr("class", "as-text")
277
- .attr("dx", (d) => d.bbox.x + d.bbox.width + attrs.nodeGutter.x)
278
- .attr("dy", attrs.childrenIndicatorRadius + 3)
279
- .text((d) => d3.max([(d.children || {}).length, (d._children || {}).length]))
280
-
281
- // merge node groups and style it
282
- nodes = enteredNodes.merge(nodes)
283
-
284
- // force simulation
285
- force.simulation.nodes(nodesArr).on("tick", ticked)
286
-
287
- // links simulation
288
- force.simulation.force("link").links(links).id((d) => d.id).distance(attrs.distance * 2).strength(2)
289
- }
290
-
291
- // ####################################### EVENT HANDLERS ########################
292
-
293
- // zoom handler
294
- // function zoomed() {
295
- // // get transform event
296
- // let transform = d3.event.transform
297
- // attrs.lastTransform = transform
298
- //
299
- // // apply transform event props to the wrapper
300
- // chart.attr("transform", transform)
301
- //
302
- // svg.selectAll(".node").attr("transform", (d) => `translate(${d.x},${d.y}) scale(${1 / (attrs.lastTransform ? attrs.lastTransform.k : 1)})`)
303
- // svg.selectAll(".link").attr("stroke-width", attrs.lineStrokeWidth / (attrs.lastTransform ? attrs.lastTransform.k : 1))
304
- // }
305
-
306
- // tick handler
307
- function ticked() {
308
- const fakeBorderWidth = attrs.fakeBorderWidth
309
- const maxXValueAvailable = (value) => Math.max(Math.min(calc.chartWidth - fakeBorderWidth, value), fakeBorderWidth)
310
- const maxYValueAvailable = (value) => Math.max(Math.min(calc.chartHeight - fakeBorderWidth, value), fakeBorderWidth)
311
- // set links position
312
- links
313
- .attr("x1", (d) => maxXValueAvailable(d.source.x))
314
- .attr("y1", (d) => maxYValueAvailable(d.source.y))
315
- .attr("x2", (d) => maxXValueAvailable(d.target.x))
316
- .attr("y2", (d) => maxYValueAvailable(d.target.y))
317
-
318
- // set nodes position
319
- svg.selectAll(".node")
320
- .attr("transform", (d) => `translate(${maxXValueAvailable(d.x)},${maxYValueAvailable(d.y)})`)
321
- }
322
-
323
- // handler drag start event
324
- function dragstarted() {
325
- // disable node fixing
326
- nodes.each((d) => {
327
- d.fx = null
328
- d.fy = null
329
- })
330
- }
331
-
332
- // handle dragging event
333
- function dragged(d) {
334
- // make dragged node fixed
335
- d.fx = d3.event.x
336
- d.fy = d3.event.y
337
- }
338
-
339
- // -------------------- handle drag end event ---------------
340
- function dragended() {
341
- // we are doing nothing, here , aren't we?
342
- }
343
-
344
- // -------------------------- node mouse hover handler ---------------
345
- function nodeMouseEnter(d) {
346
- // get links
347
- let _links = hierarchy.root.links()
348
-
349
- // get hovered node connected links
350
- let connectedLinks = _links.filter((l) => l.source.id === d.id || l.target.id === d.id)
351
-
352
- // get hovered node linked nodes
353
- let linkedNodes = connectedLinks.map((s) => s.source.id).concat(connectedLinks.map((c) => c.target.id))
354
-
355
- // reduce all other nodes opacity
356
- nodesWrapper.selectAll(".node")
357
- .filter((n) => linkedNodes.indexOf(n.id) === -1)
358
- .attr("opacity", attrs.hoverOpacity)
359
-
360
- // reduce all other links opacity
361
- linksWrapper.selectAll(".link")
362
- .attr("opacity", attrs.hoverOpacity)
363
-
364
- // highlight hovered nodes connections
365
- linksWrapper.selectAll(".link")
366
- .filter((l) => l.source.id === d.id || l.target.id === d.id)
367
- .attr("opacity", 1)
368
- }
369
-
370
- // --------------- handle mouseleave event ---------------
371
- function nodeMouseLeave() {
372
- // return things back to normal
373
- nodesWrapper.selectAll(".node")
374
- .attr("opacity", 1)
375
- linksWrapper.selectAll(".link")
376
- .attr("opacity", 1)
377
- }
378
-
379
- // --------------- handle node click event ---------------
380
- function nodeClick(d) {
381
- // free fixed nodes
382
- nodes.each((di) => {
383
- di.fx = null
384
- di.fy = null
385
- })
386
-
387
- // collapse or expand node
388
- if (d.children) {
389
- collapse(d)
390
- } else if (d._children) {
391
- expand(d)
392
- } else {
393
- // nothing is to collapse or expand
394
- }
395
-
396
- freeNodes()
397
- }
398
-
399
- // ######################################### UTIL FUNCS ##################################
400
- updateData = function () {
401
- main.run()
402
- }
403
-
404
- collapse = function (d, deep = false) {
405
- if (d.children) {
406
- if (deep) {
407
- d.children.forEach((e) => collapse(e, true))
408
- }
409
-
410
- d._children = d.children
411
- d.children = null
412
- }
413
-
414
- update(d)
415
- force.simulation.restart()
416
- force.simulation.alphaTarget(0.15)
417
- }
418
-
419
- expand = function (d, deep = false) {
420
- if (d._children) {
421
- if (deep) {
422
- d._children.forEach((e) => expand(e, true))
423
- }
424
-
425
- d.children = d._children
426
- d._children = null
427
- }
428
-
429
- update(d)
430
- force.simulation.restart()
431
- force.simulation.alphaTarget(0.15)
432
- }
433
-
434
- // function slowDownNodes() {
435
- // force.simulation.alphaTarget(0.05)
436
- // }
437
-
438
- // function speedUpNodes() {
439
- // force.simulation.alphaTarget(0.45)
440
- // }
441
-
442
- function freeNodes() {
443
- d3.selectAll(".node").each((n) => {
444
- n.fx = null
445
- n.fy = null
446
- })
447
- }
448
-
449
- function projectCircle(value, radius) {
450
- let r = radius || 0
451
- let corner = value * 2 * Math.PI
452
- return [Math.sin(corner) * r, -Math.cos(corner) * r]
453
- }
454
-
455
- // recursively loop on children and extract nodes as an array
456
- function flatten(root, clustered) {
457
- let nodesArray = []
458
- let i = 0
459
- function recurse(node, depth) {
460
- if (node.children) {
461
- node.children.forEach(function (child) {
462
- recurse(child, depth + 1)
463
- })
464
- }
465
-
466
- if (!node.id) {
467
- node.id = ++i
468
- } else {
469
- ++i
470
- }
471
-
472
- node.depth = depth
473
- if (clustered) {
474
- if (!node.cluster) {
475
- // if cluster coordinates are not set, set it
476
- node.cluster = { x: node.x, y: node.y }
477
- }
478
- }
479
- nodesArray.push(node)
480
- }
481
- recurse(root, 1)
482
- return nodesArray
483
- }
484
-
485
- function debug() {
486
- if (attrs.isDebug) {
487
- // stringify func
488
- let stringified = String(scope)
489
-
490
- // parse variable names
491
- let groupVariables = stringified
492
- // match var x-xx= {}
493
- .match(/var\s+([\w])+\s*=\s*{\s*}/gi)
494
- // match xxx
495
- .map((d) => d.match(/\s+\w*/gi).filter((s) => s.trim()))
496
- // get xxx
497
- .map((v) => v[0].trim())
498
-
499
- // assign local variables to the scope
500
- groupVariables.forEach((v) => {
501
- main[`P_${v}`] = eval(v)
502
- })
503
- }
504
- }
505
-
506
- debug()
507
-
508
- })
509
- }
510
-
511
- // ----------- PROTOTYEPE FUNCTIONS ----------------------
512
- d3.selection.prototype.patternify = function (_params) {
513
- let selector = _params.selector
514
- let elementTag = _params.tag
515
- let _data = _params.data || [selector]
516
-
517
- // pattern in action
518
- let selection = this.selectAll(`.${selector}`).data(_data)
519
- selection.exit().remove()
520
- selection = selection.enter().append(elementTag).merge(selection)
521
- selection.attr("class", selector)
522
-
523
- return selection
524
- }
525
-
526
- // custom radial layout
527
- d3.radial = function () {
528
- return function (root) {
529
-
530
- recurse(root, 0, 1)
531
-
532
- function recurse(node, min, max) {
533
- node.proportion = (max + min) / 2
534
- if (!node.x) {
535
-
536
- // if node has parent, match entered node positions to it's parent
537
- if (node.parent) {
538
- node.x = node.parent.x
539
- } else {
540
- node.x = 0
541
- }
542
- }
543
-
544
- // if node had parent, match entered node positions to it's parent
545
- if (!node.y) {
546
- if (node.parent) {
547
- node.y = node.parent.y
548
- } else {
549
- node.y = 0
550
- }
551
- }
552
-
553
- // recursively do the same for children
554
- if (node.children) {
555
- let offset = (max - min) / node.children.length
556
- node.children.forEach(function (child, i) {
557
- let newMin = min + (offset * i)
558
- let newMax = newMin + offset
559
-
560
- recurse(child, newMin, newMax)
561
- })
562
- }
563
- }
564
- }
565
- }
566
-
567
- // https://github.com/bumbeishvili/d3js-boilerplates#orderby
568
- Array.prototype.orderBy = function (func) {
569
- this.sort((_a, _b) => {
570
- let a = func(_a)
571
- let b = func(_b)
572
- if (typeof a === "string" || a instanceof String) {
573
- return a.localeCompare(b)
574
- }
575
- return a - b
576
- })
577
-
578
- return this
579
- }
580
-
581
- // ########################## BOILEPLATE STUFF ################
582
-
583
- // dinamic keys functions
584
- Object.keys(attrs).forEach((key) => {
585
- // Attach variables to main function
586
- return main[key] = function (_) {
587
- let string = `attrs['${key}'] = _`
588
-
589
- if (!arguments.length) {
590
- return eval(` attrs['${key}'];`)
591
- }
592
-
593
- eval(string)
594
-
595
- return main
596
- }
597
- })
598
-
599
- // set attrs as property
600
- main.attrs = attrs
601
-
602
- // debugging visuals
603
- main.debug = function (isDebug) {
604
- attrs.isDebug = isDebug
605
- if (isDebug) {
606
- if (!window.charts) {
607
- window.charts = []
608
- }
609
- window.charts.push(main)
610
- }
611
- return main
612
- }
613
-
614
- // exposed update functions
615
- main.data = function (value) {
616
- if (!arguments.length) {
617
- return attrs.data
618
- }
619
-
620
- attrs.data = value
621
- if (typeof updateData === "function") {
622
- updateData()
623
- }
624
- return main
625
- }
626
-
627
- // run visual
628
- main.run = function () {
629
- d3.selectAll(attrs.container)
630
- .call(main)
631
- return main
632
- }
633
-
634
- main.filter = function (filterParams) {
635
- if (!arguments.length) {
636
- return attrs.filterParams
637
- }
638
-
639
- attrs.filterParams = filterParams
640
- if (typeof filter === "function") {
641
- filter()
642
- }
643
- return main
644
- }
645
-
646
- main.reset = function () {
647
-
648
- hierarchy.root.children.forEach((e) => collapse(e, true))
649
- main.run()
650
-
651
- return main
652
- }
653
-
654
- return main
655
- }
656
-
657
- // initialization
658
- $orgChartContainer.each((i, container) => {
659
-
660
- let $container = $(container)
661
- let width = $container.width()
662
- let height = width / (16 / 9)
663
-
664
- d3.json($container.data("url")).then((data) => {
665
- // Make a fake previous node if the data entry is not hierarchical
666
- if (data instanceof Array) {
667
- fake = true
668
- dataDepicted = {
669
- name: null,
670
- children: data
671
- }
672
- } else {
673
- dataDepicted = data
674
- }
675
-
676
- orgchart = renderChartCollapsibleNetwork()
677
- .svgHeight(height)
678
- .svgWidth(width)
679
- .fakeRoot(fake)
680
- .container(`#${container.id}`)
681
- .data({
682
- root: dataDepicted
683
- })
684
- .debug(true)
685
- .run()
686
- })
687
- })
688
-
689
- // reset
690
- $btnReset.click(function() {
691
- orgchart.reset()
692
- })
693
- }
694
-
695
- $(() => {
696
- render(renderOrgCharts);
697
- })
698
- })(window);