Was this page helpful?

MindTouch Charts Gauge Clock - Events and Dynamic Gauge Updates

    What is it?

    MindTouch Charts can listen for external events, update the chart point values, and refresh the chart on the fly. This means that the gauge or chart on the page can display the new data dynamically (and with animation) without having to reload the entire page! Not only does that make it easier to create great-looking dynamic charts (you no longer have to do ajax slight of hand), the end-user experience is greatly improved. Fluid updates and visually-seamless interactivity tremendously expand the possibilities for both developers and mildly-technical users alike. 

    While this clock is a simple example, it has significant potential. Database queries can be set to fire on a specified interval, and the results can be used to update the gauge without having to reload the page. Call volume, data traffic load, anything that changes rapidly can be monitored effectively using the MindTouch database connectors and the Chart extension.

     
    Get Adobe Flash player
     

    The Chart XML

    As always, we need to pass the XML to the Chart extension. Here, we're going to call the Chart extension, and define this chart as a gauge. For this example, I don't want a background.

    anychart('
    <anychart>
       <gauges>
           <gauge>
               <chart_settings>
                   <title>
                       <text>Stopwatch</text>
                   </title>
    			   <chart_background enabled="false"/>			   
               </chart_settings>

     

    Next, I'm going to tell MindTouch Charts that I want this gauge to be a circular type. It's important to give this particular circular gauge a name, as it's needed when dynamically updating points; Charts can support multiple charts within a single code block, you'll need to define each one (this is how Charts knows which chart to update).

    This is also where I would define some styles for the chart itself. Since this tutorial is focused more on the dynamic event updating (and the XML markup for it can be seen here) , some parts will be left out. The entire code block can be seen at the bottom of this page if you'd like to see it all.
     

    <circular name="clocks">
        <styles>
            <needle_pointer_style name="anychart_default" radius="98" base_radius="0" thickness="5" point_thickness="5" point_radius="3">
                <fill type="Solid" color="#292929"/>
                <effects enabled="true">
                    <drop_shadow enabled="true" distance="1" opacity="0.4" blur_x="2" blur_y="2"/>
                </effects>
            </needle_pointer_style>
            <!-- SNIP -->
       </styles>

    We also define the axes, which for this chart would be the hours, minutes, and seconds that the pointers will hit as they are updated. The main axis is number of hours. The <scale> node defines how the pointer will move, in this case, it will go from 0 ( which shows as the 12:00 position) to 12 (also the 12:00 position), stopping at each integer. The minor_interval attribute defines the minute/second indicator placement, located every 20% (which equates to 5 minutes or seconds) between the major intervals.

    The <extra_axes> are the minute and second hands, with their corresponding . Again, I've cut out most of the styling in the interest of space.

    <axis radius="50" start_angle="180" sweep_angle="360">
        <scale minimum="0" maximum="12" major_interval="1" minor_interval=".2" />
        <labels show_first="false">
            <font color="#0F3A55" size="13" bold="true"/>
        </labels>
        <!-- SNIP -->
    </axis>
    <extra_axes>
        <axis name="minutes" radius="50" start_angle="180" sweep_angle="360">
            <scale minimum="0" maximum="60"/>
           <major_tickmark enabled="false"/>
            <minor_tickmark enabled="false"/>
            <labels enabled="false"/>
            <scale_bar enabled="false"/>
        </axis>
        <axis name="seconds" radius="50" start_angle="180" sweep_angle="360">
            <!-- SNIP -->
        </axis>
    </extra_axes>

    Last, we're going to define the pointers. Again, it's important to note that we're giving these pointers names, because we're going to be updating them using the trigger.

    <pointers use_hand_cursor="false" allow_select="false" editable="false">
        <tooltip enabled="false"/>
        <pointer type="Needle" value="0" style="hoursNeedle" name="hours"/>
        <pointer type="Needle" value="0" style="minutesNeedle" axis="minutes" name="minutes"/>
        <pointer type="Needle" value="0" style="secondsNeedle" axis="seconds" name="seconds"/>
    </pointers>

    Lastly, we're going to close out the XML and the Charts extension parameters. The parameters are, in order, height, width, and ID. I don't want to define a size, so I'm leaving those as underscores, but the ID (in this case, "@sw") is crucial here. The Javascript Events and Messages functionality within MindTouch uses this ID to both uniquely identify and communicate with this particular Charts call.

    </circular>
           </gauge>
       </gauges>
    </anychart>', _, _, @sw);

    The buttons:

    <input type="button" value="Start" id="startbutton" />
    <input type="button" value="Stop" id="stopbutton" />
    <input type="button" value="Reset" id="resetbutton" />

    The Event Trigger

    We're first going to bind the click function of the buttons above to the various scripts to start, stop, and reset the stopwatch, and then set up a simple timer to keep track of the seconds, minutes, and hours. To make sure the chart's been initialized before we bind events to it, we're going to listen to the @sw channel (again, the same as the ID used above) to listen for the event with the type of "create". Otherwise the Javascript will fail to fire when the buttons are clicked on. We're also going to simplify interaction with the chart by assigning the target to a variable (sw).

    <script type="text/jem">"
    when(@sw['type'] == 'create') {
        var sw = @sw.target;
        $('#startbutton').bind('click', function() {
            startSW()
        });
        $('#stopbutton').bind('click', function() {
            stopSW()
        });
        $('#resetbutton').bind('click', function() {
            resetSW()
        });

    Then we build a fairly generic Javascript timekeeping function. The magic happens with the updatePointData() method inside the tick() and resetSW() functions. We're incrementing the respective values with Javascript inside tick(), and then updating the data points ("seconds", "minutes", "hours") inside the chart ("clocks") to match. The resetSW() function simply sets all those values back to zero, and updates the chart in the same way. The updatePointData usage is:

    CHART_ID.updatePointData("SPECIFIC_CHART_NAME", "POINTER_NAME", {value: "NEW_VALUE"})

    It should be noted that this is only for gauges; other chart types require different methods to be covered in another tutorial.

    var h = 0, m = 0, s = 0;
        var stopwatch;
        function startSW() {
            stopwatch = setInterval(tick, 1000);
        }
    
        function stopSW() {
            clearInterval(stopwatch);
        }
    
        function tick() {
            s++;
            if (s == '60') {
                s = 0;
                m++;
                if (m == '60') {
                    m = 0;
                    h++;
                    if (h == '11') {
                        h = 0;
                    }
                }
            }
            sw.updatePointData('clocks', 'seconds', {value:s});
            sw.updatePointData('clocks', 'minutes', {value:m});
            sw.updatePointData('clocks', 'hours', {value:h});
        };
    
        function resetSW() {
            h = 0;
            m = 0;
            s = 0;
            sw.updatePointData('clocks', 'seconds', {value:s});
            sw.updatePointData('clocks', 'minutes', {value:m});
            sw.updatePointData('clocks', 'hours', {value:h});
        };
    };     
    "</script>

    The Whole Enchilada

    Here's the whole code block, start to finish:

    anychart('
    <anychart>
        <gauges>
            <gauge>
                <chart_settings>
                    <title>
                        <text>Stopwatch</text>
                    </title>
                    <chart_background enabled="false"/>
                </chart_settings>
                <circular name="clocks">
                    <styles>
                        <needle_pointer_style name="anychart_default" radius="98" base_radius="0" thickness="5" point_thickness="5" point_radius="3">
                            <fill type="Solid" color="#292929"/>
                            <effects enabled="true">
                                <drop_shadow enabled="true" distance="1" opacity="0.4" blur_x="2" blur_y="2"/>
                            </effects>
                        </needle_pointer_style>
                        <needle_pointer_style name="secondsNeedle" thickness="2" point_thickness="2" base_radius="0" radius="100">
                            <fill type="Solid" color="Rgb(220,0,0)"/>
                            <cap enabled="true" radius="10">
                                <background enabled="true">
                                    <fill enabled="true" color="Rgb(170,170,170)"/>
                                </background>
                                <effects enabled="true">
                                    <bevel enabled="true" distance="2"/>
                                </effects>
                            </cap>
                        </needle_pointer_style>
                        <needle_pointer_style name="hoursNeedle" base_radius="0" radius="60">
                        </needle_pointer_style>
                        <needle_pointer_style name="minutesNeedle" base_radius="0" radius="85">
                        </needle_pointer_style>
                    </styles>
                    <axis radius="50" start_angle="180" sweep_angle="360">
                        <scale minimum="0" maximum="12" major_interval="1" minor_interval="0.2"/>
                        <labels show_first="false">
                            <font color="#0F3A55" size="13" bold="true"/>
                        </labels>
                        <scale_bar enabled="false"/>
                        <major_tickmark enabled="true" shape="Circle" width="5" length="5">
                            <fill color="White"/>
                            <effects enabled="true">
                                <inner_shadow enabled="true" distance="1" blur_x="2" blur_y="2" opacity="0.7"/>
                            </effects>
                        </major_tickmark>
                        <minor_tickmark enabled="true" shape="Circle" width="3" length="3">
                            <fill color="White"/>
                            <effects enabled="true">
                                <inner_shadow enabled="true" distance="1" blur_x="2" blur_y="2" opacity="0.7"/>
                            </effects>
                        </minor_tickmark>
                    </axis>
                    <extra_axes>
                        <axis name="minutes" radius="50" start_angle="180" sweep_angle="360">
                            <scale minimum="0" maximum="60"/>
                            <major_tickmark enabled="false"/>
                            <minor_tickmark enabled="false"/>
                            <labels enabled="false"/>
                            <scale_bar enabled="false"/>
                        </axis>
                        <axis name="seconds" radius="50" start_angle="180" sweep_angle="360">
                            <scale minimum="0" maximum="60"/>
                            <major_tickmark enabled="false"/>
                            <minor_tickmark enabled="false"/>
                            <labels enabled="false"/>
                            <scale_bar enabled="false"/>
                        </axis>
                        <axis name="milliseconds" radius="50" start_angle="180" sweep_angle="360">
                            <scale minimum="0" maximum="100"/>
                            <major_tickmark enabled="false"/>
                            <minor_tickmark enabled="false"/>
                            <labels enabled="false"/>
                            <scale_bar enabled="false"/>
                        </axis>
    
                    </extra_axes>
                    <frame>
                        <outer_stroke enabled="false"/>
                        <inner_stroke enabled="true" thickness="10">
                            <border enabled="false"/>
                            <fill enabled="true" type="Gradient">
                                <gradient type="Radial">
                                    <key color="#1B1B1B" position="0.9"/>
                                    <key color="#6F6F6F" position="0.94"/>
                                    <key color="#000000" position="1"/>
                                </gradient>
                            </fill>
                        </inner_stroke>
                        <effects>
                            <drop_shadow enabled="true" distance="2" opacity="0.3"/>
                        </effects>
                    </frame>
                    <pointers use_hand_cursor="false" allow_select="false" editable="false">
                        <tooltip enabled="false"/>
                        <pointer type="Needle" value="0" style="hoursNeedle" name="hours"/>
                        <pointer type="Needle" value="0" style="minutesNeedle" axis="minutes" name="minutes"/>
                        <pointer type="Needle" value="0" style="secondsNeedle" axis="seconds" name="seconds"/>
                    </pointers>
                </circular>
            </gauge>
        </gauges>
    </anychart>', _, _, @sw);
    
    <input type="button" value="Start" id="startbutton" />
    <input type="button" value="Stop" id="stopbutton" />
    <input type="button" value="Reset" id="resetbutton" />
    
    <script type="text/jem">"
    when(@sw['type']== 'create') {
        var sw = @sw.target;
        $('#startbutton').bind('click', function() {
            startSW()
        });
        $('#stopbutton').bind('click', function() {
            stopSW()
        });
        $('#resetbutton').bind('click', function() {
            resetSW()
        });
    
        var h = 0, m = 0, s = 0;
        var stopwatch;
        function startSW() {
            stopwatch = setInterval(tick, 1000);
        }
    
        function stopSW() {
            clearInterval(stopwatch);
        }
    
        function tick() {
            s++;
            if (s == '60') {
                s = 0;
                m++;
                if (m == '60') {
                    m = 0;
                    h++;
                    if (h == '11') {
                        h = 0;
                    }
                }
            }
            sw.updatePointData('clocks', 'seconds', {value:s});
            sw.updatePointData('clocks', 'minutes', {value:m});
            sw.updatePointData('clocks', 'hours', {value:h});
        };
    
        function resetSW() {
            var z = 0;
            h = 0;
            m = 0;
            s = 0;
            sw.updatePointData('clocks', 'seconds', {value:z});
            sw.updatePointData('clocks', 'minutes', {value:z});
            sw.updatePointData('clocks', 'hours', {value:z});
        };
    };     
    "</script>
    Was this page helpful?
    Tag page
    Viewing 2 of 2 comments: view all
    Too bad it doesn't seem to work. Tried both IE7 and Firefox4.0 and both are a no=go.
    Posted 07:24, 29 Mar 2011
    @mcraven the page was saved by someone without UNSAFECONTENT permission. it should work now
    Posted 11:09, 29 Mar 2011
    Viewing 2 of 2 comments: view all
    You must login to post a comment.

    Copyright © 2011 MindTouch, Inc. Powered by