/** * creates a sankey chart in the sidebar * monitors for data changes and replots if there are any * details at http://ramblings.mcpher.com/Home/excelquirks/addons/sankeyaddon */ var Sankey = (function(sankey) { 'use strict'; /** * draw a sankey * @param {object} sets the chart settings * @param {string[]} headers * @param {[[string,string,number]]} data * @param {element} chartElem where to put it * @param {boolean} clear whether to clear current chart. */ sankey.drawChart = function (sets,headers, data, chartElem,clear) { // clone the settings var settings = Utils.clone (sets); if(clear) { chartElem.innerHTML = ""; } // this might fail since we could pick up the data at any point - but that's ok try { // dont let the from and to field be the same if (headers[0] === headers[1]) return; // assuming the data is all clean here var dataTable = new google.visualization.DataTable(); dataTable.addColumn ('string' , headers[0]); dataTable.addColumn ('string' , headers[1]); dataTable.addColumn ('number' , headers[2]); dataTable.addColumn({type: 'string', role: 'tooltip'}); // assign data - be lenient with mismatched data types dataTable.addRows(data.map(function(d) { return [d[0].toString(), d[1].toString() , parseInt (d[2],10) , d[0] + ">" + d[1] + "(" + d[2] + ")"]; }).filter(function(d){ // get rid of blank rows (0 volumes will not be plotted either) return d[0] && d[1] && !isNaN(d[2]) && d[2]; })); // Instantiate and draw our chart, passing in some options. var chart = new google.visualization.Sankey(chartElem); chart.draw(dataTable, settings); } catch (err) { // no need - probably just means the line is not complete yet } }; sankey.doElementer = function (setup) { return new Elementer() .setMain('') .setContainer('elementer-content') .setRoot('elementer-root') .setLayout(setup.layout) .setDetail(setup.detail) .build(); }; sankey.mapSettings = function (arger) { var ec = arger.getElements().controls; return { height: parseInt(ec.previewHeight.value, 10), width: parseInt(ec.previewWidth.value, 10), scale: { width: parseFloat(ec.scaleWidth.value), height: parseFloat(ec.scaleHeight.value), font: parseFloat(ec.scaleFont.value) }, options:{ height:parseInt(ec.previewHeight.value, 10), width:parseInt(ec.previewWidth.value, 10), tooltip:{ textStyle:{ fontName: ec.tooltipFontName.value, fontSize: parseInt(ec.tooltipFontSize.value, 10), color: ec.tooltipFontColor.value, bold: ec.tooltipFontBold.checked, italic: ec.tooltipFontItalic.checked }, isHtml:false }, sankey: { link: { colorMode:ec.linkColorMode.value, color: { fill: ec.linkFillColor.value, // Color of the link. fillOpacity: parseFloat(ec.linkOpacity.value), // Transparency of the link. stroke: ec.linkBorderColor.value, // Color of the link border. strokeWidth: parseInt(ec.linkBorderWidth.value, 10) // Thickness of the link border } }, node: { label: { fontName: ec.labelFontName.value, fontSize: parseInt(ec.labelFontSize.value, 10), color: ec.labelFontColor.value, bold: ec.labelFontBold.checked, italic: ec.labelFontItalic.checked }, labelPadding: parseInt(ec.labelPadding.value, 10), // Horizontal distance between the lab nodePadding: parseInt(ec.nodePadding.value, 10), // Vertical distance between nodes. width: parseInt(ec.nodeWidth.value, 10) // Thickness of the node. } } } }; }; sankey.setup = function() { return { detail: { sourceDivider: { template: "dividerTemplate", label: "Source data" }, filterDivider: { template: "dividerTemplate", label: "Filtering" }, columnDivider: { template: "dividerTemplate", label: "Columns" }, embedDivider: { template: "dividerTemplate", label:"Image embed code" }, manageDivider: { template: "dividerTemplate", label:"Manage settings" }, useStandard: { template: "radioTemplate", label: "Standard", icon: "tuner", properties:{ name:"use-group" }, values:{ resetable:false } }, useDocument: { template: "radioTemplate", label: "This document's settings", icon: "playlist_play", properties:{ name:"use-group" }, values:{ resetable:false } }, useUser: { template: "radioTemplate", label: "My personal settings", icon: "fingerprint", properties:{ name:"use-group" }, values:{ resetable:false } }, useInitial: { template: "radioTemplate", label: "Reset to initial", icon: "undo", properties:{ name:"use-group" }, values:{ value:true, resetable:false } }, makePermanent: { template: "radioTemplate", label: "Save for future use in this document", icon: "playlist_add_check", properties:{ name:"manage-group" }, values:{ resetable:false, value:true } }, makeDefault: { template: "radioTemplate", label: "Save for future use in all my documents", icon: "playlist_add", properties:{ name:"manage-group" }, values:{ resetable:false } }, clearPermanent: { template: "radioTemplate", label: "Clear saved settings in this document", icon: "settings_backup_restore", properties:{ name:"manage-group" }, values:{ resetable:false } }, clearDefault: { template: "radioTemplate", label: "Clear all my saved default settings", icon: "layers_clear", properties:{ name:"manage-group" }, values:{ resetable:false } }, manageButton:{ template:"buttonTemplate", classes: { element:"action" }, values:{ value:"SAVE" } }, resetButton_dataSettings:{ template:"resetButtonTemplate" }, resetButton_embedCode:{ template:"resetButtonTemplate", custom:{ cancelOnly:true } }, resetButton_arrangePreview:{ template:"resetButtonTemplate" }, resetButton_links:{ template:"resetButtonTemplate" }, resetButton_nodes:{ template:"resetButtonTemplate" }, resetButton_tooltips:{ template:"resetButtonTemplate" }, resetButton_scaleRatio:{ template:"resetButtonTemplate" }, applyButton:{ template:"buttonTemplate", classes:{ element:"action" }, values:{ value:"APPLY" }, }, wholeSheet: { template: "radioTemplate", label: "Whole sheet", icon: "grid_on", values: { value: true, resetable:true }, properties:{ name:"range-group" }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_dataSettings.disabled = false; } } }, selectedRange: { template: "radioTemplate", label: "Selected range", icon: "domain", properties:{ name:"range-group" }, values:{ resetable:true }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_dataSettings.disabled = false; } } }, fromColumn: { template: "selectTemplate", label: "Source column", icon: "skip_previous", values:{ resetable:true }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_dataSettings.disabled = false; } } }, toColumn: { template: "selectTemplate", label: "Target column", icon: "skip_next", values:{ resetable:true }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_dataSettings.disabled = false; } } }, weightColumn: { template: "selectTemplate", label: "Weight column", icon: "network_check", values:{ resetable:true }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_dataSettings.disabled = false; } } }, applyFilters: { template: "checkboxTemplate", label: "Respect filters in data", icon: "filter_list", values:{ resetable:true }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_dataSettings.disabled = false; } } }, previewWidth: { template: "numberTemplate", label: "Width", icon: "crop_landscape", properties:{ max:600 }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_arrangePreview.disabled = false; } } }, previewHeight: { template: "numberTemplate", label: "Height", icon: "crop_portrait", properties:{ max:600 }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_arrangePreview.disabled = false; } } }, scaleWidth: { template: "numberTemplate", label: "Width of embedded chart", icon: "picture_in_picture_alt", properties: { max: 1200, min: 100, step: 1 }, values:{ value:600 }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_scaleRatio.disabled = false; } } }, scaleHeight: { template: "numberTemplate", label: "Height of embedded chart", icon: "picture_in_picture", properties: { max: 1200, min: 100, step: 1 }, values:{ value:400 }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_scaleRatio.disabled = false; } } }, scaleFont: { template: "numberTemplate", label: "Font size of embedded chart", icon: "format_size", properties: { max: 32, min: 6, step: 1 }, values:{ value:12 }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_scaleRatio.disabled = false; } } }, nodePadding: { template: "numberTemplate", label: "Vertical spacing between nodes", icon: "vertical_align_bottom", properties: { max: 20, min: 0 }, values:{ value:10 }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_nodes.disabled = false; } } }, nodeWidth: { template: "numberTemplate", label: "Thickness of node", icon: "flip", properties: { max: 20, min: 0 }, values:{ value:5 }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_nodes.disabled = false; } } }, tooltipFontSize: { template: "numberTemplate", label: "Font size", icon: "format_size", properties: { min: 6, max: 20 }, values:{ value:10 }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_tooltips.disabled = false; } } }, tooltipFontName: { template: "textTemplate", label: "Font name", icon: "text_fields", values: { value: "Roboto" }, styles:{ element:"width:80px;" }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_tooltips.disabled = false; } } }, tooltipFontColor: { template: "textTemplate", label: "Font color", icon: "format_color_text", properties: { type: "color" }, values:{ value:"#212121" }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_tooltips.disabled = false; } } }, tooltipFontBold: { template: "checkboxTemplate", label: "Bold", icon: "format_bold", on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_tooltips.disabled = false; } } }, tooltipFontItalic: { template: "checkboxTemplate", label: "Italic", icon: "format_italic", on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_tooltips.disabled = false; } } }, linkColorMode:{ template:"selectTemplate", label:"Color mode", icon:"gradient", options:["none","source","target","gradient"], values:{ value:"none" }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_links.disabled = false; } } }, linkFillColor: { template: "textTemplate", label: "Background color", icon: "format_color_fill", properties: { type: "color", value: '#eeeeee' }, values:{ value:'#eeeeee' }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_links.disabled = false; } } }, linkBorderWidth: { template: "numberTemplate", label: "Border width", icon: "line_weight", properties: { max: 5, min: 0 }, values:{ value:0 }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_links.disabled = false; } } }, linkBorderColor: { template: "textTemplate", label: "Border color", icon: "border_color", properties: { type: "color" }, values:{ value:'#212121' }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_links.disabled = false; } } }, linkOpacity: { template: "numberTemplate", label: "Opacity", icon: "opacity", properties: { min: 0, max: 1, step: 0.1 }, values:{ value:0.4 }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_links.disabled = false; } } }, labelDivider: { template: "dividerTemplate", label: "Labels" }, labelPadding: { template: "numberTemplate", label: "Label padding", icon: "format_indent_increase", properties: { max: 20, min: 0, value: 6 }, values:{ value:6 }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_nodes.disabled = false; } } }, labelFontSize: { template: "numberTemplate", label: "Font size", icon: "format_size", properties: { min: 4, max: 24 }, values:{ value:10 }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_nodes.disabled = false; } } }, labelFontName: { template: "textTemplate", label: "Font name", icon: "text_fields", values: { value: "Roboto" }, styles:{ element:"width:80px;" } }, labelFontColor: { template: "textTemplate", label: "Font color", icon: "format_color_text", properties: { type: "color" }, values:{ value:'#212121' }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_nodes.disabled = false; } } }, labelFontBold: { template: "checkboxTemplate", label: "Bold", values:{ value:false }, icon: "format_bold", on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_nodes.disabled = false; } } }, labelFontItalic: { template: "checkboxTemplate", label: "Italic", icon: "format_italic", values:{ value:false }, on: { change: function (elementer, branch , ob,e) { elementer.getElements().controls.resetButton_nodes.disabled = false; } } }, svgLabel: { template:"contentTemplate", label: "Copy embeddable SVG code below", styles:{ tdLabel:"border-width:0px;" } }, svgCode: { template: "textAreaTemplate", label: "", properties: { disabled: true, rows: 16, spellcheck: false }, classes:{ elementContainer:"mui--text-dark-hint", }, values:{ resetable:false } }, chartDivider:{ label:"Chart settings", template:"dividerTemplate" }, dataDivider:{ label:"Source data settings", template:"dividerTemplate" }, }, layout: { settings: { prefix: "layout", root: "root" }, pages: { root: { label: "Settings menu", items: ["chartDivider", "arrangePreview", "scaleRatio","saveSettings","manageSettings","dataDivider","dataSettings","embedDivider","embedCode"] }, dataSettings: { label: "Data", items: ["sourceDivider", "wholeSheet", "selectedRange", "columnDivider", "fromColumn", "toColumn", "weightColumn","filterDivider","applyFilters","resetButton_dataSettings"], on:{ enter:function (elementer,branch) { elementer.getElements().controls.resetButton_dataSettings.disabled = true; Process.reserveResetValues (elementer, branch); }, exit:function (elementer, branch) { Process.restoreResetValues (Process.control.sankey.elementer , branch); } } }, manageSettings: { label:"Reset", items:["useInitial","useStandard","useUser", "useDocument","applyButton"], on: { exit: function (elementer, branch) { // reset the buttons to apply next time in Process.control.buttons.apply.disabled=false; } } }, saveSettings: { label:"Save", items:["makePermanent","makeDefault","clearPermanent","clearDefault","manageButton"], on: { exit: function (elementer, branch) { // reset the buttons to apply next time in Process.control.buttons.manage.disabled=false; } } }, embedCode: { label: "Get", items: ["svgLabel","svgCode","resetButton_embedCode"] }, arrangePreview: { label: "Appearance", items: ["previewHeight", "previewWidth", "links", "nodes","tooltips","resetButton_arrangePreview"], on:{ enter:function (elementer,branch) { elementer.getElements().controls.resetButton_arrangePreview.disabled = true; Process.reserveResetValues (elementer, branch); }, exit:function (elementer, branch) { Process.restoreResetValues (Process.control.sankey.elementer , branch); } } }, scaleRatio: { label: "Scale", items: ["scaleHeight", "scaleWidth", "scaleFont","resetButton_scaleRatio"], on:{ enter:function (elementer,branch) { elementer.getElements().controls.resetButton_scaleRatio.disabled = true; Process.reserveResetValues (elementer, branch); }, exit:function (elementer, branch) { Process.restoreResetValues (Process.control.sankey.elementer , branch); } } }, links: { label: "Links", items: ["linkColorMode","linkFillColor", "linkOpacity", "linkBorderColor", "linkBorderWidth","resetButton_links"], on:{ enter:function (elementer,branch) { elementer.getElements().controls.resetButton_links.disabled = true; Process.reserveResetValues (elementer, branch); }, exit:function (elementer, branch) { Process.restoreResetValues (Process.control.sankey.elementer , branch); } } }, nodes: { label: "Nodes", items: ["nodePadding", "nodeWidth", "labelDivider", "labelPadding", "labelFontSize", "labelFontColor", "labelFontName","labelFontBold", "labelFontItalic","resetButton_nodes"], on:{ enter:function (elementer,branch) { elementer.getElements().controls.resetButton_nodes.disabled = true; Process.reserveResetValues (elementer, branch); }, exit:function (elementer, branch) { Process.restoreResetValues (Process.control.sankey.elementer , branch); } } }, tooltips: { label: "Tooltips", items: ["tooltipFontSize", "tooltipFontColor", "tooltipFontName","tooltipFontBold", "tooltipFontItalic","resetButton_tooltips"], on:{ enter:function (elementer,branch) { elementer.getElements().controls.resetButton_tooltips.disabled = true; Process.reserveResetValues (elementer, branch); }, exit:function (elementer, branch) { Process.restoreResetValues (Process.control.sankey.elementer , branch); } } } } } } }; return sankey; })(Sankey || {});