Mercurial > hg > dml-open-vis
view 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 source
"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);