1 /** 2 * @license 3 * Copyright 2012 Dan Vanderkam (danvdk@gmail.com) 4 * MIT-licenced: https://opensource.org/licenses/MIT 5 */ 6 /*global Dygraph:false */ 7 8 "use strict"; 9 10 // TODO(danvk): move chart label options out of dygraphs and into the plugin. 11 // TODO(danvk): only tear down & rebuild the DIVs when it's necessary. 12 13 var chart_labels = function() { 14 this.title_div_ = null; 15 this.xlabel_div_ = null; 16 this.ylabel_div_ = null; 17 this.y2label_div_ = null; 18 }; 19 20 chart_labels.prototype.toString = function() { 21 return "ChartLabels Plugin"; 22 }; 23 24 chart_labels.prototype.activate = function(g) { 25 return { 26 layout: this.layout, 27 // clearChart: this.clearChart, 28 didDrawChart: this.didDrawChart 29 }; 30 }; 31 32 // QUESTION: should there be a plugin-utils.js? 33 var createDivInRect = function(r) { 34 var div = document.createElement('div'); 35 div.style.position = 'absolute'; 36 div.style.left = r.x + 'px'; 37 div.style.top = r.y + 'px'; 38 div.style.width = r.w + 'px'; 39 div.style.height = r.h + 'px'; 40 return div; 41 }; 42 43 // Detach and null out any existing nodes. 44 chart_labels.prototype.detachLabels_ = function() { 45 var els = [ this.title_div_, 46 this.xlabel_div_, 47 this.ylabel_div_, 48 this.y2label_div_ ]; 49 for (var i = 0; i < els.length; i++) { 50 var el = els[i]; 51 if (!el) continue; 52 if (el.parentNode) el.parentNode.removeChild(el); 53 } 54 55 this.title_div_ = null; 56 this.xlabel_div_ = null; 57 this.ylabel_div_ = null; 58 this.y2label_div_ = null; 59 }; 60 61 var createRotatedDiv = function(g, box, axis, classes, html) { 62 // TODO(danvk): is this outer div actually necessary? 63 var div = document.createElement("div"); 64 div.style.position = 'absolute'; 65 if (axis == 1) { 66 // NOTE: this is cheating. Should be positioned relative to the box. 67 div.style.left = '0px'; 68 } else { 69 div.style.left = box.x + 'px'; 70 } 71 div.style.top = box.y + 'px'; 72 div.style.width = box.w + 'px'; 73 div.style.height = box.h + 'px'; 74 div.style.fontSize = (g.getOption('yLabelWidth') - 2) + 'px'; 75 76 var inner_div = document.createElement("div"); 77 inner_div.style.position = 'absolute'; 78 inner_div.style.width = box.h + 'px'; 79 inner_div.style.height = box.w + 'px'; 80 inner_div.style.top = (box.h / 2 - box.w / 2) + 'px'; 81 inner_div.style.left = (box.w / 2 - box.h / 2) + 'px'; 82 // TODO: combine inner_div and class_div. 83 inner_div.className = 'dygraph-label-rotate-' + (axis == 1 ? 'right' : 'left'); 84 85 var class_div = document.createElement("div"); 86 class_div.className = classes; 87 class_div.innerHTML = html; 88 89 inner_div.appendChild(class_div); 90 div.appendChild(inner_div); 91 return div; 92 }; 93 94 chart_labels.prototype.layout = function(e) { 95 this.detachLabels_(); 96 97 var g = e.dygraph; 98 var div = e.chart_div; 99 if (g.getOption('title')) { 100 // QUESTION: should this return an absolutely-positioned div instead? 101 var title_rect = e.reserveSpaceTop(g.getOption('titleHeight')); 102 this.title_div_ = createDivInRect(title_rect); 103 this.title_div_.style.fontSize = (g.getOption('titleHeight') - 8) + 'px'; 104 105 var class_div = document.createElement("div"); 106 class_div.className = 'dygraph-label dygraph-title'; 107 class_div.innerHTML = g.getOption('title'); 108 this.title_div_.appendChild(class_div); 109 div.appendChild(this.title_div_); 110 } 111 112 if (g.getOption('xlabel')) { 113 var x_rect = e.reserveSpaceBottom(g.getOption('xLabelHeight')); 114 this.xlabel_div_ = createDivInRect(x_rect); 115 this.xlabel_div_.style.fontSize = (g.getOption('xLabelHeight') - 2) + 'px'; 116 117 var class_div = document.createElement("div"); 118 class_div.className = 'dygraph-label dygraph-xlabel'; 119 class_div.innerHTML = g.getOption('xlabel'); 120 this.xlabel_div_.appendChild(class_div); 121 div.appendChild(this.xlabel_div_); 122 } 123 124 if (g.getOption('ylabel')) { 125 // It would make sense to shift the chart here to make room for the y-axis 126 // label, but the default yAxisLabelWidth is large enough that this results 127 // in overly-padded charts. The y-axis label should fit fine. If it 128 // doesn't, the yAxisLabelWidth option can be increased. 129 var y_rect = e.reserveSpaceLeft(0); 130 131 this.ylabel_div_ = createRotatedDiv( 132 g, y_rect, 133 1, // primary (left) y-axis 134 'dygraph-label dygraph-ylabel', 135 g.getOption('ylabel')); 136 div.appendChild(this.ylabel_div_); 137 } 138 139 if (g.getOption('y2label') && g.numAxes() == 2) { 140 // same logic applies here as for ylabel. 141 var y2_rect = e.reserveSpaceRight(0); 142 this.y2label_div_ = createRotatedDiv( 143 g, y2_rect, 144 2, // secondary (right) y-axis 145 'dygraph-label dygraph-y2label', 146 g.getOption('y2label')); 147 div.appendChild(this.y2label_div_); 148 } 149 }; 150 151 chart_labels.prototype.didDrawChart = function(e) { 152 var g = e.dygraph; 153 if (this.title_div_) { 154 this.title_div_.children[0].innerHTML = g.getOption('title'); 155 } 156 if (this.xlabel_div_) { 157 this.xlabel_div_.children[0].innerHTML = g.getOption('xlabel'); 158 } 159 if (this.ylabel_div_) { 160 this.ylabel_div_.children[0].children[0].innerHTML = g.getOption('ylabel'); 161 } 162 if (this.y2label_div_) { 163 this.y2label_div_.children[0].children[0].innerHTML = g.getOption('y2label'); 164 } 165 }; 166 167 chart_labels.prototype.clearChart = function() { 168 }; 169 170 chart_labels.prototype.destroy = function() { 171 this.detachLabels_(); 172 }; 173 174 export default chart_labels; 175