OUTCASTGEEK

tips, tricks, tuts, and more

Progress Meter with d3js Reactjs and Angularjs


Here is an example on how to integrate d3js Reactjs and Angularjs to create a progress meter:

Demo

Progress
Default Content

The use of a directive as shown below lets us configure various aspects of the progress meter widget.

Progress Meter Directive

<div class="row" ng-app='d3ReactAngular' ng-controller='ProgressCtrl'>
    <div>
        <span>Progress</span>
        <input type="number" name="percentage" min="0" max="100" ng-model="progress">
    </div>
    <div>
        <span
          width='400'
          height='400'
          inner_radius='100'
          outer_radius='200'
          progress-meter>
          Default Content
        </span>
    </div>
</div>

Here is the supporting code for the progress meter widget:

d3_react_angular.js

/**
 * Created by outcastgeek on 6/29/14.
 */

'use strict';

angular
    .module('d3ReactAngular', [])
    .factory('progressMeterFactory', function () {
        return function (options) {
            var ProgressMeter = React.createClass({
                displayName: 'ProgressBarSvg',
                render: function () {
                    var percentage = this.props.percentage / 100,
                        width = options.width,
                        height = options.height,
                        twoPi = 2 * Math.PI,
                        progress = 0,
                        i = d3.interpolate(progress, percentage),
                        progress = i(1),
                        formatPercent = d3.format(".0%"),
                        arc = d3.svg.arc()
                            .startAngle(0)
                            .innerRadius(options.innerRadius)
                            .outerRadius(options.outerRadius),
                        style = {
                            fill: '#428bca'
                        };

                    return React.DOM.svg({
                            width: width,
                            height: height,
                            style: style
                        },
                        React.DOM.g({
                                transform: "translate(" + width / 2 + "," + height / 2 + ")"
                            },
                            React.DOM.g({
                                    className: options.style
                                },
                                React.DOM.path({
                                    d: arc.endAngle(twoPi * progress)()
                                }),
                                React.DOM.text({
                                    textAnchor: 'middle'
                                }, formatPercent(progress))
                            ))
                    );
                }
            });
            return ProgressMeter;
        };
    })
    .controller('ProgressCtrl', function ($scope) {
        $scope.progress = 40;
    })
    .directive('progressMeter', ['progressMeterFactory', function (progressMeterFactory) {
        return {
            link: function (scope, element, attrs) {
                var ProgressMeter = progressMeterFactory(attrs),
                    ProgressWidget = React.createClass({
                        displayName: 'ProgressWidget',
                        render: function () {
                            var percentage = this.props.percentage;
                            return React.DOM.div({},
                                ProgressMeter({
                                    percentage: percentage
                                }));
                        }
                    });
                scope.$watch('progress', function (newVal, oldVal) {
                    React.renderComponent(ProgressWidget({
                        percentage: scope.progress
                    }), element[0]);
                });
            }
        }
    }]);

Any questions, feedback, or comments?


❯❯ Back to Blog ❮❮ ❮ Previous: gradle behind proxy Next: bean traversal afternoon hack ❯
blog comments powered by Disqus