1// Source: http://bl.ocks.org/godds/ec089a2cf3e06a2cd5fc 2 3var brush_year_obs; 4var brush_year_stddist; 5function draw_barchart_year(data4graph, update, target){ 6 7 8 // sizing information, including margins so there is space for labels, etc 9 var margin = { top: 20, right: 20, bottom: 120, left: 50 }, 10 width = 500 - margin.left - margin.right, 11 height = 300 - margin.top - margin.bottom, 12 marginOverview = { top: 230, right: margin.right, bottom: 50, left: margin.left }, 13 heightOverview = 300 - marginOverview.top - marginOverview.bottom; 14 15 // set up a date parsing function for future use 16 var parseDate = d3.time.format("%Y").parse; 17 var parseYMD = d3.time.format("%Y-%m-%d").parse; 18 // some colours to use for the bars 19 var colour = d3.scale.ordinal() 20 .range(["#A9A9A9", "#000000"]); 21 22 // mathematical scales for the x and y axes 23 var x = d3.time.scale() 24 .range([0, width]); 25 var y = d3.scale.linear() 26 .range([height, 0]); 27 var xOverview = d3.time.scale() 28 .range([0, width]); 29 var yOverview = d3.scale.linear() 30 .range([heightOverview, 0]); 31 32 // rendering for the x and y axes 33 var xAxis = d3.svg.axis() 34 .scale(x) 35 .orient("bottom") 36 .ticks(d3.time.years) 37 .tickSize(16, 0) 38 .tickFormat(d3.time.format("%Y")); 39 var yAxis = d3.svg.axis() 40 .scale(y) 41 .orient("left"); 42 var xAxisOverview = d3.svg.axis() 43 .scale(xOverview) 44 .orient("bottom") 45 .ticks(d3.time.years); 46 //.tickSize(16, 0) 47 //.tickFormat(d3.time.format("%b %Y")); 48 var svg; 49 var main; 50 var overview; 51 var brush_year; 52 53 var svgid = "svg_bar_obs_year"; 54 var brushid = "brush_bar_obs_year"; 55 var divid = "d3baryearobs"; 56 var ylabel = "Observations"; 57 if("StdDistance"==target){ 58 svgid = "svg_bar_stddist_year"; 59 brushid = "brush_bar_stddist_year"; 60 divid = "d3baryearstddist"; 61 ylabel = "Std Distance (km)"; 62 } 63 if("IDs"==target){ 64 svgid = "svg_bar_ids_year"; 65 brushid = "brush_bar_ids_year"; 66 divid = "d3baryearids"; 67 ylabel = "Identifications"; 68 } 69 70 if(/*true == update*/d3.select("#"+svgid)[0][0] != null){ 71 d3.select("#"+svgid).remove(); 72 } 73 if(data4graph.length == 0){ 74 return; 75 } 76 // something for us to render the chart into 77 svg = d3.select("#"+divid) 78 .append("svg") // the overall space 79 .attr("id", svgid) 80 .attr("width", width + margin.left + margin.right) 81 .attr("height", height + margin.top + margin.bottom); 82 main = svg.append("g") 83 .attr("class", "main") 84 .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 85 overview = svg.append("g") 86 .attr("class", "overview") 87 .attr("transform", "translate(" + marginOverview.left + "," + marginOverview.top + ")"); 88 89 // brush tool to let us zoom and pan using the overview chart 90 /* 91 brush_year = d3.svg.brush() 92 .x(xOverview) 93 .on("brush", brushed) 94 .on("brushend", brushend); 95 */ 96 if("StdDistance" == target){ 97 brush_year_stddist = d3.svg.brush() 98 .x(xOverview) 99 .on("brush", brushed) 100 .on("brushend", brushend); 101 brush_year = brush_year_stddist; 102 }else if("IDs" == target){ 103 brush_year_ids = d3.svg.brush() 104 .x(xOverview) 105 .on("brush", brushed) 106 .on("brushend", brushend); 107 brush_year = brush_year_ids; 108 }else{ 109 brush_year_obs = d3.svg.brush() 110 .x(xOverview) 111 .on("brush", brushed) 112 .on("brushend", brushend); 113 brush_year = brush_year_obs; 114 } 115 // setup complete, let's get some data! 116 //d3.csv(datafile, parse_data, function(data) { 117 118 data = data4graph.map(parse_data); 119 120 //var barwidth = Math.max(Math.floor(width/((data[data.length-1].date-data[0].date)/1000/3600/24/365+1)), 2); 121 var barwidth = Math.max(Math.floor(width/((parseYMD($("#dateend").val())-parseYMD($("#datestart").val()))/1000/3600/24/365)), 2); 122 123 /* 124 if(data.length == 1){ 125 barwidth = Math.floor(width/2); 126 } 127 */ 128 129 //console.log(data) 130 // data ranges for the x and y axes 131 //x.domain(d3.extent(data, function(d) { return d.date; })); 132 133 x.domain([parseYMD($("#datestart").val()), parseYMD($("#dateend").val())]); 134 y.domain([0, d3.max(data, function(d) { return d.total; })]); 135 xOverview.domain(x.domain()); 136 yOverview.domain(y.domain()); 137 138 // data range for the bar colours 139 // (essentially maps attribute names to colour values) 140 colour.domain(d3.keys(data[0])); 141 142 // draw the axes now that they are fully set up 143 main.append("g") 144 .attr("class", "x axis") 145 .attr("transform", "translate(0," + height + ")") 146 .call(xAxis); 147 main.append("g") 148 .attr("class", "y axis") 149 .call(yAxis); 150 151 svg.append("text") 152 .attr("transform", "rotate(-90)") 153 .attr("y", -2) 154 .attr("x",-100) 155 .attr("dy", "1em") 156 .style("text-anchor", "middle") 157 .style("font-size", "12px") 158 .text(ylabel); 159 160 overview.append("g") 161 .attr("class", "x axis") 162 .attr("transform", "translate(0," + heightOverview + ")") 163 .call(xAxisOverview); 164 165 svg.selectAll(".x.axis text") // select all the text elements for the xaxis 166 .attr("transform", function(d) { 167 return "translate(" + this.getBBox().height*-2 + "," + this.getBBox().height + ")rotate(-45)"; 168 }); 169 170 // draw the bars 171 main.append("g") 172 .attr("class", "bars") 173 // a group for each stack of bars, positioned in the correct x position 174 .selectAll(".bar.stack") 175 .data(data) 176 .enter().append("g") 177 .attr("class", "bar stack") 178 .attr("transform", function(d) { return "translate(" + x(d.date) + ",0)"; }) 179 // a bar for each value in the stack, positioned in the correct y positions 180 .selectAll("rect") 181 .data(function(d) { return d.counts; }) 182 .enter().append("rect") 183 .attr("class", "bar") 184 .attr("width", barwidth) 185 .attr("y", function(d) { return y(d.y1); }) 186 .attr("height", function(d) { return y(d.y0) - y(d.y1); }) 187 .style("fill", function(d) { return colour(d.name); }); 188 189 overview.append("g") 190 .attr("class", "obars") 191 .selectAll(".bar") 192 .data(data) 193 .enter().append("rect") 194 .attr("class", "bar") 195 .attr("x", function(d) { return xOverview(d.date) - 3; }) 196 .attr("width", barwidth) 197 .attr("y", function(d) { return yOverview(d.total); }) 198 .attr("height", function(d) { return heightOverview - yOverview(d.total); }); 199 200 // add the brush target area on the overview chart 201 overview.append("g") 202 .attr("class", "x brush") 203 .attr("id", brushid) 204 .call(brush_year) 205 .selectAll("rect") 206 // -6 is magic number to offset positions for styling/interaction to feel right 207 .attr("y", -6) 208 // need to manually set the height because the brush has 209 // no y scale, i.e. we should see the extent being marked 210 // over the full height of the overview chart 211 .attr("height", heightOverview + 7); // +7 is magic number for styling 212 213 // by habit, cleaning/parsing the data and return a new object to ensure/clarify data object structure 214 function parse_data(d) { 215 //var value = { date: parseDate(d.date) }; // turn the date string into a date object 216 var value = { date: parseDate(""+d.date) }; // turn the date string into a date object 217 218 // adding calculated data to each count in preparation for stacking 219 var y0 = 0; // keeps track of where the "previous" value "ended" 220 var variables = ["count_obs", "count_obscured"]; 221 if(target == "StdDistance"){ 222 variables = ["std_dist_km"]; 223 } 224 if(target == "IDs"){ 225 variables = ["count_ids"]; 226 } 227 value.counts = variables.map(function(name) { //, "count2", "count3" 228 j = { name: name, 229 y0: y0, 230 // add this count on to the previous "end" to create a range, and update the "previous end" for the next iteration 231 y1: y0 += +d[name] 232 }; 233 if(isNaN(j.y0)){ 234 j.y0 = 0; 235 } 236 if(isNaN(j.y1)){ 237 j.y1 = 0; 238 } 239 return j; 240 }); 241 // quick way to get the total from the previous calculations 242 value.total = value.counts[value.counts.length - 1].y1; 243 if(isNaN(value.total)){ 244 value.total = 0; 245 } 246 //console.log(value); 247 return value; 248 } 249 250 // zooming/panning behaviour for overview chart 251 function brushed() { 252 //console.log("yearly bar brush() triggered"); 253 // update the main chart's x axis data range 254 x.domain(brush_year.empty() ? xOverview.domain() : brush_year.extent()); 255 // redraw the bars on the main chart 256 main.selectAll(".bar.stack") 257 .attr("transform", function(d) { return "translate(" + x(d.date) + ",0)"; }) 258 // redraw the x axis of the main chart 259 main.select(".x.axis").call(xAxis); 260 261 svg.selectAll(".x.axis text") // select all the text elements for the xaxis 262 .attr("transform", function(d) { 263 return "translate(" + this.getBBox().height*-2 + "," + this.getBBox().height + ")rotate(-45)"; 264 }); 265 if(brush_year.extent()[1] - brush_year.extent()[0] > 0){ 266 var N = (brush_year.extent()[1] - brush_year.extent()[0])/1000/3600/24/365+1; 267 //console.log(width, N, Math.floor(width/N)); 268 main.selectAll(".bar").attr('width', Math.max(2, Math.floor(width/N))); 269 } 270 else{ 271 var barwidth = Math.max(Math.floor(width/Math.ceil((data[data.length-1].date-data[0].date)/1000/3600/24/365+1)), 2); 272 if(data.length == 1){ 273 barwidth = Math.floor(width/2); 274 } 275 main.selectAll(".bar").attr('width', Math.max(2, barwidth)); 276 } 277 278 279 } 280 281 function brushend(){ 282 283 //console.log("yearly bar brushend() triggered"); 284 285 var ext = brush_year.extent(); 286 var d1 = ext[0]; 287 var d2 = ext[1]; 288 289 if(d2 - d1 == 0){ 290 //console.log("zero extent"); 291 main.selectAll(".bar").attr('width', barwidth); 292 } 293 294 /* snapping to edges of year 295 var y1 = d1.getFullYear(); 296 var y2 = d2.getFullYear(); 297 298 var ext_snapped = [new Date(y1, 0, 01), new Date(y2, 11, 31)] 299 */ 300 var ext_snapped = [d1, d2]; 301 302 d3.select("brush_year").call((brush_year.empty()) ? brush_year.clear() :brush_year.extent(ext_snapped)); 303 304 //* 305 drawBrushMonth(); 306 307 function drawBrushMonth() { 308 // our year will this.innerText 309 //console.log(this.innerText) 310 311 /* 312 var brush_xx = brush_month_obs; 313 var brush = d3.select("#brush_bar_obs_month.brush"); 314 if("StdDistance" == target){ 315 brush_xx = brush_month_stddist; 316 brush = d3.select("#brush_bar_stddist_month.brush"); 317 } 318 */ 319 320 var brush_xxs = [brush_month_obs, brush_month_stddist, brush_month_ids]; 321 var brushs = [d3.select("#brush_bar_obs_month.brush"), d3.select("#brush_bar_stddist_month.brush"), d3.select("#brush_bar_ids_month.brush")]; 322 323 for(var i in brush_xxs){ 324 325 brush_xx = brush_xxs[i]; 326 brush = brushs[i]; 327 328 var diff_d1 = brush_xx.extent()[0] - ext_snapped[0]; 329 var diff_d2 = brush_xx.extent()[1] - ext_snapped[1]; 330 331 if(diff_d1 == 0 && diff_d2 == 0){ 332 continue; 333 } 334 335 // define our brush extent to be begin and end of the year 336 brush_xx.extent(jQuery.extend(true, [], ext_snapped)); 337 338 // now draw the brush to match our extent 339 // use transition to slow it down so we can see what is happening 340 // remove transition so just d3.select(".brush") to just draw 341 brush_xx(brush.transition()); 342 //brush_xx(brush); 343 344 // now fire the brushstart, brushmove, and brushend events 345 // remove transition so just d3.select(".brush") to just draw 346 brush_xx.event(brush.transition().delay(0)); 347 //brush_xx.event(brush); 348 } 349 } 350 //*/ 351 352 353 /* 354 var dt_start = brush_year.extent()[0]; 355 var dt_end = brush_year.extent()[1]; 356 if(dt_start.toString() != dt_end.toString()){ 357 $("#datestart_tmp").val(dt_start.toJSON().split("T")[0]); 358 $("#dateend_tmp").val(dt_end.toJSON().split("T")[0]); 359 $(".datetemp").show(); 360 361 $("#datestart").prop( "disabled", true ); 362 $("#dateend").prop( "disabled", true ); 363 $("#obscured").prop( "disabled", true ); 364 $("#captivecultivated").prop( "disabled", true ); 365 $("#userid").prop( "disabled", true ); 366 $("#submit").prop( "disabled", true ); 367 368 d3.select("#query").selectAll("label").style("color","gray"); 369 d3.selectAll(".datetemp").selectAll("label").style("color","black"); 370 371 tmpMode = true; 372 373 $("#dateend_tmp").trigger("change"); 374 375 376 }else{ 377 $(".datetemp").hide(); 378 $("#datestart").prop( "disabled", false ); 379 $("#dateend").prop( "disabled", false ); 380 $("#obscured").prop( "disabled", false ); 381 $("#captivecultivated").prop( "disabled", false ); 382 $("#userid").prop( "disabled", false ); 383 $("#submit").prop( "disabled", false ); 384 385 d3.select("#query").selectAll("label").style("color","black"); 386 tmpMode = false; 387 388 $("#submit").trigger("click"); 389 } 390 */ 391 } 392 393}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.