(function($){ $.fn.phTreemap = function(options){ var phTreemap = $.fn.phTreemap; var $dom = $(this), id = $dom.selector, parent = $(this).parent(), endpoint = $dom.data('url'), npi = $dom.data('npi'), entitytypecode = $dom.data('entitytype'), CHART_HEIGHT = $dom.data('height'); CHART_HEIGHT = (CHART_HEIGHT === undefined ? 600 : CHART_HEIGHT); $(id).append( '<div class="panel-heading">' +'<h4 id="marketmapheader"></h4>' +'</div>' +'<div class="panel-body">' +'<div id="tabs">' +'<ul class="nav nav-tabs">' +'<li class="active"><a id="splittersTab" data-toggle="tab" href="#splittersChart">Splitters</a></li>' +'<li class=""><a id="allPhysiciansTab" data-toggle="tab" href="#allPhysiciansChart">All Physicians</a></li>' +'<li><a id="loyalistsTab" data-toggle="tab" href="#loyalistsChart">Loyalists</a></li>' +'<a id="report" class="btn btn-default btn-med disabled pull-right">Generate Report</a>' +'</ul>' +'</div>' +'<div class="tab-content">' +'<div id="splittersChart" class="tab-pane fade in active"></div>' +'<div id="allPhysiciansChart" class="tab-pane fade">' +'</div>' +'<div id="loyalistsChart" class="tab-pane fade">' +'</div>' +'<div id="communityChart" class="tab-pane fade"></div>' +'</div>' +'</div>' +'<div id="legend"></div>' ) String.prototype.capitalize = function(all){ if(all){ return this.split(' ').map(function(e){return e.capitalize();}).join(' '); }else{ return this.charAt(0).toUpperCase() + this.slice(1).toLowerCase(); } } var activateTab = function(tab_){ $('.nav-tabs a[href="#' + tab_ + '"]').tab('show'); }; document.onkeydown = function(e) { switch (e.keyCode) { case 37: if ($('#loyalistsChart').hasClass("active")){ activateTab("allPhysiciansChart"); } else if ($('#splittersChart').hasClass("active")){ activateTab("loyalistsChart") } break; case 39: if ($('#allPhysiciansChart').hasClass("active")){ activateTab("loyalistsChart"); } else if ($('#loyalistsChart').hasClass("active")){ activateTab("splittersChart"); } break; } }; $(".btn-group > .btn").click(function(){ $(this).addClass("active").siblings().removeClass("active"); }); var dataAll, splitters, initialized, filter, drillDown, graphName = "allPhysicians", splitterCount = 0, allPhysiciansReportData, loyalistsReportData, splittersReportData, reportData var formatNumber = d3.format(",d"); var allPhysiciansMapHasChildren = loyalistsMapHasChildren = splittersMapHasChildren = true; var initialValue = ""; var allBreadcrumbs = loyalistBreadcrumbs = splitterBreadcrumbs = initialValue; $('.grandparent').hide(); var mousemove = function(d) { var xPosition = (d3.event.pageX > 450 ? d3.event.pageX - 220 : d3.event.pageX + 5); var yPosition = d3.event.pageY - 55; d3.select("#tooltip") .style("left", xPosition + "px") .style("top", yPosition + "px"); d3.select("#tooltip #heading") .text(d.name); d3.select("#tooltip #visits") .text("Visits: " + formatNumber(d.value)); // d3.select("#tooltip #otherinfo") // .text("test"); d3.select("#tooltip").classed("hidden", false); }; var mouseout = function() { d3.select("#tooltip").classed("hidden", true); }; var build = function(root){ $('#report').on('click', function(){ var filter, chartType; if ($('#loyalistsChart').hasClass("active")){ reportData = loyalistsReportData; filter = $('#loyalistsChart').find('svg > g').find('.grandparent')[0].textContent.split(" > "); chartType = "Loyalists_"; } else if ($('#allPhysiciansChart').hasClass("active")){ reportData = allPhysiciansReportData; filter = $('#allPhysiciansChart').find('svg > g').find('.grandparent')[0].textContent.split(" > "); chartType = "AllPhysicians_"; } else if ($('#splittersChart').hasClass("active")){ reportData = splittersReportData; filter = $('#splittersChart').find('svg > g').find('.grandparent')[0].textContent.split(" > "); chartType = "splitters_"; } var drillDown = filter.length-1; var title = filter[drillDown]; var nonSpecialists;// = (title.indexOf("(non-specialists)") > -1); var level; for (var i=0;i<filter.length;i++){ if (filter[i].indexOf("non-specialists")>-1){ nonSpecialists = true; } } if (drillDown == 0){ level = "Market Map"; } else if (drillDown == 1){ level = "Taxonomy"; } else if (drillDown == 2){ level = "Classification"; } else if (drillDown == 4 || nonSpecialists){ level = "Provider Name"; } else if (drillDown == 3){ level = "Specialization"; } var generateReport = []; if (title == "Market Map"){ generateReport = reportData; } else { for (var i = 0; i < reportData.length; i++){ if (reportData[i][level] == title){ generateReport.push(reportData[i]) } } } title = chartType + filter[drillDown]; JSONToCSVConvertor(generateReport, title, true); }); allPhysiciansReportData = _.sortBy(root.nodes, 'Share').reverse(); splittersReportData = []; loyalistsReportData = []; for (var i = 0; i < allPhysiciansReportData.length; i++){ var visitsToSelected = allPhysiciansReportData[i]["Visits to hospital"]; var visitsToOther = allPhysiciansReportData[i]["Visits to other General Acute Hospitals"]; var totalVisits = visitsToOther + visitsToSelected; var leakage = (visitsToOther/totalVisits)*100 var percentCaptured = 100 - leakage; if (leakage <= 25 && percentCaptured >= 75){ loyalistsReportData.push(allPhysiciansReportData[i]) } else if (leakage < 75){ splittersReportData.push(allPhysiciansReportData[i]) } } splitters = JSON.parse(root.splitters); loyaliststree = JSON.parse(root.loyalists); root = JSON.parse(root.allDocs); // dataAll = root; phTreemap.buildTreemap = function(data, id) { var margin = {top:25, right: 0, bottom: 0, left: 0}, width = parent.width() - margin.top, height = CHART_HEIGHT,// - margin.top - margin.bottom, transitioning; var mousemove = function(d) { var xPosition = d3.event.pageX - 220; var yPosition = d3.event.pageY - 55; d3.select("#tooltip") .style("left", xPosition + "px") .style("top", yPosition + "px"); d3.select("#tooltip #heading") //.html("<strong>"+d.name+"</strong>"); .html(function(){ if (d._children){ return "<strong>"+d.name+"</strong>"; } else { return "<strong>"+d.parent.name+"</strong>"; } }) d3.select("#tooltip #visits") .html(function(){ if (d._children){ return "<strong>Visits:</strong> "+formatNumber(d.value)+"</br><strong>Percent captured:</strong> "+(threshold(d, "html")[1] * 100).toFixed(2) + "%"; } else { if (d.name.indexOf("to other hospitals") > -1){ var leakage = d.value/d.total; var captured = 1 - leakage; return "<strong>Visits:</strong> "+formatNumber(d.total - d.value)+"</br><strong>Visits to other hospitals:</strong> "+formatNumber(d.value)+"</br><strong>Percent Captured:</strong> "+(captured*100).toFixed(2)+"%"+"</br><strong>Leakage:</strong> "+(leakage*100).toFixed(2)+"%"; } else { var leakage = d.value/d.total; var captured = 1 - leakage; return "<strong>Visits:</strong> "+formatNumber(d.value)+"</br><strong>Visits to other hospitals:</strong> "+formatNumber(d.total-d.value)+"</br><strong>Percent Captured:</strong> "+(leakage*100).toFixed(2)+"%"+"</br><strong>Leakage:</strong> "+(captured*100).toFixed(2)+"%"; } } }) // d3.select("#tooltip #otherinfo") // .text("test"); d3.select("#tooltip").classed("hidden", false); }; var mouseout = function() { d3.select("#tooltip").classed("hidden", true); }; var x = d3.scale.linear() .domain([0, width]) .range([0, width]); var y = d3.scale.linear() .domain([0, height]) .range([0, height]); var treemap = d3.layout.treemap() .children(function(d, depth) { return depth ? null : d._children; }) .sort(function(a, b) { return a.value - b.value; }) .ratio(height / width * 0.5 * (1 + Math.sqrt(5))) .round(false); var svg = d3.select(id).append("svg") .attr("width", width) .attr("height", height + margin.top) .style("margin-left", -margin.left + "px") .style("margin-right", -margin.right + "px") .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .style("shape-rendering", "crispEdges") .style("opacity", 0);; var grandparent = svg.append("g") .attr("class", "grandparent"); grandparent.append("rect") .attr("y", -margin.top) .attr("width", width) .attr("height", margin.top); grandparent.append("text") .attr("x", 6) .attr("y", 6 - margin.top) .attr("dy", ".75em"); svg .transition() .delay(400) .duration(450) .style("opacity", 1) if (!initialized){ initialize(data); accumulate(data); layout(data); } display(data); function initialize(root) { root.x = root.y = 0; root.dx = width; root.dy = height; root.depth = 0; } // Aggregate the values for internal nodes function accumulate(d) { return (d._children = d.children) ? d.value = d.children.reduce(function(p, v) { return p + accumulate(v); }, 0) : d.value; } // Compute the treemap layout recursively such that each group of siblings // uses the same size (1×1) rather than the dimensions of the parent cell function layout(d) { if (d._children) { treemap.nodes({_children: d._children}); d._children.forEach(function(c) { c.x = d.x + c.x * d.dx; c.y = d.y + c.y * d.dy; c.dx *= d.dx; c.dy *= d.dy; c.parent = d; layout(c); }); } } function display(d) { grandparent .datum(d.parent) .on("click", transition) .select("text") .text(name(d)); var g1 = svg.insert("g", ".grandparent") .datum(d) .attr("class", "depth"); var g = g1.selectAll("g") .data(d._children) .enter().append("g"); g.filter(function(d) { return d._children; }) .classed("children", true) .on("click", transition); g.selectAll(".child") .data(function(d) { return d._children || [d]; }) .enter().append("rect") .attr("class", "child") .call(rect); /* write parent rectangle */ g.append("rect") .attr("class", "parent") .on("mousemove", mousemove) .on("mouseout", mouseout) .call(rect) .on("click", function(d) { if(!d._children){ var originUrl = location.origin; var url = originUrl+d.url // window.open(url, "_blank"); } }) .append("data-tooltip") .text(function(d) { return d.name + "\n" + formatNumber(d.value) + " visits"; }); /* Adding a foreign object instead of a text object, allows for text wrapping */ g.append("foreignObject") .call(rect) .on("mousemove", mousemove) .on("mouseout", mouseout) .attr("class","foreignobj") .append("xhtml:div") .attr("dy", ".75em") .html(function(d) { var percentToSelected; if (d._children == undefined){ percentToSelected = ((d.value/d.total)*100).toFixed(2) + "%"; } else { percentToSelected = (threshold(d, "html")[1] * 100).toFixed(2) + "%"; } return d.name + " | " + percentToSelected }) .on("click", function(d) { if(!d._children){ var originUrl = location.origin; var url = originUrl+d.url window.open(url, "_blank"); } }) .attr("class","textdiv"); function transition(d) { if (transitioning || !d) return; transitioning = true; var g2 = display(d), t1 = g1.transition().duration(750), t2 = g2.transition().duration(750); // Update the domain only after entering new elements. x.domain([d.x, d.x + d.dx]); y.domain([d.y, d.y + d.dy]); // Enable anti-aliasing during the transition. svg.style("shape-rendering", null); // Draw child nodes on top of parent nodes. svg.selectAll(".depth").sort(function(a, b) { return a.depth - b.depth; }); // Fade-in entering text. g2.selectAll("text").style("fill-opacity", 0); g2.selectAll("foreignObject div").style("display", "none"); /*added*/ // Transition to the new view. t1.selectAll("text").call(text).style("fill-opacity", 0); t2.selectAll("text").call(text).style("fill-opacity", 1); t1.selectAll("rect").call(rect); t2.selectAll("rect").call(rect); t1.selectAll(".textdiv").style("display", "none"); /* added */ t1.selectAll(".foreignobj").call(foreign); /* added */ t2.selectAll(".textdiv").style("display", "block"); /* added */ t2.selectAll(".foreignobj").call(foreign); /* added */ // Remove the old node when the transition is finished. t1.remove().each("end", function() { svg.style("shape-rendering", "crispEdges"); transitioning = false; }); } return g; } function text(text) { text.attr("x", function(d) { return x(d.x) + 6; }) .attr("y", function(d) { return y(d.y) + 6; }); } function rect(rect) { rect.attr("x", function(d) { return x(d.x); }) .attr("y", function(d) { return y(d.y); }) .attr("width", function(d) { return x(d.x + d.dx) - x(d.x); }) .attr("height", function(d) { return y(d.y + d.dy) - y(d.y); }) .style("fill", function(d){ return threshold(d, "fill")[0]}) } function position() { this.style("left", function(d) { return d.x + "px"; }) .style("top", function(d) { return d.y + "px"; }) .style("width", function(d) { return Math.max(0, d.dx - 2) + "px"; }) .style("height", function(d) { return Math.max(0, d.dy - 2) + "px"; }); } function threshold(d, location) { // sart fill var visitsToSelected = []; var visitsToOther = []; if (d.parent.name == 'Market Map'){ // fill for taxonomy nodes start $.each(d._children, function(i,v){ if (v.name.indexOf("non-specialists") > -1){ $.each(v._children, function(i1, v1){ $.each(v1._children, function(i2, v2){ if (v2.name.indexOf("to other hospitals") > -1){ visitsToOther.push(v2.value) } else { visitsToSelected.push(v2.value) } }) }) } else { $.each(v._children, function(i1, v1){ if (v1._children == undefined){ if (v1.name.indexOf("to other hospitals") > -1){ visitsToOther.push(v1.value) } else{ visitsToSelected.push(v1.value) } } else{ $.each(v1._children, function(i2, v2){ if (v2._children == undefined){ if (v2.name.indexOf("to other hospitals") > -1){ visitsToOther.push(v2.value) } else{ visitsToSelected.push(v2.value) } } else{ $.each(v2._children, function(i3, v3){ if (v3.name.indexOf("to other hospitals") > -1){ visitsToOther.push(v3.value) } else{ visitsToSelected.push(v3.value) } }) } }) } }) } }) } // taxonomy nodes else if (d.parent.parent.name == 'Market Map'){ // fill for classification nodes start $.each(d._children, function(i,v){ if (v._children == undefined){ if (v.name.indexOf("to other hospitals") > -1){ visitsToOther.push(v.value) } else { visitsToSelected.push(v.value) } } else { $.each(v._children, function(i2, v2){ if (v2._children == undefined){ if (v2.name.indexOf("to other hospitals") > -1){ visitsToOther.push(v2.value) } else { visitsToSelected.push(v2.value) } } else { $.each(v2._children, function(i3, v3){ if (v3.name.indexOf("to other hospitals") > -1){ visitsToOther.push(v3.value) } else { visitsToSelected.push(v3.value) } }) } }) } }) } // end classification nodes else if (d.parent.parent.parent.name == 'Market Map'){ // fill specialization nodes start if (d._children == undefined){ if (d.name.indexOf("to other hospitals") > -1){ visitsToOther.push(d.value) } else { visitsToSelected.push(d.value) } } else { $.each(d._children, function(i, v){ if (v._children == undefined){ if (v.name.indexOf("to other hospitals") > -1){ visitsToOther.push(v.value) } else { visitsToSelected.push(v.value) } } else { $.each(v._children, function(i1, v1){ if (v1.name.indexOf("to other hospitals") > -1){ visitsToOther.push(v1.value) } else { visitsToSelected.push(v1.value) } }) } }) } } // specialization nodes end else if (d.parent.parent.parent.parent.name == 'Market Map'){ // provider nodes start if (d._children == undefined){ if (d.name.indexOf("to other hospitals") > -1){ visitsToOther.push(d.value) } else { visitsToSelected.push(d.value) } } else { $.each(d._children, function(i, v){ if (v.name.indexOf("to other hospitals") > -1){ visitsToOther.push(v.value) } else { visitsToSelected.push(v.value) } }) } } // provider nodes end else if (d.parent.parent.parent.parent.parent.name == 'Market Map'){ // visit comparison nodes start if (d.parent.parent.name.indexOf("non-specialists") == -1){ if (d.name.indexOf("to other hospitals") > -1){ visitsToOther.push(d.value) } else { visitsToSelected.push(d.value) } } } //// visit comparison nodes end var sumOfVisitsToSelected = d3.sum(visitsToSelected); var sumOfVisitsToOther = d3.sum(visitsToOther); percentCaptured = sumOfVisitsToSelected/(sumOfVisitsToOther+sumOfVisitsToSelected); var leakageColorScale = { loyalist: ["#337ab7", percentCaptured, d.total], loyalist1: ["#63a0d4", percentCaptured, d.total], loyalist2: ["#9fc5e5", percentCaptured, d.total], loyalist3: ["#dbe9f5", percentCaptured, d.total], leaker: ["#f9e2e2", percentCaptured, d.total], leaker1: ["#f4cecd", percentCaptured, d.total], leaker2: ["#e7908e", percentCaptured, d.total], leaker3: ["#d9534f", percentCaptured, d.total] } if ((0.875 <= percentCaptured && percentCaptured <= 1) || percentCaptured > 1){ return leakageColorScale.loyalist; } else if (0.75 <= percentCaptured && percentCaptured < 0.875){ return leakageColorScale.loyalist1; } else if (0.625 <= percentCaptured && percentCaptured < 0.75){ return leakageColorScale.loyalist2; } else if (0.5 <= percentCaptured && percentCaptured < 0.625){ return leakageColorScale.loyalist3; } else if (0.375 <= percentCaptured && percentCaptured < 0.5){ return leakageColorScale.leaker; } else if (0.25 <= percentCaptured && percentCaptured < 0.375){ return leakageColorScale.leaker1; } else if (0.125 <= percentCaptured && percentCaptured < 0.25){ return leakageColorScale.leaker2; } else if (percentCaptured < 0.125){ return leakageColorScale.leaker3; } else { return "#101010" } } // end fill function name(d) { return d.parent ? name(d.parent) + " > " + d.name : d.name; } function foreign(foreign){ /* added */ foreign.attr("x", function(d) { return x(d.x); }) .attr("y", function(d) { return y(d.y); }) .attr("width", function(d) { return x(d.x + d.dx) - x(d.x); }) .attr("height", function(d) { return y(d.y + d.dy) - y(d.y); }); } } $(document).ready(function(){ // document read function $('#report').removeClass("disabled"); $('#report').removeClass("active"); // idk why the button is becoming activated $('#loyalists').removeClass("disabled"); // }); // xhr // create legend $('#legend')[0].innerHTML = "Percent of visits captured: "; var leakageColorScale = ["#337ab7", "#63a0d4", "#9fc5e5", "#dbe9f5", "#f9e2e2", "#f4cecd", "#e7908e", "#d9534f"]; var leakageLabels = ['87.5% - 100%', '75% - 87.5%', '62.5% - 75%', '50% - 62.5%', '37.5% - 50%', '25% - 37.5%', '12.5% - 25%', '0 - 12.5%'] var colors = d3.scale.quantize() .range(leakageColorScale); var legend = d3.select('#legend') .append('ul') .attr('class', 'list-inline'); var keys = legend.selectAll('li.key') .data(colors.range()); keys.enter().append('li') .attr('class', 'key') .style('border-top-color', String) .text(function(d, i) { return leakageLabels[i] }); }); // end document ready function $('.grandparent').show(); phTreemap.buildTreemap(root, "#allPhysiciansChart"); phTreemap.buildTreemap(loyaliststree, "#loyalistsChart"); phTreemap.buildTreemap(splitters, "#splittersChart"); initialized = true; window.addEventListener("resize", function() { $('#allPhysiciansChart').empty(); $('#loyalistsChart').empty(); $('#splittersChart').empty(); phTreemap.buildTreemap(root, "#allPhysiciansChart"); phTreemap.buildTreemap(loyaliststree, "#loyalistsChart"); phTreemap.buildTreemap(splitters, "#splittersChart"); }); }; if (options){ build(options.data); } else { d3.json(endpoint, function(root) { build(root); }); } } return this })(jQuery)