Anyone ever seen pictures of west-cost start-ups with those TV screens front and center showing some sort of stat or metric? If it is a dev house maybe it is the builds, bugs, & deadlines. A sales firm may have revenue, opportunities and a highlight of recently closed deals. Either way, they are meant to highlight data and allow it to be consumed in a very passive manner, reading it as you pass by. Salesforce makes reports a breeze and dashboards are a snap too. However, what if you wanted to recreate that seamless look, without the tabs, browser UI, or any indication of what is driving the display at all? Sure, there are tons of articles that show you how to get PowerPoint to do that, but using stale data is for suckers. Let’s take a look at what some Apex, Visualforce and JavaScript could do for you.

We should start with the controller.

    public class ChartController {
    
        public class ChartData
        { 
            public String name { get; set; } 
            public Decimal data { get; set; } 
    
            public ChartData(String name, Decimal data)
            { 
                this.name = name; 
                this.data = data; 
            } 
        }  
    
    }

A good start but missing any real meat. Let’s look at what is there, shall we? Pretty much the only thing in this class so far is a nested wrapper class. This is just a convenient way to get data to the charts. Feel free to do your own thing if this isn’t your style. We better add a way to get some data.

    
    public List<ChartData> casePriorityData
        {
            get
            {
                casePriorityData  = new List<ChartData>();
                for(AggregateResult res : [SELECT Priority, Count(Id)
                                          FROM Case
                                          GROUP BY Priority])
                {
                    casePriorityData.add(new ChartData(
                        (String)res.get('Priority'),
                        (Decimal)res.get('expr0'))
                    );
                }
    
                return casePriorityData;
            }
            set;
        }

This looks promising! This method grabs all the cases, groups them by priority, then counts the number of cases in those groups. We iterate over that data and toss it into that wrapper object from the prior code block. Add as many of these chunks of code as you want, one for each chart you feel like creating. We are almost done the controller, just one more piece.

    
    public void refreshCharts()
        {
            casePriorityData = null;
            opportunityStageData = null;
        }

This to-the-point bit of code is there to erase the current set of data so it can be refreshed. Remember what I said about stale data being for suckers? This prevents you from being a sucker. Put all of those together and you get a completed controller (mine has a second list of chart data because a one slide slideshow is boring).

    
    public class ChartController {
    
        public List<ChartData> casePriorityData
        {
            get
            {
                casePriorityData  = new List<ChartData>();
                for(AggregateResult res : [SELECT Priority, Count(Id)
                                          FROM Case
                                          GROUP BY Priority])
                {
                    casePriorityData.add(new ChartData(
                        (String)res.get('Priority'),
                        (Decimal)res.get('expr0'))
                    );
                }
    
                return casePriorityData;
            }
            set;
        } 
    
        public List<ChartData> opportunityStageData
        {
            get
            {
                opportunityStageData= new List<ChartData>();
                for(AggregateResult res : [SELECT StageName, Count(Id)
                                          FROM Opportunity
                                          GROUP BY StageName])
                {
                    opportunityStageData.add(new ChartData(
                        (String)res.get('StageName'),
                        (Decimal)res.get('expr0'))
                    );
                }
                return opportunityStageData;
            }
            set;
        } 
    
        public void refreshCharts()
        {
            casePriorityData = null;
            opportunityStageData = null;
        }
    
        public class ChartData
        { 
            public String name { get; set; } 
            public Decimal data { get; set; } 
    
            public ChartData(String name, Decimal data)
            { 
                this.name = name; 
                this.data = data; 
            } 
        }  
    
    }

On to the Visualforce. We will start off small again and build from there.

    
    <apex:page
        controller="ChartController"
        showHeader="false" sidebar="false">
    
    </apex:page>

This is the base, telling the page to use the ChartController and to not show the header or sidebar. Remember, we don’t want this looking like a webpage or a browser, just a slideshow. Now we need a chart.

    
    <div class="slide activeSlide">
        <apex:chart height="800px" width="1500px"
            data="{!opportunityStageData}" id="oppStageData">
            <apex:pieSeries tips="false" dataField="data"
                labelField="name"/>
            <apex:legend position="bottom"/>
        </apex:chart>
    </div>

This is an apex chart. The width and the height shown here are based on my screen size and layout. If you have extra styling or branding on your slideshow (Trust me, you will want it. The end result of this is bare bones.) you will need to change these values to fit. The apex:chart tag also tells the page what data to use and the id will be used to keep the data fresh. The apex:pieSeries tag tells the page that the data comes from the data field on the wrapper and that the label comes from the name field. There is also the apex:legend tag which provides a legend in the position specified. Finally all of that is wrapped in a div that will provide us the means to allow for movement. Like with the controller, you need one of these for each list of ChartData that you created, just leave the ‘activeSlide’ style off the rest. We still need to code to bring this to life. Let’s begin with the styling first.

    
    <style>
        .slide{
            position: absolute;
            top:0px;
            left: 0px;
            background-color: white;
            z-index: 1;
        }
    
        .activeSlide{
            z-index: 999;
        }
    </style>

Simple stuff here. The ‘side’ class has an absolute position, a white background and is glued to the top left. Every slide has that and therefore, every slide is stacked on top of each other. The slide that also has the ‘activeSlide’ class rises to the top, thanks to its high z-index. To make these slides shuffle, we also need some JavaScript.

    
    <apex:includeScript value="{!$Resource.jquery}"/>
    <apex:form>
        <apex:actionFunction action="{!refreshCharts}"
            name="refreshCharts" rerender="oppStageData, casePriorityDate"/>
    </apex:form>
    <script>
    
        var moveSlide = function(){
            var next = $( ".activeSlide" ).next('.slide');
            if(next.length == 0){
                next = $( ".slide" ).first();
            }
    
            $('.activeSlide').removeClass('activeSlide');
    
            next.addClass('activeSlide');
        }
    
        window.setInterval(moveSlide, 5*1000); //5 seconds 
        window.setInterval(refreshCharts, 10*60*1000);//10 minutes
    
    </script>

First off, I am lazy at times. Seriously, no joke. That is why I included JQuery, because it makes things so darn easy. The next bit sets up a JavaScript method named ‘refreshCharts’ that calls the controller method ‘refreshCharts’ and re-renders my two charts with that data. This is done with the apex:actionFunction tag and will automatically generate the appropriate code. After that, I set up another JavaScript method that will determine the next slide, remove the ‘activeSlide’ class from the currently visible slide, and add it to the next one. To set things in motion, I call that method every 5 seconds and the ‘refreshCharts’ method every 10 minutes. Mix it all together and cook at 350 degrees and your Visualforce should look like this:

    
    <apex:page
        controller="ChartController"
        showHeader="false" sidebar="false">
    
        <head>
            <style>
                .slide{
                    position: absolute;
                    top:0px;
                    left: 0px;
                    background-color: white;
                    z-index: 1;
                }
    
                .activeSlide{
                    z-index: 999;
                }
            </style>
        </head>
    
            <div class="slide activeSlide">
                <apex:chart height="800px" width="1500px"
                    data="{!opportunityStageData}" id="oppStageData">
                    <apex:pieSeries tips="false" dataField="data"
                        labelField="name"/>
                    <apex:legend position="bottom"/>
                </apex:chart>
            </div>
            <div class="slide">
                <apex:chart height="800px" width="1500px"
                    data="{!casePriorityData}" id="casePriorityDate">
                    <apex:pieSeries tips="false" dataField="data"
                        labelField="name"/>
                    <apex:legend position="bottom"/>
                </apex:chart>
            </div>
    
        <apex:includeScript value="{!$Resource.jquery}"/>
        <apex:form>
            <apex:actionFunction action="{!refreshCharts}"
                name="refreshCharts" rerender="oppStageData, casePriorityDate"/>
        </apex:form>
        <script>
    
            var moveSlide = function(){
                var next = $( ".activeSlide" ).next('.slide');
                if(next.length == 0){
                    next = $( ".slide" ).first();
                }
    
                $('.activeSlide').removeClass('activeSlide');
    
                next.addClass('activeSlide');
            }
    
            window.setInterval(moveSlide, 5*1000); //5 seconds
    
            window.setInterval(refreshCharts, 10*60*1000);//10 minutes
    
        </script>
    </apex:page>

What does this look like in action? A chart, then another chart. This is not worth a picture because a still image won’t show it in action and an animated gif can be staged. The best way to see this is to follow along and get this code into any developer account. After you do that, just type in the URL, ‘/apex/'. Tapping F11 should remove all of the browser UI and dragging the mouse to the right side will hide it from view. There you go, a live slideshow. This is the perfect project to dedicate some old hardware to.