Funnel Chart series data color

  • 1
  • Question
  • Updated 9 months ago
  • Answered
Hello,

I have a Chart use case , but have been unable to find what I need reading through all of the chart related posts and Highchart api's.  I have a simple sales pipeline funnel chart to represent the Opportunity Stages.  I have customized with a short snippet and added 4 styling colors in action framework.

The execs want the Stages to remain the same color regardless of the data results:
                           
                                    stage1 should always be blue
                                    stage2 should always be yellow  etc etc

I have tried to implement Rob's snippet https://community.skuid.com/skuid/topics/have-certain-colors-represent-certain-values-in-charts, but is not working for the funnel chart.  I am currently using the snippet below to show data label values, and need to add in the color per stage (series) code.   If this can't be accomplished, are there any workarounds to achieve this?  Would be great if the Salesforce assigned stage colors were in Skuid metadata.   Any help or examples would be greatly appreciated.   My current data value snippet that I need to add this to is below.  Thanks


var chartObj = arguments[0],
$ = skuid.$;
$.extend(true, chartObj.plotOptions,{
        funnel: {        
                dataLabels: {
                   format: "${point.y:,.0f}.00",
                    enabled: true,
                    color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'black',
            }
        }        
});
Photo of Ann Kukich

Ann Kukich

  • 1,316 Points 1k badge 2x thumb

Posted 10 months ago

  • 1
Photo of Bill McCullough

Bill McCullough, Champion

  • 12,436 Points 10k badge 2x thumb
Ann,

Rob's snippet does work for the funnel chart.  I think you just need to make sure that you set the colors for the chart in the page builder.  Then the first color becomes 'ind=0', the second color is 'ind=1'; etc.

Here is a sample page.

Thanks,

Bill

<skuidpage unsavedchangeswarning="yes" personalizationmode="server" showsidebar="true" useviewportmeta="true" showheader="true">
    <models>
        <model id="OppByStage" limit="" query="true" createrowifnonefound="false" datasource="salesforce" type="aggregate" sobject="Opportunity">
            <fields>
                <field id="Amount" name="sumAmount" function="SUM"/>
            </fields>
            <conditions/>
            <actions/>
            <groupby method="simple">
                <field id="StageName" name="stageName"/>
            </groupby>
        </model>
    </models>
    <components>
        <skuidvis__chart model="OppByStage" maintitle="{{Model.labelPlural}}" type="funnel" uniqueid="sk-jRzxt-286" rendersnippet="beforeRender">
            <dataaxes>
                <axis id="axis1"/>
            </dataaxes>
            <categoryaxes>
                <axis id="categories" categorytype="field"/>
            </categoryaxes>
            <serieslist>
                <series valuefield="sumAmount" splittype="field" splitfield="stageName"/>
            </serieslist>
            <colors>
                <value>#ff0000</value>
                <value>#00ff00</value>
                <value>#0000ff</value>
                <value>#ff00ff</value>
                <value>#ffff00</value>
                <value>#330033</value>
                <value>#220011</value>
                <value>#81d4fa</value>
                <value>#9575cd</value>
                <value>#5c6bc0</value>
                <value>#5677fc</value>
                <value>#039be5</value>
                <value>#512da8</value>
                <value>#283593</value>
            </colors>
            <legend layout="horizontal" halign="center" valign="bottom"/>
            <renderconditions logictype="and"/>
        </skuidvis__chart>
    </components>
    <resources>
        <labels/>
        <javascript>
            <jsitem location="inlinesnippet" name="beforeRender" cachelocation="false">var chartObj = arguments[0],
$ = skuid.$;

s = chartObj.series;
ind = 0,
//for each series entry grab series id.  Based on id value set ind variable.
    $.each(s, function (i, s){   
        switch(s.id) {       
        case "Prospecting": ind = 0; break;
        case "Qualification": ind = 1; break;
        case "Needs Analysis": ind = 2; break;
        case "Value Proposition": ind = 3; break;
        case "Id. Decision Makers": ind = 4; break;
        case "Perception Analysis": ind = 5; break;
        case "Proposal/Price Quote": ind = 6; break;
        case "Negotiation/Review": ind = 7; break;
        case "Invoice": ind = 8;  break;
        case "Closed Won": ind = 9;  break;
        case "Closed Lost": ind = 10; break;
        default: ind = 10;
        }       
// update series index number and color index with ind variable.
        $.extend(true, chartObj.series[i],{
            index: ind,
            _colorIndex: ind
        });
    })

$.extend(true, chartObj.plotOptions,{
        funnel: {       
                dataLabels: {
                   format: "{point.name}: ${point.y:,.0f}.00",
                    enabled: true,
                    color: (Highcharts.theme &amp;&amp; Highcharts.theme.dataLabelsColor) || 'black',
            }
        }       
});
console.log(chartObj);</jsitem>
        </javascript>
        <css/>
        <actionsequences uniqueid="sk-jRwWU-266"/>
    </resources>
    <styles>
        <styleitem type="background" bgtype="none"/>
    </styles>
</skuidpage>
Photo of Ann Kukich

Ann Kukich

  • 1,316 Points 1k badge 2x thumb
This works perfectly Bill!   Thank you!!
Photo of Ann Kukich

Ann Kukich

  • 1,316 Points 1k badge 2x thumb
Hi Bill,

This works great keeping the colors in an order, but when there are no records for a certain stage the colors do not follow the stage name.  I only have 3 stages to deal with for this, so I am thinking this shouldn't be too difficult?

I have tried to modify the code to grab the point.series.name, series.point.series.name, etc etc but nothing I am doing is working for this.

Any suggestions on this?

Thanks Bill,
Ann
Photo of Ann Kukich

Ann Kukich

  • 1,316 Points 1k badge 2x thumb
Just a quick update on this in case anyone needs a workaround.  Not the greatest workaround, but because our company only has 5 Sales people and 4 Pipeline stages, I decided to go ahead with this for now.

I created 4 "house" dummy opportunities for each Salesperson, for each Stage, with an Amount value of $0.00.   Used a different record type than real Opportunites so that I could control which models pull these, in our case it is 5 Pipeline funnel charts.  

The Pipeline series now shows all 4 Stages in the funnel chart, which results in the Stages having the same color on all funnel charts for all pages.  The only downsides (besides creating extra records), is there are $0.00 values that show in the chart if there are no records in that stage.  I am ok with that for now until I have more time to take a deeper dive into HighCharts.   
Photo of Bill McCullough

Bill McCullough, Champion

  • 12,436 Points 10k badge 2x thumb
Ann,

This turned out to be tricky.  According to Highcharts' reference, you should be able to add the color you want to the data series and have it display that color.  I could not get this to work.  It seems like Skuid wants to apply its color theme.

In Rob's script, he sets the colorIndex.  While this does line up the colors, they aren't 'sticky' to their index.  If you have fewer stages than colors defined, you end up with the first color to the first stage found (and not the index that you expect).

What worked for me is to render the chart using a Template component.  This let me build up the data series and set the colors in a way that is 'sticky'.

Here is a sample you can use.  You can edit the colors by editing the inline snippet called 'renderChartFunctions'.  You will also need to set the model name that is used for the data series.

Thanks,

Bill


<skuidpage unsavedchangeswarning="yes" personalizationmode="server" showsidebar="false" useviewportmeta="true" showheader="false">
    <models>
        <model id="OppByStage" limit="" query="true" createrowifnonefound="false" datasource="salesforce" type="aggregate" sobject="Opportunity">
            <fields>
                <field id="Amount" name="sumAmount" function="SUM"/>
            </fields>
            <conditions>
                <condition type="multiple" value="" field="StageName" operator="in" enclosevalueinquotes="true" state="filterableoff" inactive="true" name="StageName">
                    <values>
                        <value>Closed Won</value>
                        <value>Proposal/Quote</value>
                    </values>
                </condition>
            </conditions>
            <actions>
                <action>
                    <actions>
                        <action type="custom" snippet="rerenderChartRequery"/>
                    </actions>
                    <events>
                        <event>models.loaded</event>
                    </events>
                </action>
            </actions>
            <groupby method="simple">
                <field id="StageName" name="stageName"/>
            </groupby>
        </model>
    </models>
    <components>
        <filterset model="OppByStage" searchmethod="server" searchbox="false" uniqueid="sk-1Tnxq6-955" emptysearchbehavior="query">
            <filters>
                <filter type="toggle" filteroffoptionlabel="New Filter" createfilteroffoption="true" affectcookies="false" autocompthreshold="25" conditionsource="manual" labelmode="auto" filtermethod="server" label="Activate  Stage Filter">
                    <effects>
                        <effect action="activate" value="" condition="StageName"/>
                    </effects>
                </filter>
            </filters>
            <searchfields/>
        </filterset>
        <template multiple="false" uniqueid="sk-1Trafj-257" allowhtml="true">
            <contents>&lt;div id="container" style="min-width: 300px; max-width: 800px; margin: 0 auto"&gt;&lt;/div&gt;
</contents>
        </template>
    </components>
    <resources>
        <labels/>
        <javascript>
            <jsitem location="external" name="highCharts" cachelocation="false" url="https://code.highcharts.com/highcharts.js">var params = arguments[0],
$ = skuid.$;
</jsitem>
            <jsitem location="external" name="funnel" cachelocation="false" url="https://code.highcharts.com/modules/funnel.js">var params = arguments[0],
$ = skuid.$;
</jsitem>
            <jsitem location="external" name="export" cachelocation="false" url="https://code.highcharts.com/modules/exporting.js">var params = arguments[0],
$ = skuid.$;
</jsitem>
            <jsitem location="inline" name="renderChartFunctions" cachelocation="false" url="">function renderfunnel() {
    var myModel = skuid.model.getModel('OppByStage');
console.log(myModel);
        var chartData = [];
        for (var j=0; j&lt;myModel.data.length; j++) {
        console.log(myModel.data[j]);
        var item = {name: myModel.data[j].stageName, y: myModel.data[j].sumAmount, color: getColor(myModel.data[j].stageName)};
        chartData.push(item);
        }
        console.log('chartData');
        console.log(chartData);
        Highcharts.chart('container', {
            chart: {
                type: 'funnel'
            },
            title: {
                text: 'Opportunity Funnel'
            },
            subtitle: {
                text: 'Resize the frame or click buttons to change appearance'
            },
            plotOptions: {
                series: {
                    dataLabels: {
                        enabled: true,
                        format: '&lt;b&gt;{point.name}&lt;/b&gt; ({point.y:,.0f})',
                        color: (Highcharts.theme &amp;&amp; Highcharts.theme.contrastTextColor) || 'black',
                        softConnector: true
                    },
                    center: ['40%', '50%'],
                    neckWidth: '30%',
                    neckHeight: '25%',
                    width: '80%'
                }
            },
            legend: {
                enabled: false
            },
            responsive: {
                rules: [{
                    condition: {
                        maxWidth: 500
                    },
                    chartOptions: {
                        legend: {
                            align: 'center',
                            verticalAlign: 'bottom',
                            layout: 'horizontal'
                        },
                        yAxis: {
                            labels: {
                                align: 'left',
                                x: 0,
                                y: -5
                            },
                            title: {
                                text: null
                            }
                        },
                        subtitle: {
                            text: null
                        },
                        credits: {
                            enabled: false
                        }
                    }
                }]
            },
            series: [{
                name: 'Opportunities',
                data: chartData
            }]
        });

} //end renderfunnel function

function getColor(stagename) {
    switch(stagename) {
    case "Prospecting": return '#8E388E';
    case "Qualification": return'#7D9EC0';
    case "Needs Analysis": return'#388E8E';
    case "Value Proposition": return'#71C671';
    case "Id. Decision Makers": return'#C5C1AA';
    case "Perception Analysis": return'#C67171';
    case "Proposal/Quote": return'#FFC125';
    case "Negotiation/Review": return'#B3EE3A';
    case "Invoice": return'#98F5FF';
    case "Closed Won": return'#63B8FF';
    case "Closed Lost": return'#EE00EE';
    default: return'#FF3E96';
    }
}</jsitem>
            <jsitem location="inline" name="renderChartPageLoad" cachelocation="false" url="">(function(skuid){
var $ = skuid.$;
$(document.body).one('pageload',function(){
    renderfunnel();
});

})(skuid);</jsitem>
            <jsitem location="inlinesnippet" name="rerenderChartRequery" cachelocation="false">var params = arguments[0],
$ = skuid.$;
renderfunnel();</jsitem>
        </javascript>
        <css/>
        <actionsequences uniqueid="sk-jRwWU-266"/>
    </resources>
    <styles>
        <styleitem type="background" bgtype="none"/>
    </styles>
</skuidpage>
(Edited)
Photo of Ann Kukich

Ann Kukich

  • 1,316 Points 1k badge 2x thumb
Wow, this is great.   I have applied this to a couple of charts so far and was able to modify as needed.  This would have taken me over a year to figure out, thanks Bill for spending the time on this, not only does it work well, but explains alot on how the Highchart api works

Ann