Customized Sunburst

Welcome to Toppersarena.com Forums Programming Blogs Customized Sunburst

This topic contains 0 replies, has 0 voices, and was last updated by Admin admin 1 year, 1 month ago.

Viewing 1 post (of 1 total)
  • Author
    Posts
  • #3023
    Admin
    admin
    Keymaster

    /**
    *@author: dhruv.sood
    */

    Box.Application.addModule(‘module-viewTCOSunburst’, function(context) {

    ‘use strict’;

    // private methods here
    var $, d3, commonUtils, jsonService,colors;

    var spinner = null;

    //Method to handle Spinner image loading
    function showLoading(show){
    var spinService = context.getService(‘service-spinner’);
    var $moduleDiv = $(context.getElement());
    //Calling the service
    spinner = spinService.getSpinner($moduleDiv,show,spinner);
    }

    //Method to get the TCO Sunburst Wrapper and Show the chart after generation
    function getSunburstWrapper(){
    var wrapperUrl = commonUtils.getAppBaseURL(“tco/reports/TCOSunburstWrapper”);
    var dataObj={};
    dataObj.ChartOfAccountID = $(‘#sunburst’).data(“coaid”);
    var deffMassage = $.Deferred();
    var dataPromise = jsonService.getJsonResponse(wrapperUrl,dataObj);
    dataPromise.done ( function (data) {
    showLoading(false);
    // need to massage it and then sending the data to the map
    deffMassage.resolve (generateChart(data));
    })

    .fail (function (error) {
    deffMassage.reject(error);
    });

    }

    //Converting incomming data to Sunburst format
    function convertJsonFormat(jsonData){
    jsonData = JSON.parse(JSON.stringify(jsonData).split(‘”costStructureName”:’).join(‘”name”:’));
    jsonData = JSON.parse(JSON.stringify(jsonData).split(‘”subCostStructureList”:’).join(‘”children”:’));
    jsonData = JSON.parse(JSON.stringify(jsonData).split(‘”cost”:’).join(‘”size”:’));

    return jsonData;
    }

    //Method to generate Sunburst Chart
    function generateChart(data){

    //First, Convert the incomming data into Sunburst format
    var root = convertJsonFormat(data);

    var b = { w: 75, h: 30, s: 3, t: 10 };

    var margin = {top: 245, right: 375, bottom: 245, left: 375},
    radius = Math.min(margin.top, margin.right, margin.bottom, margin.left) – 10;

    function filter_min_arc_size_text(d, i) {return (d.dx*d.depth*radius/3)>14};

    var colorBrewrer = colors.Set1[8];
    var hue = d3.scale.ordinal().range(colorBrewrer);

    var luminance = d3.scale.sqrt()
    .domain([0, 1e6])
    .range([90, 20]);

    var svg = d3.select(“#sunburst”).append(“svg”)
    .attr(“width”, margin.left + margin.right)
    .attr(“height”, margin.top + margin.bottom)
    .append(“g”)
    .attr(“transform”, “translate(” + margin.left + “,” + margin.top + “)”);

    var partition = d3.layout.partition()
    .sort(function(a, b) { return d3.ascending(a.name, b.name); })
    .size([2 * Math.PI, radius]);

    var arc = d3.svg.arc()
    .startAngle(function(d) { return d.x; })
    .endAngle(function(d) { return d.x + d.dx – .01 / (d.depth + .5); })
    .innerRadius(function(d) { return radius / 3 * d.depth; })
    .outerRadius(function(d) { return radius / 3 * (d.depth + 1) – 1; });

    // Basic setup of page breadcrumbs
    initializeBreadcrumbTrail();

    //Tooltip description
    var tooltip = d3.select(“#breadcumb”)
    .append(“div”)
    .attr(“id”, “tooltip”)
    .style(“position”, “fixed !important”)
    .style(“z-index”, “10”)
    .style(“background-color”, “white”)
    .style(“padding”, “3px 5px”)
    .style(“text-align”, “left”)
    .style(“opacity”, 0);

    function format_number(x) {
    return “$”+x.toString().replace(/B(?=(d{3})+(?!d))/g, “,”);
    }

    function format_description(d) {
    return ‘

    Cost Structure :  ‘ + d.name + ‘
    Total Cost :  ‘ + format_number(d.value) + ‘

    ‘;
    }

    function computeTextRotation(d) {
    var angle=(d.x +d.dx/2)*180/Math.PI – 90

    return angle;
    }

    // Generate a string that describes the points of a breadcrumb polygon.
    function breadcrumbPoints(d, i) {
    var points = [];
    points.push(“0,0”);
    points.push(b.w + “,0”);
    points.push(b.w + b.t + “,” + (b.h / 2));
    points.push(b.w + “,” + b.h);
    points.push(“0,” + b.h);
    if (i > 0) { // Leftmost breadcrumb; don’t include 6th vertex.
    points.push(b.t + “,” + (b.h / 2));
    }
    return points.join(” “);
    }

    //Creating the breadcumb box and labels
    function initializeBreadcrumbTrail() {
    // Add the svg area.
    var trail = d3.select(“#breadcumb”).append(“svg:svg”)
    .attr(“width”, 750)
    .attr(“height”, 50)
    .attr(“id”, “trail”);
    // Add the label at the end, for the percentage.
    trail.append(“svg:text”)
    .attr(“id”, “endlabel”)
    .style(“fill”, “#000”);
    }
    // Update the breadcrumb trail to show the current sequence and percentage.
    function updateBreadcrumbs(nodeArray, percentageString) {

    // Data join; key function combines name and depth (= position in sequence).
    var g = d3.select(“#trail”)
    .selectAll(“g”)
    .data(nodeArray, function(d) { return d.name + d.depth; });

    // Add breadcrumb and label for entering nodes.
    var entering = g.enter().append(“svg:g”);

    entering.append(“svg:polygon”)
    .attr(“points”, breadcrumbPoints)
    .style(“fill”, function(d) { return d.fill; });

    entering.append(“svg:text”)
    .attr(“x”, (b.w + b.t) / 2)
    .attr(“y”, b.h / 2)
    .attr(“dy”, “0.35em”)
    .attr(“text-anchor”, “middle”)
    .text(function(d) { return truncateName(d.name); })
    .style(“fill”, “#fff”);

    // Set position for entering and updating nodes.
    g.attr(“transform”, function(d, i) {
    return “translate(” + i * (b.w + b.s) + “, 0)”;
    });

    // Remove exiting nodes.
    g.exit().remove();

    // Now move and update the percentage at the end and setting its ‘x’ and ‘y’ coordinates
    d3.select(“#trail”).select(“#endlabel”)
    .attr(“x”, (nodeArray.length + 0.6) * (b.w + b.s))
    .attr(“y”, b.h / 2)
    .attr(“dy”, “0.35em”)
    .attr(“text-anchor”, “middle”)
    .text(percentageString);

    // Make the breadcrumb trail visible, if it’s hidden.
    d3.select(“#trail”)
    .style(“visibility”, “”);

    }

    // Show it in the breadcrumb trail.
    function mouseover(d) {
    var percentageString = format_number(d.value);

    var sequenceArray = getAncestors(d);
    updateBreadcrumbs(sequenceArray, percentageString);

    }

    function mouseOverArc(d) {
    d3.select(this).attr(“stroke”,”black”).attr(“stroke-width”,”4″)
    mouseover(d);

    tooltip.html(format_description(d));
    return tooltip.style(“opacity”, 0.9);
    }

    function mouseOutArc(){
    d3.select(this).attr(“stroke”,””)
    // Hide the breadcrumb trail
    d3.select(“#trail”).style(“visibility”, “hidden”);
    return tooltip.style(“opacity”, 0);
    }

    function mouseMoveArc (d) {
    return tooltip.style(“top”, (d3.event.pageY-10)+”px”).style(“left”, (d3.event.pageX+10)+”px”);
    }

    // Compute the initial layout on the entire tree to sum sizes.
    // Also compute the full name and fill color for each node,
    // and stash the children so they can be restored as we descend.

    partition
    .value(function(d) { return d.size; })
    .nodes(root)
    .forEach(function(d) {
    d._children = d.children;
    d.sum = d.value;
    d.key = key(d);
    d.fill = fill(d);
    });

    // Now redefine the value function to use the previously-computed sum.
    partition
    .children(function(d, depth) { return depth < 2 ? d._children : null; })
    .value(function(d) { return d.sum; });

    var center = svg.append(“circle”)
    .attr(“r”, radius / 3)
    .style(“fill”,”none”)
    .style(“pointer-events”,”all”)
    .on(“click”, zoomOut);

    center.append(“title”).text(“Zoom Out”);

    var partitioned_data=partition.nodes(root).slice(1)

    var path = svg.selectAll(“path”)
    .data(partitioned_data)
    .enter().append(“path”)
    .attr(“d”, arc)
    .style(“fill”, function(d) { return d.fill; })
    .each(function(d) { this._current = updateArc(d); })
    .on(“click”, zoomIn)
    .on(“mouseover”, mouseOverArc)
    .on(“mousemove”, mouseMoveArc)
    .on(“mouseout”, mouseOutArc);

    var totalSize = path.node().__data__.value;

    var texts = svg.selectAll(“text”)
    .data(partitioned_data)
    .enter().append(“text”)
    .filter(filter_min_arc_size_text)
    .attr(“transform”, function(d) { return “rotate(” + computeTextRotation(d) + “)”; })
    .attr(“x”, function(d) { return radius / 3 * d.depth; })
    .attr(“dx”, “6”) // margin
    .attr(“dy”, “.35em”) // vertical-align
    .text(function(d,i) {return truncateName(d.name);})
    .style(“fill”, “#fff”);

    function zoomIn(p) {
    if (p.depth > 1) p = p.parent;
    if (!p.children) return;
    zoom(p, p);
    }

    function zoomOut(p) {
    if (!p.parent) return;
    zoom(p.parent, p);
    }

    // Zoom to the specified new root.
    function zoom(root, p) {
    if (document.documentElement.__transition__) return;

    // Rescale outside angles to match the new layout.
    var enterArc,
    exitArc,
    outsideAngle = d3.scale.linear().domain([0, 2 * Math.PI]);

    function insideArc(d) {
    return p.key > d.key
    ? {depth: d.depth – 1, x: 0, dx: 0} : p.key < d.key
    ? {depth: d.depth – 1, x: 2 * Math.PI, dx: 0}
    : {depth: 0, x: 0, dx: 2 * Math.PI};
    }

    function outsideArc(d) {
    return {depth: d.depth + 1, x: outsideAngle(d.x), dx: outsideAngle(d.x + d.dx) – outsideAngle(d.x)};
    }

    center.datum(root);

    // When zooming in, arcs enter from the outside and exit to the inside.
    // Entering outside arcs start from the old layout.
    if (root === p) enterArc = outsideArc, exitArc = insideArc, outsideAngle.range([p.x, p.x + p.dx]);

    var new_data=partition.nodes(root).slice(1)

    path = path.data(new_data, function(d) { return d.key; });

    // When zooming out, arcs enter from the inside and exit to the outside.
    // Exiting outside arcs transition to the new layout.
    if (root !== p) enterArc = insideArc, exitArc = outsideArc, outsideAngle.range([p.x, p.x + p.dx]);

    d3.transition().duration(d3.event.altKey ? 7500 : 750).each(function() {
    path.exit().transition()
    .style(“fill-opacity”, function(d) { return d.depth === 1 + (root === p) ? 1 : 0; })
    .attrTween(“d”, function(d) { return arcTween.call(this, exitArc(d)); })
    .remove();

    path.enter().append(“path”)
    .style(“fill-opacity”, function(d) { return d.depth === 2 – (root === p) ? 1 : 0; })
    .style(“fill”, function(d) { return d.fill; })
    .on(“click”, zoomIn)
    .on(“mouseover”, mouseOverArc)
    .on(“mousemove”, mouseMoveArc)
    .on(“mouseout”, mouseOutArc)
    .each(function(d) { this._current = enterArc(d); });

    path.transition()
    .style(“fill-opacity”, 1)
    .attrTween(“d”, function(d) { return arcTween.call(this, updateArc(d)); });

    });

    texts = texts.data(new_data, function(d) { return d.key; })

    texts.exit()
    .remove()
    texts.enter()
    .append(“text”)

    texts.style(“opacity”, 0)
    .attr(“transform”, function(d) { return “rotate(” + computeTextRotation(d) + “)”; })
    .attr(“x”, function(d) { return radius / 3 * d.depth; })
    .attr(“dx”, “6”) // margin
    .attr(“dy”, “.35em”) // vertical-align
    .filter(filter_min_arc_size_text)
    .text(function(d,i) {return truncateName(d.name);})
    .style(“fill”, “#fff”)
    .transition().delay(750).style(“opacity”, 1)

    }

    function truncateName(name){
    return name.substring(0,8);
    }

    // Given a node in a partition layout, return an array of all of its ancestor
    // nodes, highest first, but excluding the root.
    function getAncestors(node) {
    var path = [];
    var current = node;
    while (current.parent) {
    path.unshift(current);
    current = current.parent;
    }
    return path;
    }

    function key(d) {
    var k = [], p = d;
    while (p.depth) k.push(p.name), p = p.parent;
    return k.reverse().join(“.”);
    }

    function fill(d) {
    var p = d;
    while (p.depth > 1) p = p.parent;
    var c = d3.lab(hue(p.name));
    c.a = luminance(d.sum);
    return c;
    }

    function arcTween(b) {
    var i = d3.interpolate(this._current, b);
    this._current = i(0);
    return function(t) {
    return arc(i(t));
    };
    }

    function updateArc(d) {
    return {depth: d.depth, x: d.x, dx: d.dx};
    }

    d3.select(self.frameElement).style(“height”, margin.top + margin.bottom + “px”);
    }

    return {
    init: function (){

    // Retrieving the references
    $ = context.getGlobal(‘jQuery’);
    commonUtils = context.getService(‘commonUtils’);
    jsonService = context.getService(‘jsonService’);
    colors = context.getGlobal(‘colorbrewer’);
    d3 = context.getGlobal(‘d3’);
    showLoading(true);
    //Method to get the SunburstWrapper
    getSunburstWrapper();

    }

    };
    });

Viewing 1 post (of 1 total)

You must be logged in to reply to this topic.