d3 charts

d3 charts

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <title>d3.js from Excel - ramblings.mcpher.com
    </title>
    <!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame
Remove this if you use the .htaccess -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <script type="text/javascript" src="http://d3js.org/d3.v3.min.js">
    </script>
    <script type="text/javascript" src="https://www.google.com/jsapi">
    </script>
    <script type="text/javascript">
        google.load("jquery", "1");
        google.setOnLoadCallback(function() {
            initialize().then(
                function(control) {
                    doTheTreeViz(control);
                }
            );
        });
    </script>
    <style>
        body {
            position: relative;
            font-family: "Helvetica Neue", Helvetica, sans-serif;
            margin: 1em auto 4em auto;
            width: 960px;
        }
        
        h1 {
            font-size: 64px;
            font-weight: 300;
            letter-spacing: -2px;
            margin: .3em 0 .1em 0;
        }
        
        h2 {
            margin-top: 2em;
        }
        
        h1,
        h2 {
            text-rendering: optimizeLegibility;
        }
        
        h2 a {
            color: #ccc;
            left: -20px;
            position: absolute;
            width: 740px;
        }
        
        footer {
            font-size: small;
            margin-top: 8em;
        }
        
        header aside {
            margin-top: 20px;
        }
        
        header aside,
        footer aside {
            color: #636363;
            text-align: right;
        }
        
        aside {
            float: right;
            display: inline;
            font-size: small;
        }
        
        .attribution {
            font-size: small;
            margin-bottom: 2em;
        }
        
        body>p,
        li>p {
            line-height: 1.5em;
        }
        
        body>p {
            width: 720px;
        }
        
        body>blockquote {
            width: 640px;
        }
        
        li {
            width: 680px;
        }
        
        pre,
        code,
        textarea {
            font-family: "Menlo", monospace;
        }
        
        code {
            line-height: 1em;
        }
        
        textarea {
            font-size: 100%;
        }
        
        body>pre {
            border-left: solid 2px #ccc;
            padding-left: 18px;
            margin: 2em 0 2em -20px;
        }
        
        .html .value,
        .javascript .string,
        .javascript .regexp {
            color: #756bb1;
        }
        
        .html .tag,
        .css .tag,
        .javascript .keyword {
            color: #3182bd;
        }
        
        .comment {
            color: #636363;
        }
        
        .html .doctype,
        .javascript .number {
            color: #31a354;
        }
        
        .html .attribute,
        .css .attribute,
        .javascript .class,
        .javascript .special {
            color: #e6550d;
        }
        
        svg {
            font: 10px sans-serif;
        }
        
        .axis path,
        .axis line {
            fill: none;
            stroke: #000;
            shape-rendering: crispEdges;
        }
        
        sup,
        sub {
            line-height: 0;
        }
        
        q:before,
        blockquote:before {
            content: "?";
        }
        
        q:after,
        blockquote:after {
            content: "?";
        }
        
        blockquote:before {
            position: absolute;
            left: 2em;
        }
        
        blockquote:after {
            position: absolute;
        }
    </style>
    <style>
        #chart {
            height: 600px;
        }
        
        .node rect {
            cursor: move;
            fill-opacity: .9;
            shape-rendering: crispEdges;
        }
        
        .node text {
            pointer-events: none;
            text-shadow: 0 1px 0 #fff;
        }
        
        .link {
            fill: none;
            stroke: #000;
            stroke-opacity: .2;
        }
        
        .link:hover {
            stroke-opacity: .5;
        }
        
        circle.node-dot {
            fill: DarkSlateGray;
            stroke: SlateGray;
            stroke-width: 1px;
        }
        
        line.link {
            fill: none;
            stroke: SlateGray;
            stroke-width: 1.5px;
        }
        
        marker#defaultMarker {
            fill: SlateGray;
        }
        
        line.link.defaultMarker {
            stroke: SlateGray;
        }
        
        circle {
            fill: #ccc;
            stroke: #333;
            stroke-width: 1.5px;
        }
        
        text {
            pointer-events: none;
        }
        
        text.shadow {
            stroke: #fff;
            stroke-width: 3px;
            stroke-opacity: .8;
        }
    </style>
    <script>
        function doTheTreeViz(control) {
            var svg = control.svg;
            var force = control.force;
            force.nodes(control.nodes)
                .links(control.links)
                .start();
            // Update the links
            var link = svg.selectAll("line.link")
                .data(control.links, function(d) {
                    return d.unique;
                });
            // Enter any new links
            link.enter().insert("svg:line", ".node")
                .attr("class", "link")
                .attr("x1", function(d) {
                    return d.source.x;
                })
                .attr("y1", function(d) {
                    return d.source.y;
                })
                .attr("x2", function(d) {
                    return d.target.x;
                })
                .attr("y2", function(d) {
                    return d.target.y;
                })
                .append("svg:title")
                .text(function(d) {
                    return d.source[control.options.nodeLabel] + ":" + d.target[control.options.nodeLabel];
                });
            // Exit any old links.
            link.exit().remove();
            // Update the nodes
            var node = svg.selectAll("g.node")
                .data(control.nodes, function(d) {
                    return d.unique;
                });
            node.select("circle")
                .style("fill", function(d) {
                    return getColor(d);
                })
                .attr("r", function(d) {
                    return getRadius(d);
                })
            // Enter any new nodes.
            var nodeEnter = node.enter()
                .append("svg:g")
                .attr("class", "node")
                .attr("transform", function(d) {
                    return "translate(" + d.x + "," + d.y + ")";
                })
                .on("dblclick", function(d) {
                    control.nodeClickInProgress = false;
                    if (d.url) window.open(d.url);
                })
                .on("click", function(d) {
                    // this is a hack so that click doesnt fire on the1st click of a dblclick
                    if (!control.nodeClickInProgress) {
                        control.nodeClickInProgress = true;
                        setTimeout(function() {
                            if (control.nodeClickInProgress) {
                                control.nodeClickInProgress = false;
                                if (control.options.nodeFocus) {
                                    d.isCurrentlyFocused = !d.isCurrentlyFocused;
                                    doTheTreeViz(makeFilteredData(control));
                                }
                            }
                        }, control.clickHack);
                    }
                })
                .call(force.drag);
            nodeEnter
                .append("svg:circle")
                .attr("r", function(d) {
                    return getRadius(d);
                })
                .style("fill", function(d) {
                    return getColor(d);
                })
                .append("svg:title")
                .text(function(d) {
                    return d[control.options.nodeLabel];
                });
            if (control.options.nodeLabel) {
                // text is done once for shadow as well as for text
                nodeEnter.append("svg:text")
                    .attr("x", control.options.labelOffset)
                    .attr("dy", ".31em")
                    .attr("class", "shadow")
                    .style("font-size", control.options.labelFontSize + "px")
                    .text(function(d) {
                        return d.shortName ? d.shortName : d.name;
                    });
                nodeEnter.append("svg:text")
                    .attr("x", control.options.labelOffset)
                    .attr("dy", ".35em")
                    .attr("class", "text")
                    .style("font-size", control.options.labelFontSize + "px")
                    .text(function(d) {
                        return d.shortName ? d.shortName : d.name;
                    });
            }
            // Exit any old nodes.
            node.exit().remove();
            control.link = svg.selectAll("line.link");
            control.node = svg.selectAll("g.node");
            force.on("tick", tick);
            if (control.options.linkName) {
                link.append("title")
                    .text(function(d) {
                        return d[control.options.linkName];
                    });
            }

            function tick() {
                link.attr("x1", function(d) {
                        return d.source.x;
                    })
                    .attr("y1", function(d) {
                        return d.source.y;
                    })
                    .attr("x2", function(d) {
                        return d.target.x;
                    })
                    .attr("y2", function(d) {
                        return d.target.y;
                    });
                node.attr("transform", function(d) {
                    return "translate(" + d.x + "," + d.y + ")";
                });
            }

            function getRadius(d) {
                var r = control.options.radius * (control.options.nodeResize ? Math.sqrt(d[control.options.nodeResize]) / Math.PI : 1);
                return control.options.nodeFocus && d.isCurrentlyFocused ? control.options.nodeFocusRadius : r;
            }

            function getColor(d) {
                return control.options.nodeFocus && d.isCurrentlyFocused ? control.options.nodeFocusColor : control.color(d.group);
            }
        }

        function makeFilteredData(control, selectedNode) {
            // we'll keep only the data where filterned nodes are the source or target
            var newNodes = [];
            var newLinks = [];
            for (var i = 0; i < control.data.links.length; i++) {
                var link = control.data.links[i];
                if (link.target.isCurrentlyFocused || link.source.isCurrentlyFocused) {
                    newLinks.push(link);
                    addNodeIfNotThere(link.source, newNodes);
                    addNodeIfNotThere(link.target, newNodes);
                }
            }
            // if none are selected reinstate the whole dataset
            if (newNodes.length > 0) {
                control.links = newLinks;
                control.nodes = newNodes;
            } else {
                control.nodes = control.data.nodes;
                control.links = control.data.links;
            }
            return control;

            function addNodeIfNotThere(node, nodes) {
                for (var i = 0; i < nodes.length; i++) {
                    if (nodes[i].unique == node.unique) return i;
                }
                return nodes.push(node) - 1;
            }
        }

        function organizeData(control) {
            for (var i = 0; i < control.nodes.length; i++) {
                var node = control.nodes[i];
                node.unique = i;
                node.isCurrentlyFocused = false;
            }
            for (var i = 0; i < control.links.length; i++) {
                var link = control.links[i];
                link.unique = i;
                link.source = control.nodes[link.source];
                link.target = control.nodes[link.target];
            }
            return control;
        }

        function initialize() {
            var initPromise = $.Deferred();
            getTheData().then(function(data) {
                var control = {};
                control.data = data;
                control.divName = "#chart";
                control.options = $.extend({
                    stackHeight: 12,
                    radius: 5,
                    fontSize: 14,
                    labelFontSize: 8,
                    nodeLabel: null,
                    markerWidth: 0,
                    markerHeight: 0,
                    width: $(control.divName).outerWidth(),
                    gap: 1.5,
                    nodeResize: "",
                    linkDistance: 80,
                    charge: -120,
                    styleColumn: null,
                    styles: null,
                    linkName: null,
                    nodeFocus: true,
                    nodeFocusRadius: 25,
                    nodeFocusColor: "black",
                    labelOffset: "5",
                    gravity: .05,
                    height: $(control.divName).outerHeight()
                }, control.data.d3.options);
                var options = control.options;
                options.gap = options.gap * options.radius;
                control.width = options.width;
                control.height = options.height;
                control.data = control.data.d3.data;
                control.nodes = control.data.nodes;
                control.links = control.data.links;
                control.color = d3.scale.category20();
                control.clickHack = 200;
                organizeData(control);
                control.svg = d3.select(control.divName)
                    .append("svg:svg")
                    .attr("width", control.width)
                    .attr("height", control.height);
                // get list of unique values in stylecolumn
                control.linkStyles = [];
                if (control.options.styleColumn) {
                    var x;
                    for (var i = 0; i < control.links.length; i++) {
                        if (control.linkStyles.indexOf(x = control.links[i][control.options.styleColumn].toLowerCase()) == -1)
                            control.linkStyles.push(x);
                    }
                } else
                    control.linkStyles[0] = "defaultMarker";
                control.force = d3.layout.force().
                size([control.width, control.height])
                    .linkDistance(control.options.linkDistance)
                    .charge(control.options.charge)
                    .gravity(control.options.gravity);
                initPromise.resolve(control);
            });
            return initPromise.promise();
        }

        function getTheData() {
            var dataPromise = $.Deferred();
            // return a promise if data is being received asynch and resolve it when done.
            dataPromise.resolve(mcpherTreeData);
            return dataPromise.promise();
        }
    </script>
    <script>
        window['mcpherTreeData'] = {
            "d3": {
                "options": {
                    "radius": 2.5,
                    "fontSize": 9,
                    "labelFontSize": 9,
                    "gravity": 0.1,
                    "height": 800,
                    "nodeFocusColor": "black",
                    "nodeFocusRadius": 25,
                    "nodeFocus": true,
                    "linkDistance": 150,
                    "charge": -220,
                    "nodeResize": "count",
                    "nodeLabel": "label",
                    "linkName": "tag"
                },
                "data": {
                    "nodes": [{
                            "name": "courses",
                            "count": 1000,
                            "group": "courses",
                            "linkCount": 164,
                            "label": "courses registered with APSSDC",
                            "userCount": true,
                            "url": "https://sites.google.com/a/mcpher.com/share/Home/excelquirks/jsondynamic",
                            "shortName": "courses"
                        },
                        {
                            "name": "vbaExcel",
                            "count": 100,
                            "group": "vbaExcel",
                            "linkCount": 235,
                            "label": "Services",
                            "userCount": true,
                            "url": "https://sites.google.com/a/mcpher.com/share/Home",
                            "shortName": "vbaExcel"
                        },
                        {
                            "name": "vbaExcel",
                            "count": 100,
                            "group": "vbaExcel",
                            "linkCount": 235,
                            "label": "Services",
                            "userCount": true,
                            "url": "https://sites.google.com/a/mcpher.com/share/Home",
                            "shortName": "vbaExcel"
                        },
                        {
                            "name": "vbaExcel",
                            "count": 100,
                            "group": "vbaExcel",
                            "linkCount": 235,
                            "label": "Services",
                            "userCount": true,
                            "url": "https://sites.google.com/a/mcpher.com/share/Home",
                            "shortName": "vbaExcel"
                        },

                    ],

                    "links": [{
                            "source": 0,
                            "target": 1,
                            "depth": 0,
                            "count": 0,
                            "linkName": "http://www.some.com"
                        },
                        {
                            "source": 0,
                            "target": 2,
                            "depth": 0,
                            "count": 0,
                            "linkName": "http://www.some.com"
                        },
                        {
                            "source": 0,
                            "target": 3,
                            "depth": 0,
                            "count": 0,
                            "linkName": "http://www.some.com"
                        }


                    ]
                }
            }
        };
    </script>
</head>

<body>
    <div id="chart">
    </div>
</body>

</html>