Mercurial > hg > dml-open-vis
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/DML/MainVisBundle/Resources/assets/marionette/modules/GraphicsRenderingModule/GraphicsRenderingModule.20-Renderer.chord-seq.parallel-coordinates.js Tue Feb 09 20:54:02 2016 +0100 @@ -0,0 +1,416 @@ +"use strict"; + +App.module("GraphicsRenderingModule", function(GraphicsRenderingModule, App, Backbone, Marionette, $, _, Logger) { + + GraphicsRenderingModule.addInitializer(function(options) { + + GraphicsRenderingModule.registerRenderer({ + id: "chord-seq.parallel-coordinates", + inherit: "chord-seq._", + + defaultVegaConfig: { + sizeOfStepMark: 5, + stepCount: 3, + primaryAxisFontSize: 11, + chordGapSizeToChordSizeRatio: 1, + paddingWhenAxisLabelsAreHidden: {"top": 5, "left": 15, "bottom": 10, "right": 15}, + paddingWhenAxisLabelsAreShownParitally: {"top": 20, "left": 15, "bottom": 10, "right": 15}, + paddingWhenAxisLabelsAreShown: {"top":NaN, "left": 15, "bottom": 10, "right": 15}, + }, + + _formVC: function(vc, data) { + var renderer = this; + + // Derive variables from the config + vc.numberOfRootNotes = vc.sequenceOfUsedRootNotes.length; // Excluding N (if any) + vc.numberOfChordTypes = vc.sequenceOfUsedChordTypes.length; + + // titles of root notes + vc.titlesForChordTypes = vc.chordTypesWithM; + vc.titlesForRootNotes = vc.relativeRootNotes; + if (vc.recordingsInMajorModeAreIncluded && !vc.recordingsInMinorModeAreIncluded) { + vc.titlesForRootNotes = vc.relativeRootNotesInMajor; + } + if (vc.recordingsInMinorModeAreIncluded && !vc.recordingsInMajorModeAreIncluded) { + vc.titlesForRootNotes = vc.relativeRootNotesInMinor; + } + + // calculate the sizes of the elements + vc.numberOfChords = vc.numberOfRootNotes * vc.numberOfChordTypes; + vc.numberOfGaps = vc.chordGrouppingIsByType + ? vc.numberOfChordTypes - 1 + : vc.numberOfRootNotes - 1; + + vc.padding = vc.paddingWhenAxisLabelsAreHidden; + vc.width = vc.totalWidth - vc.padding.left - vc.padding.right; + vc.labelsForGroupsAreShown = vc.width / (vc.numberOfGaps + 1) > 30; + vc.labelsForChordsAreShown = vc.width / (vc.numberOfChords + vc.numberOfGaps) > 10; + + if (vc.labelsForGroupsAreShown) { + vc.padding = vc.paddingWhenAxisLabelsAreShownParitally; + } + if (vc.labelsForChordsAreShown) { + vc.padding = vc.paddingWhenAxisLabelsAreShown; + var titles = []; + if (vc.chordGrouppingIsByType) { + titles = _.map(vc.sequenceOfUsedRootNotes, function(index) {return vc.titlesForRootNotes[index];}); + } else { + titles = _.map(vc.sequenceOfUsedChordTypes, function(index) {return vc.titlesForChordTypes[index];}); + } + var maxTitleLength = 0; + _.each(titles, function(title) { + if (title.length > maxTitleLength) { + maxTitleLength = title.length; + } + }); + + vc.padding.top = maxTitleLength * 4 + 25; + } + + if (vc.nIsIncluded) { + vc.numberOfChords += 1; + vc.numberOfGaps += 1; + } + + + vc.chordSize = 1; + do { + vc.chordSize++; + vc.chordGroupGapSize = Math.round(vc.chordSize * vc.chordGapSizeToChordSizeRatio); + vc.width = (vc.numberOfChords - 1) * vc.chordSize + vc.numberOfGaps * vc.chordGroupGapSize; + } while (vc.width + vc.padding.left + vc.padding.right < vc.totalWidth); + + --vc.chordSize; + vc.chordGroupGapSize = Math.round(vc.chordSize * vc.chordGapSizeToChordSizeRatio); + vc.width = (vc.numberOfChords - 1) * vc.chordSize + vc.numberOfGaps * vc.chordGroupGapSize; + vc.height = vc.width + vc.padding.left + vc.padding.right - vc.padding.top - vc.padding.bottom; + + + // ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + // Data + + // ............................................................. + // Data - links + var linksInVegaData = []; + var encodedChordSequences = data.self.stats.sequences; + var support = data.self.stats.support; + + var sequenceId = 0; + _.each(encodedChordSequences, function(encodedChordSequence, i) { + var recordsToAdd = []; + var failed = false; + var chordSequenceHasCycles = _.unique(encodedChordSequence).length !== encodedChordSequence.length; + if (!vc.chordSequencesWithCyclesAreIncluded && chordSequenceHasCycles) { + return; + } + + var parsedEncodedChordSequence = []; + var chordTitles = []; + _.each(encodedChordSequence, function(encodedChord, index) { + if (index > vc.stepCount) { + return; + } + var parsedEncodedChord = renderer.parseEncodedChord(encodedChord); + parsedEncodedChordSequence.push(parsedEncodedChord); + if (index == vc.stepCount) { + chordTitles.push("..."); + } else { + chordTitles.push(renderer.titleOfParsedEncodedChord(vc, parsedEncodedChord)); + } + }); + + var tooltip = chordTitles.join(" → ") + "<br/>support: " + support[i]; + _.each(parsedEncodedChordSequence, function(parsedEncodedChord, indexInSequence) { + if (failed) { + return; + } + if (parsedEncodedChord !== 0 && !((vc.recordingsInMajorModeAreIncluded && parsedEncodedChord[0] == 1) + || (vc.recordingsInMinorModeAreIncluded && parsedEncodedChord[0] == 2))) { + failed = true; + return; + } + var bin = renderer.parsedEncodedChordToBin(vc, parsedEncodedChord); + if (bin === null) { + failed = true; + return; + } + + recordsToAdd.push({ + sequenceId: sequenceId, + encodedChordSequence: encodedChordSequence, + chordSequenceHasCycles: chordSequenceHasCycles, + indexInSequence: indexInSequence, + support: support[i], + chordCoordinate: renderer.chordBinToCoordinate(vc, bin), + color: vc.primaryColor, + tooltip: tooltip + }); + }); + if (!failed) { + linksInVegaData.push.apply(linksInVegaData, recordsToAdd); + } + ++sequenceId; + }); + + // Put most frequent on top + linksInVegaData.reverse(); + + vc.data.push({ + "name": "links", + "values": linksInVegaData + }); + + // ............................................................. + // Data - chord names in the secondary axis + var chordsInVegaData = []; + _.each(vc.sequenceOfUsedRootNotes, function(indexOfRootNote) { + _.each(vc.sequenceOfUsedChordTypes, function(indexOfChordType) { + var bin = renderer.parsedEncodedChordToBin(vc, [0, indexOfRootNote, indexOfChordType]); + chordsInVegaData.push({ + rootNoteIndex: indexOfRootNote, + rootNoteTitle: vc.titlesForRootNotes[indexOfRootNote], + + chordTypeIndex: indexOfChordType, + chordTypeTitle: vc.titlesForChordTypes[indexOfChordType], + + chordCoordinate: renderer.chordBinToCoordinate(vc, bin) + }); + }); + }); + vc.data.push({ + "name": "chords", + "values": chordsInVegaData, + }); + + // ............................................................. + // Data - chord names in the primary axis + if (vc.labelsForGroupsAreShown) { + var groupsForVega = []; + if (vc.chordGrouppingIsByType) { + groupsForVega = chordsInVegaData.filter(function(chord) { + return chord.rootNoteIndex == vc.sequenceOfUsedRootNotes[0]; + }); + } else { + groupsForVega = chordsInVegaData.filter(function(chord) { + return chord.chordTypeIndex == vc.sequenceOfUsedChordTypes[0]; + }); + } + vc.data.push({ + "name": "groups", + "values": groupsForVega, + }); + } + + // ............................................................. + // Data - steps + var stepsInVegaData = _.range(0, vc.stepCount); + vc.data.push({ + "name": "steps", + "values": stepsInVegaData, + }); + + + // ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + // Scales + + // ............................................................. + // Scale - steps + vc.scales.push({ + //"type": "ordinal", + "name": "indexInSequence", + "domainMin": 0, + "domainMax": vc.stepCount - 1, + "point": true, + "round": true, + "range": [0, vc.height] + }); + + // ............................................................. + // Scale - line opacity + vc.scales.push({ + "name": "strokeOpacity", + "type": "linear", + "domain": [0, data.self.coverage["ok_count"] * 2], + "point": true, + "range": [0, 1] + }); + + + // ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + // Marks + + // ............................................................. + // Mark - vertical lines for chords + if (true || vc.guidesAreVisible) { + vc.marks.push({ + "type": "rect", + "from": {"data": "chords"}, + "properties": { + "enter": { + "x": {"field": "chordCoordinate"}, + "y": {"value": 0}, + "width": {"value": 1}, + "height": {"field": {"group": "height"}}, + "fill": {"value": vc.colorForAxes} + }, + } + }); + } + + // ............................................................. + // Mark - vertical lines for N chord + if (vc.nIsIncluded && vc.guidesAreVisible) { + vc.marks.push({ + "type": "rect", + "properties": { + "enter": { + "x": {"field": {"group": "width"}}, + "y": {"value": 0}, + "width": {"value": "1"}, + "height": {"field": {"group": "height"}}, + "fill": {"value": vc.colorForAxes}, + }, + } + }); + } + + // ............................................................. + // Mark - horisontal lines denoting steps + if (vc.guidesAreVisible) { + for (var right = 0; right < 2; right++) { + vc.marks.push({ + "type": "rect", + "from": {"data": "steps"}, + "properties": { + "enter": { + "x": right ? {"field": {"group": "width"}} : {"value": -vc.sizeOfStepMark}, + "width": {"value": vc.sizeOfStepMark}, + "y": {"scale": "indexInSequence", "field": "data"}, + "height": {"value": 1}, + "fill": {"value": vc.colorForAxes}, + } + } + }); + } + } + + // ............................................................. + // Mark - links + vc.marks.push({ + "type": "group", + "from": { + "data": "links", + "transform": [ { + "type": "facet", + "groupby": ["sequenceId"] + } ] + }, + "marks": [{ + "type": "line", + "properties": { + "enter": { + "x": {"field": "chordCoordinate"}, + "y": {"scale": "indexInSequence", "field": "indexInSequence"}, + "strokeOpacity": {"scale": "strokeOpacity", "field": "support"}, + "stroke": {"field": "color"}, + "strokeWidth": {"value": 2}, + }, + "update": { + "strokeOpacity": {"scale": "strokeOpacity", "field": "support"}, + "stroke": {"field": "color"}, + }, + "hover": { + "strokeOpacity": {"value": 1}, + "stroke": {"value": "#000"}, + } + }, + }] + }); + + // ............................................................. + // Mark - group name (primary axis) + vc.yOffsetForGroupLabels = -vc.padding.top + 15; + vc.yOffsetForChordLabels = -3; + + vc.xOffsetForGroupLabels = 0.5 * vc.chordSize * ((vc.chordGrouppingIsByType ? vc.numberOfRootNotes : vc.numberOfChordTypes) - 1); + + if (vc.labelsForGroupsAreShown) { + vc.marks.push({ + "type": "text", + "from": {"data": "groups"}, + "properties": { + "enter": { + "x": {"field": "chordCoordinate", "offset": vc.xOffsetForGroupLabels}, + "y": {"value": vc.yOffsetForGroupLabels}, + "text": {"field": vc.chordGrouppingIsByType ? "chordTypeTitle": "rootNoteTitle"}, + "baseline": {"value":"bottom"}, + "align": {"value": "center"}, + "fill": {"value": vc.colorForAxisLabels}, + "font": {"value": vc.fontFace}, + "fontSize": {"value": vc.fontSizeForLabelsInAxis}, + }, + } + }); + } + + // ............................................................. + // Mark - column name for N + if (vc.nIsIncluded && vc.labelsForGroupsAreShown) { + vc.marks.push({ + "type": "text", + "properties": { + "enter": { + "y": {"value": vc.labelsForChordsAreShown ? vc.yOffsetForChordLabels : vc.yOffsetForGroupLabels}, + "x": {"field": {"group": "width"}}, + "text": {"value":"N"}, + "align": {"value":"center"}, + "baseline": {"value":"bottom"}, + "fill": {"value": vc.colorForAxisLabels}, + "font": {"value": vc.fontFace}, + "fontSize": {"value": vc.fontSizeForLabelsInAxis}, + }, + } + }); + } + + // ............................................................. + // Mark - chord name (secondary axis) + if (vc.labelsForChordsAreShown) { + vc.marks.push({ + "type": "text", + "from": {"data": "chords"}, + "properties": { + "enter": { + "x": {"field": "data.chordCoordinate", "offset": 0}, + "y": {"value": vc.yOffsetForChordLabels}, + "text": {"field": vc.chordGrouppingIsByType ? "data.rootNoteTitle": "data.chordTypeTitle"}, + "angle": {"value": "-90"}, + "baseline": {"value": "middle"}, + "fill": {"value": vc.colorForAxisLabels}, + "font": {"value": vc.fontFace}, + "fontSize": {"value": vc.fontSizeForLabelsInSecondaryAxis}, + }, + } + }); + } + + // ............................................................. + // Mark - fader + vc.marks.push({ + "type": "image", + "from": {"data": "dummy"}, + "properties": { + "enter": { + "x": {"value": 0}, + "width": {"field": {"group": "width"}}, + "y": {"field": {"group": "height"}}, + "height": {"value": vc.padding.bottom + 2}, + "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=="}, + "fill": {"value": "#F00"}, + }, + } + }); + } + }); + }); +}, Logger);