Skip to content
This repository
Browse code

Initial customTheme code for using consistant colors for series of th…

…e same key
  • Loading branch information...
commit a364ca0b9cafbd59e4a9b63a791e292e8d154c3f 1 parent 45ec30c
Bob Monteverde bobmonteverde authored

Showing 3 changed files with 354 additions and 307 deletions. Show diff stats Hide diff stats

  1. +328 307 nv.d3.js
  2. +5 0 nv.d3.min.js
  3. +21 0 src/utils.js
635 nv.d3.js
@@ -272,6 +272,27 @@ nv.utils.defaultColor = function() {
272 272 }
273 273
274 274
  275 +// Returns a color function that takes the result of 'getKey' for each series and
  276 +// looks for a corresponding color from the dictionary,
  277 +nv.utils.customTheme = function(dictionary, getKey, defaultColors) {
  278 + getKey = getKey || function(series) { return series.key }; // use default series.key if getKey is undefined
  279 + defaultColors = defaultColors || d3.scale.category20().range(); //default color function
  280 +
  281 + var defIndex = defaultColors.length; //current default color (going in reverse)
  282 +
  283 + return function(series, index) {
  284 + var key = getKey(series);
  285 +
  286 + if (!defIndex) defIndex = defaultColors.length; //used all the default colors, start over
  287 +
  288 + if (typeof dictionary[key] !== "undefined")
  289 + return (typeof dictionary[key] === "function") ? dictionary[key]() : dictionary[key];
  290 + else
  291 + return defaultColors[--defIndex]; // no match in dictionary, use default color
  292 + }
  293 +}
  294 +
  295 +
275 296
276 297 // From the PJAX example on d3js.org, while this is not really directly needed
277 298 // it's a very cool method for doing pjax, I may expand upon it a little bit,
@@ -2728,313 +2749,313 @@ nv.models.distribution = function() {
2728 2749
2729 2750 return chart;
2730 2751 }
2731   -
2732   -nv.models.indentedTree = function() {
2733   -
2734   - //============================================================
2735   - // Public Variables with Default Settings
2736   - //------------------------------------------------------------
2737   -
2738   - var margin = {top: 0, right: 0, bottom: 0, left: 0} //TODO: implement, maybe as margin on the containing div
2739   - , width = 960
2740   - , height = 500
2741   - , color = nv.utils.defaultColor()
2742   - , id = Math.floor(Math.random() * 10000)
2743   - , header = true
2744   - , noData = "No Data Available."
2745   - , childIndent = 20
2746   - , columns = [{key:'key', label: 'Name', type:'text'}] //TODO: consider functions like chart.addColumn, chart.removeColumn, instead of a block like this
2747   - , tableClass = null
2748   - , iconOpen = 'images/grey-plus.png' //TODO: consider removing this and replacing with a '+' or '-' unless user defines images
2749   - , iconClose = 'images/grey-minus.png'
2750   - , dispatch = d3.dispatch('elementClick', 'elementDblclick', 'elementMouseover', 'elementMouseout')
2751   - ;
2752   -
2753   - //============================================================
2754   -
2755   -
2756   - function chart(selection) {
2757   - selection.each(function(data) {
2758   - var i = 0,
2759   - depth = 1;
2760   -
2761   - var tree = d3.layout.tree()
2762   - .children(function(d) { return d.values })
2763   - .size([height, childIndent]); //Not sure if this is needed now that the result is HTML
2764   -
2765   - chart.update = function() { selection.transition().call(chart) };
2766   - chart.container = this;
2767   -
2768   -
2769   - //------------------------------------------------------------
2770   - // Display No Data message if there's nothing to show.
2771   -
2772   - if (!data[0].key) data[0].key = noData;
2773   -
2774   - //------------------------------------------------------------
2775   -
2776   -
2777   - var nodes = tree.nodes(data[0]);
2778   -
2779   -
2780   - //------------------------------------------------------------
2781   - // Setup containers and skeleton of chart
2782   -
2783   - var wrap = d3.select(this).selectAll('div').data([[nodes]]);
2784   - var wrapEnter = wrap.enter().append('div').attr('class', 'nvd3 nv-wrap nv-indentedtree');
2785   - var tableEnter = wrapEnter.append('table');
2786   - var table = wrap.select('table').attr('width', '100%').attr('class', tableClass);
2787   -
2788   - //------------------------------------------------------------
2789   -
2790   -
2791   - if (header) {
2792   - var thead = tableEnter.append('thead');
2793   -
2794   - var theadRow1 = thead.append('tr');
2795   -
2796   - columns.forEach(function(column) {
2797   - theadRow1
2798   - .append('th')
2799   - .attr('width', column.width ? column.width : '10%')
2800   - .style('text-align', column.type == 'numeric' ? 'right' : 'left')
2801   - .append('span')
2802   - .text(column.label);
2803   - });
2804   - }
2805   -
2806   -
2807   - var tbody = table.selectAll('tbody')
2808   - .data(function(d) {return d });
2809   - tbody.enter().append('tbody');
2810   -
2811   -
2812   -
2813   - //compute max generations
2814   - depth = d3.max(nodes, function(node) { return node.depth });
2815   - tree.size([height, depth * childIndent]); //TODO: see if this is necessary at all
2816   -
2817   -
2818   - // Update the nodes…
2819   - var node = tbody.selectAll('tr')
2820   - .data(function(d) { return d }, function(d) { return d.id || (d.id == ++i)});
2821   - //.style('display', 'table-row'); //TODO: see if this does anything
2822   -
2823   - node.exit().remove();
2824   -
2825   -
2826   - node.select('img.nv-treeicon')
2827   - .attr('src', icon)
2828   - .classed('folded', folded);
2829   -
2830   - var nodeEnter = node.enter().append('tr');
2831   -
2832   -
2833   - columns.forEach(function(column, index) {
2834   -
2835   - var nodeName = nodeEnter.append('td')
2836   - .style('padding-left', function(d) { return (index ? 0 : d.depth * childIndent + 12 + (icon(d) ? 0 : 16)) + 'px' }, 'important') //TODO: check why I did the ternary here
2837   - .style('text-align', column.type == 'numeric' ? 'right' : 'left');
2838   -
2839   -
2840   - if (index == 0) {
2841   - nodeName.append('img')
2842   - .classed('nv-treeicon', true)
2843   - .classed('nv-folded', folded)
2844   - .attr('src', icon)
2845   - .style('width', '14px')
2846   - .style('height', '14px')
2847   - .style('padding', '0 1px')
2848   - .style('display', function(d) { return icon(d) ? 'inline-block' : 'none'; })
2849   - .on('click', click);
2850   - }
2851   -
2852   -
2853   - nodeName.append('span')
2854   - .attr('class', d3.functor(column.classes) )
2855   - .text(function(d) { return column.format ? column.format(d) :
2856   - (d[column.key] || '-') });
2857   -
2858   - if (column.showCount)
2859   - nodeName.append('span')
2860   - .attr('class', 'nv-childrenCount')
2861   - .text(function(d) {
2862   - return ((d.values && d.values.length) || (d._values && d._values.length)) ?
2863   - '(' + ((d.values && d.values.length) || (d._values && d._values.length)) + ')'
2864   - : ''
2865   - });
2866   -
2867   -
2868   - if (column.click)
2869   - nodeName.select('span').on('click', column.click);
2870   -
2871   - });
2872   -
2873   -
2874   - node
2875   - .order()
2876   - .on('click', function(d) {
2877   - dispatch.elementClick({
2878   - row: this, //TODO: decide whether or not this should be consistent with scatter/line events or should be an html link (a href)
2879   - data: d,
2880   - pos: [d.x, d.y]
2881   - });
2882   - })
2883   - .on('dblclick', function(d) {
2884   - dispatch.elementDblclick({
2885   - row: this,
2886   - data: d,
2887   - pos: [d.x, d.y]
2888   - });
2889   - })
2890   - .on('mouseover', function(d) {
2891   - dispatch.elementMouseover({
2892   - row: this,
2893   - data: d,
2894   - pos: [d.x, d.y]
2895   - });
2896   - })
2897   - .on('mouseout', function(d) {
2898   - dispatch.elementMouseout({
2899   - row: this,
2900   - data: d,
2901   - pos: [d.x, d.y]
2902   - });
2903   - });
2904   -
2905   -
2906   -
2907   -
2908   - // Toggle children on click.
2909   - function click(d, _, unshift) {
2910   - d3.event.stopPropagation();
2911   -
2912   - if(d3.event.shiftKey && !unshift) {
2913   - //If you shift-click, it'll toggle fold all the children, instead of itself
2914   - d3.event.shiftKey = false;
2915   - d.values && d.values.forEach(function(node){
2916   - if (node.values || node._values) {
2917   - click(node, 0, true);
2918   - }
2919   - });
2920   - return true;
2921   - }
2922   - if(!hasChildren(d)) {
2923   - //download file
2924   - //window.location.href = d.url;
2925   - return true;
2926   - }
2927   - if (d.values) {
2928   - d._values = d.values;
2929   - d.values = null;
2930   - } else {
2931   - d.values = d._values;
2932   - d._values = null;
2933   - }
2934   - chart.update();
2935   - }
2936   -
2937   -
2938   - function icon(d) {
2939   - return (d._values && d._values.length) ? iconOpen : (d.values && d.values.length) ? iconClose : '';
2940   - }
2941   -
2942   - function folded(d) {
2943   - return (d._values && d._values.length);
2944   - }
2945   -
2946   - function hasChildren(d) {
2947   - var values = d.values || d._values;
2948   -
2949   - return (values && values.length);
2950   - }
2951   -
2952   -
2953   - });
2954   -
2955   - return chart;
2956   - }
2957   -
2958   -
2959   - //============================================================
2960   - // Expose Public Variables
2961   - //------------------------------------------------------------
2962   -
2963   - chart.margin = function(_) {
2964   - if (!arguments.length) return margin;
2965   - margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
2966   - margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
2967   - margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
2968   - margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
2969   - return chart;
2970   - };
2971   -
2972   - chart.width = function(_) {
2973   - if (!arguments.length) return width;
2974   - width = _;
2975   - return chart;
2976   - };
2977   -
2978   - chart.height = function(_) {
2979   - if (!arguments.length) return height;
2980   - height = _;
2981   - return chart;
2982   - };
2983   -
2984   - chart.color = function(_) {
2985   - if (!arguments.length) return color;
2986   - color = nv.utils.getColor(_);
2987   - scatter.color(color);
2988   - return chart;
2989   - };
2990   -
2991   - chart.id = function(_) {
2992   - if (!arguments.length) return id;
2993   - id = _;
2994   - return chart;
2995   - };
2996   -
2997   - chart.header = function(_) {
2998   - if (!arguments.length) return header;
2999   - header = _;
3000   - return chart;
3001   - };
3002   -
3003   - chart.noData = function(_) {
3004   - if (!arguments.length) return noData;
3005   - noData = _;
3006   - return chart;
3007   - };
3008   -
3009   - chart.columns = function(_) {
3010   - if (!arguments.length) return columns;
3011   - columns = _;
3012   - return chart;
3013   - };
3014   -
3015   - chart.tableClass = function(_) {
3016   - if (!arguments.length) return tableClass;
3017   - tableClass = _;
3018   - return chart;
3019   - };
3020   -
3021   - chart.iconOpen = function(_){
3022   - if (!arguments.length) return iconOpen;
3023   - iconOpen = _;
3024   - return chart;
3025   - }
3026   -
3027   - chart.iconClose = function(_){
3028   - if (!arguments.length) return iconClose;
3029   - iconClose = _;
3030   - return chart;
3031   - }
3032   -
3033   - //============================================================
3034   -
3035   -
3036   - return chart;
3037   -}
  2752 +
  2753 +nv.models.indentedTree = function() {
  2754 +
  2755 + //============================================================
  2756 + // Public Variables with Default Settings
  2757 + //------------------------------------------------------------
  2758 +
  2759 + var margin = {top: 0, right: 0, bottom: 0, left: 0} //TODO: implement, maybe as margin on the containing div
  2760 + , width = 960
  2761 + , height = 500
  2762 + , color = nv.utils.defaultColor()
  2763 + , id = Math.floor(Math.random() * 10000)
  2764 + , header = true
  2765 + , noData = "No Data Available."
  2766 + , childIndent = 20
  2767 + , columns = [{key:'key', label: 'Name', type:'text'}] //TODO: consider functions like chart.addColumn, chart.removeColumn, instead of a block like this
  2768 + , tableClass = null
  2769 + , iconOpen = 'images/grey-plus.png' //TODO: consider removing this and replacing with a '+' or '-' unless user defines images
  2770 + , iconClose = 'images/grey-minus.png'
  2771 + , dispatch = d3.dispatch('elementClick', 'elementDblclick', 'elementMouseover', 'elementMouseout')
  2772 + ;
  2773 +
  2774 + //============================================================
  2775 +
  2776 +
  2777 + function chart(selection) {
  2778 + selection.each(function(data) {
  2779 + var i = 0,
  2780 + depth = 1;
  2781 +
  2782 + var tree = d3.layout.tree()
  2783 + .children(function(d) { return d.values })
  2784 + .size([height, childIndent]); //Not sure if this is needed now that the result is HTML
  2785 +
  2786 + chart.update = function() { selection.transition().call(chart) };
  2787 + chart.container = this;
  2788 +
  2789 +
  2790 + //------------------------------------------------------------
  2791 + // Display No Data message if there's nothing to show.
  2792 +
  2793 + if (!data[0].key) data[0].key = noData;
  2794 +
  2795 + //------------------------------------------------------------
  2796 +
  2797 +
  2798 + var nodes = tree.nodes(data[0]);
  2799 +
  2800 +
  2801 + //------------------------------------------------------------
  2802 + // Setup containers and skeleton of chart
  2803 +
  2804 + var wrap = d3.select(this).selectAll('div').data([[nodes]]);
  2805 + var wrapEnter = wrap.enter().append('div').attr('class', 'nvd3 nv-wrap nv-indentedtree');
  2806 + var tableEnter = wrapEnter.append('table');
  2807 + var table = wrap.select('table').attr('width', '100%').attr('class', tableClass);
  2808 +
  2809 + //------------------------------------------------------------
  2810 +
  2811 +
  2812 + if (header) {
  2813 + var thead = tableEnter.append('thead');
  2814 +
  2815 + var theadRow1 = thead.append('tr');
  2816 +
  2817 + columns.forEach(function(column) {
  2818 + theadRow1
  2819 + .append('th')
  2820 + .attr('width', column.width ? column.width : '10%')
  2821 + .style('text-align', column.type == 'numeric' ? 'right' : 'left')
  2822 + .append('span')
  2823 + .text(column.label);
  2824 + });
  2825 + }
  2826 +
  2827 +
  2828 + var tbody = table.selectAll('tbody')
  2829 + .data(function(d) {return d });
  2830 + tbody.enter().append('tbody');
  2831 +
  2832 +
  2833 +
  2834 + //compute max generations
  2835 + depth = d3.max(nodes, function(node) { return node.depth });
  2836 + tree.size([height, depth * childIndent]); //TODO: see if this is necessary at all
  2837 +
  2838 +
  2839 + // Update the nodes…
  2840 + var node = tbody.selectAll('tr')
  2841 + .data(function(d) { return d }, function(d) { return d.id || (d.id == ++i)});
  2842 + //.style('display', 'table-row'); //TODO: see if this does anything
  2843 +
  2844 + node.exit().remove();
  2845 +
  2846 +
  2847 + node.select('img.nv-treeicon')
  2848 + .attr('src', icon)
  2849 + .classed('folded', folded);
  2850 +
  2851 + var nodeEnter = node.enter().append('tr');
  2852 +
  2853 +
  2854 + columns.forEach(function(column, index) {
  2855 +
  2856 + var nodeName = nodeEnter.append('td')
  2857 + .style('padding-left', function(d) { return (index ? 0 : d.depth * childIndent + 12 + (icon(d) ? 0 : 16)) + 'px' }, 'important') //TODO: check why I did the ternary here
  2858 + .style('text-align', column.type == 'numeric' ? 'right' : 'left');
  2859 +
  2860 +
  2861 + if (index == 0) {
  2862 + nodeName.append('img')
  2863 + .classed('nv-treeicon', true)
  2864 + .classed('nv-folded', folded)
  2865 + .attr('src', icon)
  2866 + .style('width', '14px')
  2867 + .style('height', '14px')
  2868 + .style('padding', '0 1px')
  2869 + .style('display', function(d) { return icon(d) ? 'inline-block' : 'none'; })
  2870 + .on('click', click);
  2871 + }
  2872 +
  2873 +
  2874 + nodeName.append('span')
  2875 + .attr('class', d3.functor(column.classes) )
  2876 + .text(function(d) { return column.format ? column.format(d) :
  2877 + (d[column.key] || '-') });
  2878 +
  2879 + if (column.showCount)
  2880 + nodeName.append('span')
  2881 + .attr('class', 'nv-childrenCount')
  2882 + .text(function(d) {
  2883 + return ((d.values && d.values.length) || (d._values && d._values.length)) ?
  2884 + '(' + ((d.values && d.values.length) || (d._values && d._values.length)) + ')'
  2885 + : ''
  2886 + });
  2887 +
  2888 +
  2889 + if (column.click)
  2890 + nodeName.select('span').on('click', column.click);
  2891 +
  2892 + });
  2893 +
  2894 +
  2895 + node
  2896 + .order()
  2897 + .on('click', function(d) {
  2898 + dispatch.elementClick({
  2899 + row: this, //TODO: decide whether or not this should be consistent with scatter/line events or should be an html link (a href)
  2900 + data: d,
  2901 + pos: [d.x, d.y]
  2902 + });
  2903 + })
  2904 + .on('dblclick', function(d) {
  2905 + dispatch.elementDblclick({
  2906 + row: this,
  2907 + data: d,
  2908 + pos: [d.x, d.y]
  2909 + });
  2910 + })
  2911 + .on('mouseover', function(d) {
  2912 + dispatch.elementMouseover({
  2913 + row: this,
  2914 + data: d,
  2915 + pos: [d.x, d.y]
  2916 + });
  2917 + })
  2918 + .on('mouseout', function(d) {
  2919 + dispatch.elementMouseout({
  2920 + row: this,
  2921 + data: d,
  2922 + pos: [d.x, d.y]
  2923 + });
  2924 + });
  2925 +
  2926 +
  2927 +
  2928 +
  2929 + // Toggle children on click.
  2930 + function click(d, _, unshift) {
  2931 + d3.event.stopPropagation();
  2932 +
  2933 + if(d3.event.shiftKey && !unshift) {
  2934 + //If you shift-click, it'll toggle fold all the children, instead of itself
  2935 + d3.event.shiftKey = false;
  2936 + d.values && d.values.forEach(function(node){
  2937 + if (node.values || node._values) {
  2938 + click(node, 0, true);
  2939 + }
  2940 + });
  2941 + return true;
  2942 + }
  2943 + if(!hasChildren(d)) {
  2944 + //download file
  2945 + //window.location.href = d.url;
  2946 + return true;
  2947 + }
  2948 + if (d.values) {
  2949 + d._values = d.values;
  2950 + d.values = null;
  2951 + } else {
  2952 + d.values = d._values;
  2953 + d._values = null;
  2954 + }
  2955 + chart.update();
  2956 + }
  2957 +
  2958 +
  2959 + function icon(d) {
  2960 + return (d._values && d._values.length) ? iconOpen : (d.values && d.values.length) ? iconClose : '';
  2961 + }
  2962 +
  2963 + function folded(d) {
  2964 + return (d._values && d._values.length);
  2965 + }
  2966 +
  2967 + function hasChildren(d) {
  2968 + var values = d.values || d._values;
  2969 +
  2970 + return (values && values.length);
  2971 + }
  2972 +
  2973 +
  2974 + });
  2975 +
  2976 + return chart;
  2977 + }
  2978 +
  2979 +
  2980 + //============================================================
  2981 + // Expose Public Variables
  2982 + //------------------------------------------------------------
  2983 +
  2984 + chart.margin = function(_) {
  2985 + if (!arguments.length) return margin;
  2986 + margin.top = typeof _.top != 'undefined' ? _.top : margin.top;
  2987 + margin.right = typeof _.right != 'undefined' ? _.right : margin.right;
  2988 + margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
  2989 + margin.left = typeof _.left != 'undefined' ? _.left : margin.left;
  2990 + return chart;
  2991 + };
  2992 +
  2993 + chart.width = function(_) {
  2994 + if (!arguments.length) return width;
  2995 + width = _;
  2996 + return chart;
  2997 + };
  2998 +
  2999 + chart.height = function(_) {
  3000 + if (!arguments.length) return height;
  3001 + height = _;
  3002 + return chart;
  3003 + };
  3004 +
  3005 + chart.color = function(_) {
  3006 + if (!arguments.length) return color;
  3007 + color = nv.utils.getColor(_);
  3008 + scatter.color(color);
  3009 + return chart;
  3010 + };
  3011 +
  3012 + chart.id = function(_) {
  3013 + if (!arguments.length) return id;
  3014 + id = _;
  3015 + return chart;
  3016 + };
  3017 +
  3018 + chart.header = function(_) {
  3019 + if (!arguments.length) return header;
  3020 + header = _;
  3021 + return chart;
  3022 + };
  3023 +
  3024 + chart.noData = function(_) {
  3025 + if (!arguments.length) return noData;
  3026 + noData = _;
  3027 + return chart;
  3028 + };
  3029 +
  3030 + chart.columns = function(_) {
  3031 + if (!arguments.length) return columns;
  3032 + columns = _;
  3033 + return chart;
  3034 + };
  3035 +
  3036 + chart.tableClass = function(_) {
  3037 + if (!arguments.length) return tableClass;
  3038 + tableClass = _;
  3039 + return chart;
  3040 + };
  3041 +
  3042 + chart.iconOpen = function(_){
  3043 + if (!arguments.length) return iconOpen;
  3044 + iconOpen = _;
  3045 + return chart;
  3046 + }
  3047 +
  3048 + chart.iconClose = function(_){
  3049 + if (!arguments.length) return iconClose;
  3050 + iconClose = _;
  3051 + return chart;
  3052 + }
  3053 +
  3054 + //============================================================
  3055 +
  3056 +
  3057 + return chart;
  3058 +}
3038 3059 nv.models.legend = function() {
3039 3060
3040 3061 //============================================================
5 nv.d3.min.js
5 additions, 0 deletions not shown
21 src/utils.js
@@ -58,6 +58,27 @@ nv.utils.defaultColor = function() {
58 58 }
59 59
60 60
  61 +// Returns a color function that takes the result of 'getKey' for each series and
  62 +// looks for a corresponding color from the dictionary,
  63 +nv.utils.customTheme = function(dictionary, getKey, defaultColors) {
  64 + getKey = getKey || function(series) { return series.key }; // use default series.key if getKey is undefined
  65 + defaultColors = defaultColors || d3.scale.category20().range(); //default color function
  66 +
  67 + var defIndex = defaultColors.length; //current default color (going in reverse)
  68 +
  69 + return function(series, index) {
  70 + var key = getKey(series);
  71 +
  72 + if (!defIndex) defIndex = defaultColors.length; //used all the default colors, start over
  73 +
  74 + if (typeof dictionary[key] !== "undefined")
  75 + return (typeof dictionary[key] === "function") ? dictionary[key]() : dictionary[key];
  76 + else
  77 + return defaultColors[--defIndex]; // no match in dictionary, use default color
  78 + }
  79 +}
  80 +
  81 +
61 82
62 83 // From the PJAX example on d3js.org, while this is not really directly needed
63 84 // it's a very cool method for doing pjax, I may expand upon it a little bit,

0 comments on commit a364ca0

Please sign in to comment.
Something went wrong with that request. Please try again.