Mercurial > hg > dml-open-vis
comparison src/DML/MainVisBundle/Resources/assets/marionette/modules/GraphicsRenderingModule/GraphicsRenderingModule.20-Renderer.chord-seq.parallel-coordinates.js @ 0:493bcb69166c
added public content
author | Daniel Wolff |
---|---|
date | Tue, 09 Feb 2016 20:54:02 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:493bcb69166c |
---|---|
1 "use strict"; | |
2 | |
3 App.module("GraphicsRenderingModule", function(GraphicsRenderingModule, App, Backbone, Marionette, $, _, Logger) { | |
4 | |
5 GraphicsRenderingModule.addInitializer(function(options) { | |
6 | |
7 GraphicsRenderingModule.registerRenderer({ | |
8 id: "chord-seq.parallel-coordinates", | |
9 inherit: "chord-seq._", | |
10 | |
11 defaultVegaConfig: { | |
12 sizeOfStepMark: 5, | |
13 stepCount: 3, | |
14 primaryAxisFontSize: 11, | |
15 chordGapSizeToChordSizeRatio: 1, | |
16 paddingWhenAxisLabelsAreHidden: {"top": 5, "left": 15, "bottom": 10, "right": 15}, | |
17 paddingWhenAxisLabelsAreShownParitally: {"top": 20, "left": 15, "bottom": 10, "right": 15}, | |
18 paddingWhenAxisLabelsAreShown: {"top":NaN, "left": 15, "bottom": 10, "right": 15}, | |
19 }, | |
20 | |
21 _formVC: function(vc, data) { | |
22 var renderer = this; | |
23 | |
24 // Derive variables from the config | |
25 vc.numberOfRootNotes = vc.sequenceOfUsedRootNotes.length; // Excluding N (if any) | |
26 vc.numberOfChordTypes = vc.sequenceOfUsedChordTypes.length; | |
27 | |
28 // titles of root notes | |
29 vc.titlesForChordTypes = vc.chordTypesWithM; | |
30 vc.titlesForRootNotes = vc.relativeRootNotes; | |
31 if (vc.recordingsInMajorModeAreIncluded && !vc.recordingsInMinorModeAreIncluded) { | |
32 vc.titlesForRootNotes = vc.relativeRootNotesInMajor; | |
33 } | |
34 if (vc.recordingsInMinorModeAreIncluded && !vc.recordingsInMajorModeAreIncluded) { | |
35 vc.titlesForRootNotes = vc.relativeRootNotesInMinor; | |
36 } | |
37 | |
38 // calculate the sizes of the elements | |
39 vc.numberOfChords = vc.numberOfRootNotes * vc.numberOfChordTypes; | |
40 vc.numberOfGaps = vc.chordGrouppingIsByType | |
41 ? vc.numberOfChordTypes - 1 | |
42 : vc.numberOfRootNotes - 1; | |
43 | |
44 vc.padding = vc.paddingWhenAxisLabelsAreHidden; | |
45 vc.width = vc.totalWidth - vc.padding.left - vc.padding.right; | |
46 vc.labelsForGroupsAreShown = vc.width / (vc.numberOfGaps + 1) > 30; | |
47 vc.labelsForChordsAreShown = vc.width / (vc.numberOfChords + vc.numberOfGaps) > 10; | |
48 | |
49 if (vc.labelsForGroupsAreShown) { | |
50 vc.padding = vc.paddingWhenAxisLabelsAreShownParitally; | |
51 } | |
52 if (vc.labelsForChordsAreShown) { | |
53 vc.padding = vc.paddingWhenAxisLabelsAreShown; | |
54 var titles = []; | |
55 if (vc.chordGrouppingIsByType) { | |
56 titles = _.map(vc.sequenceOfUsedRootNotes, function(index) {return vc.titlesForRootNotes[index];}); | |
57 } else { | |
58 titles = _.map(vc.sequenceOfUsedChordTypes, function(index) {return vc.titlesForChordTypes[index];}); | |
59 } | |
60 var maxTitleLength = 0; | |
61 _.each(titles, function(title) { | |
62 if (title.length > maxTitleLength) { | |
63 maxTitleLength = title.length; | |
64 } | |
65 }); | |
66 | |
67 vc.padding.top = maxTitleLength * 4 + 25; | |
68 } | |
69 | |
70 if (vc.nIsIncluded) { | |
71 vc.numberOfChords += 1; | |
72 vc.numberOfGaps += 1; | |
73 } | |
74 | |
75 | |
76 vc.chordSize = 1; | |
77 do { | |
78 vc.chordSize++; | |
79 vc.chordGroupGapSize = Math.round(vc.chordSize * vc.chordGapSizeToChordSizeRatio); | |
80 vc.width = (vc.numberOfChords - 1) * vc.chordSize + vc.numberOfGaps * vc.chordGroupGapSize; | |
81 } while (vc.width + vc.padding.left + vc.padding.right < vc.totalWidth); | |
82 | |
83 --vc.chordSize; | |
84 vc.chordGroupGapSize = Math.round(vc.chordSize * vc.chordGapSizeToChordSizeRatio); | |
85 vc.width = (vc.numberOfChords - 1) * vc.chordSize + vc.numberOfGaps * vc.chordGroupGapSize; | |
86 vc.height = vc.width + vc.padding.left + vc.padding.right - vc.padding.top - vc.padding.bottom; | |
87 | |
88 | |
89 // ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | |
90 // Data | |
91 | |
92 // ............................................................. | |
93 // Data - links | |
94 var linksInVegaData = []; | |
95 var encodedChordSequences = data.self.stats.sequences; | |
96 var support = data.self.stats.support; | |
97 | |
98 var sequenceId = 0; | |
99 _.each(encodedChordSequences, function(encodedChordSequence, i) { | |
100 var recordsToAdd = []; | |
101 var failed = false; | |
102 var chordSequenceHasCycles = _.unique(encodedChordSequence).length !== encodedChordSequence.length; | |
103 if (!vc.chordSequencesWithCyclesAreIncluded && chordSequenceHasCycles) { | |
104 return; | |
105 } | |
106 | |
107 var parsedEncodedChordSequence = []; | |
108 var chordTitles = []; | |
109 _.each(encodedChordSequence, function(encodedChord, index) { | |
110 if (index > vc.stepCount) { | |
111 return; | |
112 } | |
113 var parsedEncodedChord = renderer.parseEncodedChord(encodedChord); | |
114 parsedEncodedChordSequence.push(parsedEncodedChord); | |
115 if (index == vc.stepCount) { | |
116 chordTitles.push("..."); | |
117 } else { | |
118 chordTitles.push(renderer.titleOfParsedEncodedChord(vc, parsedEncodedChord)); | |
119 } | |
120 }); | |
121 | |
122 var tooltip = chordTitles.join(" → ") + "<br/>support: " + support[i]; | |
123 _.each(parsedEncodedChordSequence, function(parsedEncodedChord, indexInSequence) { | |
124 if (failed) { | |
125 return; | |
126 } | |
127 if (parsedEncodedChord !== 0 && !((vc.recordingsInMajorModeAreIncluded && parsedEncodedChord[0] == 1) | |
128 || (vc.recordingsInMinorModeAreIncluded && parsedEncodedChord[0] == 2))) { | |
129 failed = true; | |
130 return; | |
131 } | |
132 var bin = renderer.parsedEncodedChordToBin(vc, parsedEncodedChord); | |
133 if (bin === null) { | |
134 failed = true; | |
135 return; | |
136 } | |
137 | |
138 recordsToAdd.push({ | |
139 sequenceId: sequenceId, | |
140 encodedChordSequence: encodedChordSequence, | |
141 chordSequenceHasCycles: chordSequenceHasCycles, | |
142 indexInSequence: indexInSequence, | |
143 support: support[i], | |
144 chordCoordinate: renderer.chordBinToCoordinate(vc, bin), | |
145 color: vc.primaryColor, | |
146 tooltip: tooltip | |
147 }); | |
148 }); | |
149 if (!failed) { | |
150 linksInVegaData.push.apply(linksInVegaData, recordsToAdd); | |
151 } | |
152 ++sequenceId; | |
153 }); | |
154 | |
155 // Put most frequent on top | |
156 linksInVegaData.reverse(); | |
157 | |
158 vc.data.push({ | |
159 "name": "links", | |
160 "values": linksInVegaData | |
161 }); | |
162 | |
163 // ............................................................. | |
164 // Data - chord names in the secondary axis | |
165 var chordsInVegaData = []; | |
166 _.each(vc.sequenceOfUsedRootNotes, function(indexOfRootNote) { | |
167 _.each(vc.sequenceOfUsedChordTypes, function(indexOfChordType) { | |
168 var bin = renderer.parsedEncodedChordToBin(vc, [0, indexOfRootNote, indexOfChordType]); | |
169 chordsInVegaData.push({ | |
170 rootNoteIndex: indexOfRootNote, | |
171 rootNoteTitle: vc.titlesForRootNotes[indexOfRootNote], | |
172 | |
173 chordTypeIndex: indexOfChordType, | |
174 chordTypeTitle: vc.titlesForChordTypes[indexOfChordType], | |
175 | |
176 chordCoordinate: renderer.chordBinToCoordinate(vc, bin) | |
177 }); | |
178 }); | |
179 }); | |
180 vc.data.push({ | |
181 "name": "chords", | |
182 "values": chordsInVegaData, | |
183 }); | |
184 | |
185 // ............................................................. | |
186 // Data - chord names in the primary axis | |
187 if (vc.labelsForGroupsAreShown) { | |
188 var groupsForVega = []; | |
189 if (vc.chordGrouppingIsByType) { | |
190 groupsForVega = chordsInVegaData.filter(function(chord) { | |
191 return chord.rootNoteIndex == vc.sequenceOfUsedRootNotes[0]; | |
192 }); | |
193 } else { | |
194 groupsForVega = chordsInVegaData.filter(function(chord) { | |
195 return chord.chordTypeIndex == vc.sequenceOfUsedChordTypes[0]; | |
196 }); | |
197 } | |
198 vc.data.push({ | |
199 "name": "groups", | |
200 "values": groupsForVega, | |
201 }); | |
202 } | |
203 | |
204 // ............................................................. | |
205 // Data - steps | |
206 var stepsInVegaData = _.range(0, vc.stepCount); | |
207 vc.data.push({ | |
208 "name": "steps", | |
209 "values": stepsInVegaData, | |
210 }); | |
211 | |
212 | |
213 // ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | |
214 // Scales | |
215 | |
216 // ............................................................. | |
217 // Scale - steps | |
218 vc.scales.push({ | |
219 //"type": "ordinal", | |
220 "name": "indexInSequence", | |
221 "domainMin": 0, | |
222 "domainMax": vc.stepCount - 1, | |
223 "point": true, | |
224 "round": true, | |
225 "range": [0, vc.height] | |
226 }); | |
227 | |
228 // ............................................................. | |
229 // Scale - line opacity | |
230 vc.scales.push({ | |
231 "name": "strokeOpacity", | |
232 "type": "linear", | |
233 "domain": [0, data.self.coverage["ok_count"] * 2], | |
234 "point": true, | |
235 "range": [0, 1] | |
236 }); | |
237 | |
238 | |
239 // ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | |
240 // Marks | |
241 | |
242 // ............................................................. | |
243 // Mark - vertical lines for chords | |
244 if (true || vc.guidesAreVisible) { | |
245 vc.marks.push({ | |
246 "type": "rect", | |
247 "from": {"data": "chords"}, | |
248 "properties": { | |
249 "enter": { | |
250 "x": {"field": "chordCoordinate"}, | |
251 "y": {"value": 0}, | |
252 "width": {"value": 1}, | |
253 "height": {"field": {"group": "height"}}, | |
254 "fill": {"value": vc.colorForAxes} | |
255 }, | |
256 } | |
257 }); | |
258 } | |
259 | |
260 // ............................................................. | |
261 // Mark - vertical lines for N chord | |
262 if (vc.nIsIncluded && vc.guidesAreVisible) { | |
263 vc.marks.push({ | |
264 "type": "rect", | |
265 "properties": { | |
266 "enter": { | |
267 "x": {"field": {"group": "width"}}, | |
268 "y": {"value": 0}, | |
269 "width": {"value": "1"}, | |
270 "height": {"field": {"group": "height"}}, | |
271 "fill": {"value": vc.colorForAxes}, | |
272 }, | |
273 } | |
274 }); | |
275 } | |
276 | |
277 // ............................................................. | |
278 // Mark - horisontal lines denoting steps | |
279 if (vc.guidesAreVisible) { | |
280 for (var right = 0; right < 2; right++) { | |
281 vc.marks.push({ | |
282 "type": "rect", | |
283 "from": {"data": "steps"}, | |
284 "properties": { | |
285 "enter": { | |
286 "x": right ? {"field": {"group": "width"}} : {"value": -vc.sizeOfStepMark}, | |
287 "width": {"value": vc.sizeOfStepMark}, | |
288 "y": {"scale": "indexInSequence", "field": "data"}, | |
289 "height": {"value": 1}, | |
290 "fill": {"value": vc.colorForAxes}, | |
291 } | |
292 } | |
293 }); | |
294 } | |
295 } | |
296 | |
297 // ............................................................. | |
298 // Mark - links | |
299 vc.marks.push({ | |
300 "type": "group", | |
301 "from": { | |
302 "data": "links", | |
303 "transform": [ { | |
304 "type": "facet", | |
305 "groupby": ["sequenceId"] | |
306 } ] | |
307 }, | |
308 "marks": [{ | |
309 "type": "line", | |
310 "properties": { | |
311 "enter": { | |
312 "x": {"field": "chordCoordinate"}, | |
313 "y": {"scale": "indexInSequence", "field": "indexInSequence"}, | |
314 "strokeOpacity": {"scale": "strokeOpacity", "field": "support"}, | |
315 "stroke": {"field": "color"}, | |
316 "strokeWidth": {"value": 2}, | |
317 }, | |
318 "update": { | |
319 "strokeOpacity": {"scale": "strokeOpacity", "field": "support"}, | |
320 "stroke": {"field": "color"}, | |
321 }, | |
322 "hover": { | |
323 "strokeOpacity": {"value": 1}, | |
324 "stroke": {"value": "#000"}, | |
325 } | |
326 }, | |
327 }] | |
328 }); | |
329 | |
330 // ............................................................. | |
331 // Mark - group name (primary axis) | |
332 vc.yOffsetForGroupLabels = -vc.padding.top + 15; | |
333 vc.yOffsetForChordLabels = -3; | |
334 | |
335 vc.xOffsetForGroupLabels = 0.5 * vc.chordSize * ((vc.chordGrouppingIsByType ? vc.numberOfRootNotes : vc.numberOfChordTypes) - 1); | |
336 | |
337 if (vc.labelsForGroupsAreShown) { | |
338 vc.marks.push({ | |
339 "type": "text", | |
340 "from": {"data": "groups"}, | |
341 "properties": { | |
342 "enter": { | |
343 "x": {"field": "chordCoordinate", "offset": vc.xOffsetForGroupLabels}, | |
344 "y": {"value": vc.yOffsetForGroupLabels}, | |
345 "text": {"field": vc.chordGrouppingIsByType ? "chordTypeTitle": "rootNoteTitle"}, | |
346 "baseline": {"value":"bottom"}, | |
347 "align": {"value": "center"}, | |
348 "fill": {"value": vc.colorForAxisLabels}, | |
349 "font": {"value": vc.fontFace}, | |
350 "fontSize": {"value": vc.fontSizeForLabelsInAxis}, | |
351 }, | |
352 } | |
353 }); | |
354 } | |
355 | |
356 // ............................................................. | |
357 // Mark - column name for N | |
358 if (vc.nIsIncluded && vc.labelsForGroupsAreShown) { | |
359 vc.marks.push({ | |
360 "type": "text", | |
361 "properties": { | |
362 "enter": { | |
363 "y": {"value": vc.labelsForChordsAreShown ? vc.yOffsetForChordLabels : vc.yOffsetForGroupLabels}, | |
364 "x": {"field": {"group": "width"}}, | |
365 "text": {"value":"N"}, | |
366 "align": {"value":"center"}, | |
367 "baseline": {"value":"bottom"}, | |
368 "fill": {"value": vc.colorForAxisLabels}, | |
369 "font": {"value": vc.fontFace}, | |
370 "fontSize": {"value": vc.fontSizeForLabelsInAxis}, | |
371 }, | |
372 } | |
373 }); | |
374 } | |
375 | |
376 // ............................................................. | |
377 // Mark - chord name (secondary axis) | |
378 if (vc.labelsForChordsAreShown) { | |
379 vc.marks.push({ | |
380 "type": "text", | |
381 "from": {"data": "chords"}, | |
382 "properties": { | |
383 "enter": { | |
384 "x": {"field": "data.chordCoordinate", "offset": 0}, | |
385 "y": {"value": vc.yOffsetForChordLabels}, | |
386 "text": {"field": vc.chordGrouppingIsByType ? "data.rootNoteTitle": "data.chordTypeTitle"}, | |
387 "angle": {"value": "-90"}, | |
388 "baseline": {"value": "middle"}, | |
389 "fill": {"value": vc.colorForAxisLabels}, | |
390 "font": {"value": vc.fontFace}, | |
391 "fontSize": {"value": vc.fontSizeForLabelsInSecondaryAxis}, | |
392 }, | |
393 } | |
394 }); | |
395 } | |
396 | |
397 // ............................................................. | |
398 // Mark - fader | |
399 vc.marks.push({ | |
400 "type": "image", | |
401 "from": {"data": "dummy"}, | |
402 "properties": { | |
403 "enter": { | |
404 "x": {"value": 0}, | |
405 "width": {"field": {"group": "width"}}, | |
406 "y": {"field": {"group": "height"}}, | |
407 "height": {"value": vc.padding.bottom + 2}, | |
408 "url": {"value": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQIAAAAMCAYAAACJMrOUAAABFUlEQVRoge2PwW0CQQxFXQEUAoVAYaGT0Ek64Lq5QgMgLVJ4uezBspYsoxnCsPMPT1/y2B4/A5aOhctFqD3ynkvq/tL3yF/+TfobsAZWA2uXj7AK85G4L/bn/pc6X3qf/OU/C38DtglsXG5CrUZK3yt/+c/S34BdBh8ux/A9Y/1T77n7no385T8LfwM+/2Dvch9qJfpT53P3pyJ/+Tfhb8CXEKJtDDgIIdrGgA74vkPnsgu1V5B7T+q8/OXfhL8Bp3/k6PIYai0gf/lX6W/AGbgMnF2OcQn9kTgf+1Pfp/6f2pd7n/zl34S/AT1wHehd9qE29h6Z6s/dF6n9XvnL/y38Dfhx3FzeQq0Ez95f+33yl3+V/r9d8S8/zvVSHwAAAABJRU5ErkJggg=="}, | |
409 "fill": {"value": "#F00"}, | |
410 }, | |
411 } | |
412 }); | |
413 } | |
414 }); | |
415 }); | |
416 }, Logger); |