| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 | Drupal.behaviors.tripalFeature_adminSummaryChart = {  attach: function (context, settings) {    // Set-up the dimensions for our chart canvas.    // Note: these are adjusted below so think of these are your minimum size.    var margin = {top: 20, right: 50, bottom: 20, left: 100},        fullWidth = document.getElementById('tripal-feature-admin-summary').offsetWidth,        width = fullWidth - margin.left - margin.right,        height = 300 - margin.top - margin.bottom;    var color = d3.scale.ordinal()        .range(["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99","#b15928"]);    var formatNum = d3.format("0,000");    // The data was parsed and saved into tripalFeature.admin.summary    // in the preprocess function for this template.    if (Drupal.settings.tripalFeature.admin.summary) {      // Determine the max number of characters in both the type name      // and the total number of features per bar for use in width/magin adjustments.      var maxTypeLength = 0;      var maxTotalLength = 0;      var numBars = Drupal.settings.tripalFeature.admin.summary.length;      for(var i=0; i < numBars; i++){        var element = Drupal.settings.tripalFeature.admin.summary[i];        if(element.name.length > maxTypeLength){          maxTypeLength = element.name.length;        }        if(element.total_features.length > maxTotalLength){          maxTotalLength = element.total_features.length;        }      }      // Ensure a minimum in case something goes wrong...      if (maxTotalLength < 4) { maxTotalLength = 4; }      if (maxTypeLength < 10) { maxTypeLength = 10; }      // Adjust our bottom margin based on the length of type names in the data.      // Assume 4px/character based on the slope of the label.      xAxisHeight = maxTypeLength * 3;      margin.bottom = xAxisHeight + 25;      // Adjust the width of the chart based on the number or bars (types)      // and the length of the bar totals which need to fit on the top of the bar.      // Assume 9px/character since it's not rotated.      if ((width + margin.left + margin.right) < (numBars * (maxTotalLength * 9))) {        width = numBars * (maxTotalLength * 9);      }      // Determine the best place for the legend. Default to top since that      // will for sure not cause conflict... even though it looks better      // on the right ;).      // Logic: If the difference between the max & min bar heights is greater      // than 1/2 the chart height (max bar height) then there "should"      // be room for the chart nested on the right.      minBarHeight = d3.min(Drupal.settings.tripalFeature.admin.summary, function(d,i) { return d.total_features; });      barHeightDifference = Drupal.settings.tripalFeature.admin.maxBarHeight - minBarHeight;      if (barHeightDifference >= Drupal.settings.tripalFeature.admin.maxBarHeight/2) {        Drupal.settings.tripalFeature.admin.legendPosition = 'right';      }      // Also if we need to put the legend along the top we need to      // increase the top margin.      if (Drupal.settings.tripalFeature.admin.legendPosition == 'top') {        // Draw a top legend in the margin.        var columnWidth = d3.max(Drupal.settings.tripalFeature.admin.organisms, function(d,i) {return d.length;}) * 10;        var maxNumColumns = Math.round(width / columnWidth);        var numRows = Math.ceil(Drupal.settings.tripalFeature.admin.organisms.length / maxNumColumns);        var idealNumColumns = Math.round(Drupal.settings.tripalFeature.admin.organisms.length / numRows);        var legendMargin = {          left: (width - (idealNumColumns * columnWidth))/2,          right: (width - (idealNumColumns * columnWidth))/2,          bottom: 25        };        margin.top = margin.top + (numRows * 20) + legendMargin.bottom;      }      // Set-up the scales of the chart.      var x0 = d3.scale.ordinal()        .rangeRoundBands([0, width], .1);      var x1 = d3.scale.ordinal();      var y = d3.scale.linear()        .range([height, 0]);      // Now set-up the axis functions.      var xAxis = d3.svg.axis()        .scale(x0)        .orient('bottom');      var yAxis = d3.svg.axis()        .scale(y)        .orient('left')        .ticks(10, '');      // Create our chart canvas.      var svg = d3.select('#tripal-feature-admin-summary-chart').append('svg')          .attr('width', width + margin.left + margin.right)          .attr('height', height + margin.top + margin.bottom)        .append('g')          .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');      // map the data to the x & y axis' of our chart.      data = Drupal.settings.tripalFeature.admin.summary;      x0.domain(data.map(function(d) { return d.name; }));      x1.domain(Drupal.settings.tripalFeature.admin.organisms).rangeRoundBands([0, x0.rangeBand()]);      y.domain([0, Drupal.settings.tripalFeature.admin.maxBarHeight]);      // Create the x-axis.      var xaxis = svg.append('g')        .attr('class', 'x axis')        .attr('transform', 'translate(0,' + height + ')')        .call(xAxis);      xaxis.selectAll("text")        .style("text-anchor", "end")        .attr("dx", "-.8em")        .attr("dy", ".15em")        .attr("transform", function(d) { return "rotate(-25)"; });      // Label the  x-axis.      xaxis.append('g')        .attr('class', 'axis-label')          .attr('transform', 'translate(' + width/2 + ',' + xAxisHeight + ')')        .append('text')          .attr('font-size', '16px')          .attr('dy', '.71em')          .style('text-anchor', 'middle')          .text('Types of Features');      // Create the y-axis.      var yaxis = svg.append('g')          .attr('class', 'y axis')          .call(yAxis);      // Label the y-axis.      yaxis.append('g')        .attr('class', 'axis-label')          .attr('transform', 'translate(-70,' + height/2 + ')')        .append('text')          .attr('transform', 'rotate(-90)')          .attr('font-size', '16px')          .attr('dy', '.71em')          .style('text-anchor', 'middle')          .text('Total Number of Features');      // Add a g element to contain each set of bars (1 per type).      var type = svg.selectAll(".type")          .data(data)        .enter().append("g")          .attr("class", "g")          .attr("transform", function(d) { return "translate(" + x0(d.name) + ",0)"; });      // Now add the bars :)      // Keep in mind some processing was done in the preprocess function to      // generate the bars array based on the organisms array      // and pre-calculated the y0 & y1 used here.      type.selectAll("rect")          .data(function(d) { return d.bars; })        .enter().append("rect")          .attr("width", x0.rangeBand())          .attr("y", function(d) { return y(d.y1); })          .attr("height", function(d) { return y(d.y0) - y(d.y1); })          .style("fill", function(d) { return color(d.name); })        .append("svg:title")          .text(function(d) { return formatNum(d.y1 - d.y0); });      // Add the total to the top of the bar.      svg.selectAll("g.bar-totals")        .data(data)      .enter().append('g')        .classed('bar-totals', true)      .append("text")        .attr("class", "bar-label")        .attr("text-anchor", "middle")        .attr('font-size', '10px')        .attr("x", function(d) { return x0(d.name) + x0.rangeBand()/2; })        .attr("y", function(d) { return y(d.total_features) -5; })        .text(function(d) { return formatNum(d.total_features); });      // Legend      //---------      // NOTE: we would prefer to have the legend overlapping the chart on the      // right side but this could be a problem if you have a similar count      // for all features (legend overlaps bars) or a large number of types      // (legend gets pushed out of the viewable screen area). In these cases      // switch to a bottom legend.      if (Drupal.settings.tripalFeature.admin.legendPosition == 'top') {        // Draw a bottom legend in the margin.        var legend = svg.append('g')          .classed('legend', true)          .attr('transform', 'translate(' + (legendMargin.left - 20) + ',-' + margin.top + ')');        var legendItem = legend.selectAll('g')            .data(Drupal.settings.tripalFeature.admin.organisms.slice().reverse())          .enter().append("g")            .attr("class", "legend-item")            .attr("transform", function(d,i) {              xOff = (i % idealNumColumns) * columnWidth;              yOff = Math.floor(i  / idealNumColumns) * 25;              return "translate(" + xOff + "," + yOff + ")"          });        legendItem.append("rect")            //.attr("x", width - 18)            .attr("width", 18)            .attr("height", 18)            .style("fill", color);        legendItem.append("text")            .attr("x", 24)            .attr("y", 9)            .attr("dy", ".35em")            .style("text-anchor", "start")            .attr('font-style','italic')            .text(function(d) { return d; });      }      else {        // Draw a right inset legend.        var legend = svg.append('g')          .classed('legend', true)          .attr('transform', 'translate(0,-' + margin.top + ')');        var legendItem = legend.selectAll('g')            .data(Drupal.settings.tripalFeature.admin.organisms.slice().reverse())          .enter().append("g")            .attr("class", "legend")            .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });        legendItem.append("rect")            .attr("x", width - 18)            .attr("width", 18)            .attr("height", 18)            .style("fill", color);        legendItem.append("text")            .attr("x", width - 24)            .attr("y", 9)            .attr("dy", ".35em")            .style("text-anchor", "end")            .attr('font-style','italic')            .text(function(d) { return d; });      }    }  }};
 |