uvcharts.js 115 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116
  1. (function(global, factory) {
  2. if (typeof module === "object" && typeof module.exports === "object") {
  3. module.exports = global.document? factory(global, true ): factory(global);
  4. } else {
  5. factory(global);
  6. }
  7. }(typeof window !== "undefined" ? window: this, function(window, noGlobal) {
  8. "use strict";
  9. var uv = {};
  10. uv.util = {};
  11. /**
  12. * Utility method to extend prototype for JavaScript classes, to act like inheritance
  13. * @param {Class} f Original class which is being extended
  14. * @return {Prototype} Prototype containing the functions from the super class
  15. */
  16. uv.util.inherits = function (f) {
  17. function G() {}
  18. G.prototype = f.prototype || f;
  19. return new G();
  20. };
  21. /**
  22. * Utility method to return a unique identification id
  23. * @return {number} Timestamp in ms is returned as a unique id
  24. */
  25. uv.util.getUniqueId = function () {
  26. return new Date().getTime();
  27. };
  28. uv.util.getMax = function (graphdef, classification) {
  29. switch (classification) {
  30. case 'stepup':
  31. return this.getStepMaxValue(graphdef);
  32. case 'normal':
  33. return this.getMaxValue(graphdef);
  34. case 'percent':
  35. return 100;
  36. case 'waterfall':
  37. return this.getWaterfallMaxValue(graphdef);
  38. default:
  39. console.error("Unknown classification for chart", classification);
  40. }
  41. }
  42. /**
  43. *
  44. */
  45. uv.util.getMaxValue = function (graphdef) {
  46. return d3.max(graphdef.categories.map(function (d) {
  47. return d3.max(graphdef.dataset[d].map(function (d) {
  48. return d.value;
  49. }));
  50. }));
  51. };
  52. uv.util.getStepMaxValue = function (graphdef) {
  53. var sumMap = graphdef.dataset[graphdef.categories[0]].map(function () {return 0; }),
  54. maxMap = sumMap.map(function () { return 0; });
  55. graphdef.categories.map(function (d) {
  56. graphdef.dataset[d].map(function (d, i) {
  57. if (d.resetSum === true) {
  58. sumMap[i] = 0;
  59. }
  60. sumMap[i] += d.value;
  61. maxMap[i] = d3.max([sumMap[i], maxMap[i]]);
  62. });
  63. });
  64. return d3.max(maxMap);
  65. };
  66. uv.util.getWaterfallMaxValue = function(graphdef) {
  67. var sumMap = graphdef.categories.map(function() {return 0;});
  68. graphdef.categories.map(function (d, i) {
  69. var localMax = 0;
  70. graphdef.dataset[d].map(function(d) {
  71. localMax += d.value;
  72. if(sumMap[i] < localMax) {
  73. sumMap[i] = localMax;
  74. }
  75. });
  76. });
  77. return d3.max(sumMap);
  78. };
  79. uv.util.getMin = function (graphdef, classification) {
  80. switch (classification) {
  81. case 'normal':
  82. return this.getMinValue(graphdef);
  83. case 'stepup':
  84. return this.getStepMinValue(graphdef);
  85. default:
  86. return 0;
  87. }
  88. }
  89. /**
  90. *
  91. */
  92. uv.util.getMinValue = function (graphdef) {
  93. return d3.min([0, d3.min(graphdef.categories.map(function (d) {
  94. return d3.min(graphdef.dataset[d].map(function (d) {
  95. return d.value;
  96. }));
  97. }))
  98. ]);
  99. };
  100. uv.util.getStepMinValue = function (graphdef) {
  101. var sumMap = graphdef.dataset[graphdef.categories[0]].map(function () {return 0; }),
  102. minMap = sumMap.map(function () { return 0; });
  103. graphdef.categories.map(function (d) {
  104. graphdef.dataset[d].map(function (d, i) {
  105. sumMap[i] += d.value;
  106. minMap[i] = d3.min([sumMap[i], minMap[i]]);
  107. });
  108. });
  109. return d3.min(minMap);
  110. }
  111. uv.util.getSumUpArray = function (graphdef) {
  112. var sumMap = graphdef.dataset[graphdef.categories[0]].map(function () {return 0; });
  113. graphdef.categories.map(function (d) {
  114. graphdef.dataset[d].map(function (d, i) {
  115. sumMap[i] += d.value;
  116. });
  117. });
  118. return sumMap;
  119. };
  120. uv.util.getPercentage = function (value, total) {
  121. return value* 100 / total;
  122. };
  123. uv.util.getDataArray = function (graphdef) {
  124. return graphdef.categories.map(function (d) { return graphdef.dataset[d]; });
  125. };
  126. uv.util.getTabularArray = function (graphdef) {
  127. var table = [], i, j, catlen, len, arr = [];
  128. for (i = 0, len = graphdef.dataset[graphdef.categories[0]].length; i < len; i = i + 1) {
  129. arr = [];
  130. arr.push(graphdef.dataset[graphdef.categories[0]][i].name);
  131. for (j = 0, catlen = graphdef.categories.length; j < catlen; j = j + 1) {
  132. arr.push(graphdef.dataset[graphdef.categories[j]][i].value);
  133. }
  134. table.push(arr);
  135. }
  136. return table;
  137. };
  138. uv.util.getLabelArray = function (graphdef, idx) {
  139. return graphdef.dataset[graphdef.categories[idx ? idx : 0]].map(function (d) { return d.name; });
  140. };
  141. uv.util.getCategoryArray = function (graphdef) {
  142. return graphdef.categories.map(function (d) { return d; });
  143. };
  144. uv.util.getCategoryData = function (graphdef, categories) {
  145. return categories.map(function (d) {
  146. return graphdef.dataset[d].map(function (d) {
  147. return d.value;
  148. });
  149. });
  150. };
  151. uv.util.transposeData = function (graphdef) {
  152. var dataset = {}, i, j, length, jlength, resetSum,
  153. name, label, value, categories = graphdef.dataset[graphdef.categories[0]].map(function (d) { return d.name; });
  154. for (i = 0, length = categories.length; i < length; i = i + 1) {
  155. dataset[categories[i]] = [];
  156. }
  157. for (i = 0, length = graphdef.categories.length; i < length; i = i + 1) {
  158. name = graphdef.categories[i];
  159. for (j = 0, jlength = graphdef.dataset[name].length; j < jlength; j = j + 1) {
  160. label = graphdef.dataset[name][j].name;
  161. value = graphdef.dataset[name][j].value;
  162. resetSum = graphdef.dataset[name][j].resetSum;
  163. dataset[label].push({ 'name' : name, 'value' : value, 'resetSum': resetSum });
  164. }
  165. }
  166. graphdef.categories = categories;
  167. graphdef.dataset = dataset;
  168. };
  169. uv.util.getPascalCasedName = function (name) {
  170. return name.substring(0, 1).toUpperCase() + name.substring(1);
  171. };
  172. uv.util.getColorBand = function (config, index) {
  173. var len = 0,
  174. palette = config.graph.palette || 'Default';
  175. if (config.graph.custompalette && config.graph.custompalette.length !== 0) {
  176. len = config.graph.custompalette.length;
  177. return config.graph.custompalette[index % len];
  178. } else {
  179. len = uv.palette[config.graph.palette].length;
  180. return uv.palette[config.graph.palette][index % len];
  181. }
  182. };
  183. /**
  184. * This function finds regular expressions other than Alphabets, Numbers,
  185. * "_" and "-" and replaces it with "-".
  186. * @param {string} name The string which needs to be formatted
  187. * @return {string} Returns the formatted String
  188. */
  189. uv.util.formatClassName = function(name){
  190. var returnName = name.trim().replace(/[^A-Za-z0-9_\-]/g,"-").toLowerCase();
  191. return returnName;
  192. };
  193. uv.util.svgToPng = function (downloadElmtRef, callback) {
  194. if (this.isCanvasSupported()) {
  195. var svgContent = d3.select(downloadElmtRef.frame.node().parentNode).html();
  196. var canvas = document.createElement('canvas');
  197. var ctx = canvas.getContext("2d");
  198. canvas.setAttribute('width',d3.select(downloadElmtRef.frame.node()).attr('width'));
  199. canvas.setAttribute('height',d3.select(downloadElmtRef.frame.node()).attr('height'));
  200. ctx.drawSvg(svgContent);
  201. canvas.toBlob(function(blob) {
  202. //saveAs(blob, "png_download"+Math.ceil(Math.random()*100000)+".png");
  203. var a = document.createElement("a");
  204. document.body.appendChild(a);
  205. a.style = "display: none";
  206. var url = window.URL.createObjectURL(blob);
  207. a.href = url;
  208. a.download = "png_download"+Math.ceil(Math.random()*100000)+".png";
  209. a.click();
  210. //window.URL.revokeObjectURL(url);
  211. }, "image/png");
  212. callback.call();
  213. } else {
  214. console.log('uvCharts: Download feature is not supported in this version of browser');
  215. }
  216. };
  217. uv.util.isDownloadSupported = function() {
  218. var canvas = document.createElement('canvas');
  219. var ctx = canvas.getContext("2d");
  220. return typeof(ctx.drawSvg) === 'function' && typeof(canvas.toBlob) === 'function';
  221. };
  222. uv.util.isCanvasSupported = function () {
  223. var elem = document.createElement('canvas');
  224. return !!(elem.getContext && elem.getContext('2d'));
  225. };
  226. /**
  227. * This function waits till the end of the transition and then call the callback
  228. * function which is passed as an argument
  229. * @param {transition} transition It's the current transition
  230. * @param {Function} callback function which is called at the end of
  231. * transition
  232. */
  233. uv.util.endAll = function (transition, callback){
  234. var n = 0;
  235. transition.each(function() { ++n; }).each("end", function() {
  236. if (!--n) {
  237. callback.apply(this, arguments);
  238. }
  239. });
  240. };
  241. /**
  242. * This function returns all class names of the element including new class name.
  243. * Useful in cases where we need to avoid over-writting of classes.
  244. * @param {} self this referring to svgElement
  245. * @param {String} name new class name to be added
  246. * @return {String} All class names as string.
  247. */
  248. uv.util.getClassName = function(self, name) {
  249. var formattedName = uv.util.formatClassName(name);
  250. if( !d3.select(self).attr('class')) {
  251. return formattedName;
  252. }
  253. if(d3.select(self).attr('class').split(' ').indexOf(formattedName) !== -1) {
  254. return d3.select(self).attr('class');
  255. }
  256. return d3.select(self).attr('class') + " " + formattedName;
  257. };
  258. /**
  259. * Returns specified value of given data object if integer, else returns formatted value considering precision.
  260. * @param self
  261. * @param {Number} d data object
  262. * @return {Strinig} value with precision
  263. */
  264. uv.util.getLabelValue = function(self, d) {
  265. // if(typeof d.value !== 'number') return null;
  266. if (self.config.label.formatter !== undefined) {
  267. return self.config.label.formatter(d.value);
  268. }
  269. var val = (d.value % 1 === 0) ? d.value : d.value.toFixed(self.config.label.precision);
  270. return self.config.label.prefix + String(val) + self.config.label.suffix;
  271. };
  272. uv.util._deepClone = function(target, src) {
  273. if(typeof src === 'object') {
  274. var isEmpty = true;
  275. for(var key in src) {
  276. isEmpty = false;
  277. if(src.hasOwnProperty(key)) {
  278. if(target === undefined) {
  279. target = Array.isArray(src) ? [] : {};
  280. }
  281. target[key] = uv.util._deepClone(target[key], src[key]);
  282. }
  283. }
  284. if(isEmpty){
  285. target = Array.isArray(src) ? [] : {};
  286. }
  287. } else {
  288. target = src;
  289. }
  290. return target;
  291. };
  292. /**
  293. * Extends properies of rest of the arguments to the first argument.
  294. * @param {Object} target
  295. * @param {Object} argument1
  296. * @param {Object} argumentN
  297. * @return target object
  298. */
  299. uv.util.extend = function() {
  300. if(arguments[0] === undefined || arguments[0] === null) {
  301. return arguments[0];
  302. }
  303. for(var i=1; i<arguments.length; i++) {
  304. for(var key in arguments[i]) {
  305. if(arguments[i].hasOwnProperty(key)) {
  306. arguments[0][key] = uv.util._deepClone(arguments[0][key], arguments[i][key]);
  307. }
  308. }
  309. }
  310. return arguments[0];
  311. };
  312. /**
  313. * This method returns tool tip text value if config option ‘show tooltiptext’ is true else returns empty string.
  314. * The text is as per the format specified using %c, %l, %v for category, label and values respectively.
  315. * Default format is - ‘%c [%l] : %v’
  316. * @param self
  317. * @param {String} category
  318. * @param {String} label
  319. * @param {String} value
  320. * @return {[String]} tool tip text with specified format.
  321. */
  322. uv.util.getTooltipText = function(self, category, label, value) {
  323. if(!self.config.tooltip.show) {
  324. return '';
  325. }
  326. var format = self.config.tooltip.format;
  327. if(format === '') {
  328. return category + ' [' + label + '] : ' + uv.util.getLabelValue(value);
  329. }
  330. return format.replace(/%c/gi, category).replace(/%l/gi, label).replace(/%v/gi, uv.util.getLabelValue(self, value));
  331. };
  332. uv.config = {
  333. graph: {
  334. palette: 'Default',
  335. bgcolor: '#FFFFFF',
  336. orientation: 'Horizontal',
  337. max: 0,
  338. min: 0,
  339. custompalette: [],
  340. opacity: 1,
  341. responsive: false,
  342. align: 'xMinYMin',
  343. meetOrSlice: 'meet'
  344. },
  345. meta: {
  346. position: '#uv-div',
  347. caption: '',
  348. subcaption: '',
  349. hlabel: '',
  350. vlabel: '',
  351. hsublabel: '',
  352. vsublabel: '',
  353. isDownloadable: false,
  354. downloadLabel: 'Download'
  355. },
  356. dimension: {
  357. width: 400,
  358. height: 400
  359. },
  360. margin: {
  361. top: 50,
  362. bottom: 150,
  363. left: 100,
  364. right: 100
  365. },
  366. frame: {
  367. bgcolor: '#FFFFFF'
  368. },
  369. axis: {
  370. ticks: 8,
  371. subticks: 2,
  372. padding: 5,
  373. minor: -10,
  374. strokecolor: '#000000',
  375. fontfamily: 'Arial',
  376. fontsize: '14',
  377. fontweight: 'bold',
  378. showticks: true,
  379. showsubticks: true,
  380. showtext: true,
  381. showhortext: true,
  382. showvertext: true,
  383. opacity: 0.1
  384. },
  385. label: {
  386. fontfamily: 'Arial',
  387. fontsize: '11',
  388. fontweight: 'normal',
  389. strokecolor: '#000000',
  390. showlabel: true,
  391. precision: 2,
  392. prefix: '',
  393. suffix: '',
  394. formatter: undefined
  395. },
  396. tooltip: {
  397. show: true,
  398. format: '%c [%l]: %v'
  399. },
  400. scale: {
  401. type: 'linear',
  402. ordinality: 0.2
  403. },
  404. bar: {
  405. strokecolor: 'none',
  406. fontfamily: 'Arial',
  407. fontsize: '10',
  408. fontweight: 'bold',
  409. textcolor: '#000'
  410. },
  411. line: {
  412. interpolation: 'linear',
  413. showcircles: true,
  414. circleradius: 3.5,
  415. circleopacity: 0.6,
  416. fontfamily: 'Arial',
  417. fontsize : '10',
  418. fontweight: 'bold',
  419. textcolor: '#000',
  420. strokewidth: 1.5,
  421. strokeopacity: 1
  422. },
  423. area: {
  424. interpolation: 'cardinal',
  425. offset: 'zero',
  426. opacity: 0.2
  427. },
  428. pie: {
  429. fontfamily: 'Arial',
  430. fontsize: '14',
  431. fontweight: 'normal',
  432. fontvariant: 'small-caps',
  433. fontfill: '#FFFFFF',
  434. strokecolor: '#FFFFFF',
  435. strokewidth: 1
  436. },
  437. donut: {
  438. fontfamily: 'Arial',
  439. fontsize: '14',
  440. fontweight: 'normal',
  441. fontvariant: 'small-caps',
  442. fontfill: '#000',
  443. factor: 0.4,
  444. strokecolor: '#FFFFFF',
  445. strokewidth: 1
  446. },
  447. caption: {
  448. fontfamily: 'Arial',
  449. fontsize: '14',
  450. fontweight: 'bold',
  451. fontvariant: 'small-caps',
  452. textdecoration: 'none',
  453. hovercolor: '#696969',
  454. strokecolor: '#0000FF',
  455. textanchor: 'middle',
  456. cursor: 'pointer'
  457. },
  458. subCaption: {
  459. fontfamily: 'Arial',
  460. fontsize: '9',
  461. fontweight: 'normal',
  462. fontvariant: 'normal',
  463. textdecoration: 'none',
  464. textanchor: 'middle'
  465. },
  466. legend: {
  467. position: 'bottom',
  468. fontfamily: 'Arial',
  469. fontsize: '11',
  470. fontweight: 'normal',
  471. color: "#000000",
  472. strokewidth: 0.15,
  473. textmargin: 15,
  474. symbolsize: 10,
  475. inactivecolor: '#DDD',
  476. legendstart: 0,
  477. legendtype: 'categories',
  478. showlegends: true,
  479. },
  480. effects: {
  481. hovercolor: '#FF0000',
  482. strokecolor: 'none',
  483. textcolor: '#000000',
  484. duration: 800,
  485. hover: 400,
  486. showhovertext: false
  487. }
  488. };
  489. uv.constants = {};
  490. uv.constants.classes = {
  491. uv : 'uv',
  492. pos : 'uv-div',
  493. frame : 'uv-frame',
  494. panel : 'uv-panel',
  495. bg : 'uv-chart-bg',
  496. chart : 'uv-chart',
  497. axes : 'uv-axes',
  498. legend : 'uv-legend',
  499. framebg : 'uv-frame-bg',
  500. horaxis : 'uv-hor-axis',
  501. veraxis : 'uv-ver-axis',
  502. caption : 'uv-caption',
  503. captiontext : 'uv-caption-text',
  504. subcaption : 'uv-subcaption',
  505. subcaptiontext : 'uv-subcaption-text',
  506. axeslabelgroup : 'uv-axes-label-group',
  507. axeslabel : 'uv-axes-label',
  508. axessublabel : 'uv-axes-sub-label',
  509. legendsign : 'uv-legend-sign',
  510. legendlabel : 'uv-legend-label',
  511. hoverbg : 'uv-hover-bg',
  512. arc : 'uv-arc-',
  513. areapath : 'uv-areapath-',
  514. linepath :'uv-linepath-',
  515. area : 'uv-area-',
  516. line : 'uv-line-',
  517. dot : 'uv-dot',
  518. chartdiv : 'uv-chart-div',
  519. circleticks : 'circle-ticks',
  520. download : 'uv-download-options'
  521. };
  522. uv.constants.downloads = {
  523. downloadLabel: 'Download'
  524. };
  525. uv.types = {};
  526. uv.addChart = function (type, functionName) {
  527. uv.types[type] = functionName;
  528. };
  529. uv.addChart('bar','BarGraph');
  530. uv.addChart('line','LineGraph');
  531. uv.addChart('stackedbar','StackedBarGraph');
  532. uv.addChart('stepupbar','StepUpBarGraph');
  533. uv.addChart('area','AreaGraph');
  534. uv.addChart('stackedarea','StackedAreaGraph');
  535. uv.addChart('percentbar','PercentBarGraph');
  536. uv.addChart('percentarea','PercentAreaGraph');
  537. uv.addChart('pie','PieGraph');
  538. uv.addChart('donut','DonutGraph');
  539. uv.addChart('waterfall','WaterfallGraph');
  540. uv.addChart('polararea','PolarAreaGraph');
  541. uv.chart = function (type, graphdef, config) {
  542. type = type.toLowerCase()
  543. if (uv.types[type] !== undefined) {
  544. return new uv[uv.types[type]](graphdef, config);
  545. }
  546. };
  547. uv.effects = {};
  548. uv.effects.bar = {};
  549. uv.effects.bar.mouseover = function (graph, idx) {
  550. var config = graph.config,
  551. category = graph.categories[idx],
  552. label = graph.labels[idx];
  553. var effect = function () {
  554. graph.frame.selectAll('rect.cr-' + uv.util.formatClassName(category))
  555. .transition().duration(config.effects.hover)
  556. .style('fill', config.effects.hovercolor)
  557. .style('stroke', config.effects.strokecolor);
  558. if(config.effects.showhovertext){
  559. graph.frame.selectAll('text.cr-' + uv.util.formatClassName(category))
  560. .transition().duration(config.effects.hover)
  561. .style('fill', config.effects.textcolor)
  562. .style('opacity', 1);
  563. }
  564. };
  565. if(config.legend.legendtype === 'categories'){
  566. graph.effects[category].mouseover = effect;
  567. }else{
  568. graph.effects[label].mouseover = effect;
  569. }
  570. return effect;
  571. };
  572. uv.effects.bar.mouseout = function (graph, idx, defColor) {
  573. var config = graph.config,
  574. category = graph.categories[idx],
  575. barColor = uv.util.getColorBand(graph.config, idx),
  576. textColor = defColor || uv.util.getColorBand(graph.config, idx),
  577. label = graph.labels[idx];
  578. var effect = function () {
  579. graph.frame.selectAll('rect.cr-' + uv.util.formatClassName(category))
  580. .transition().duration(config.effects.hover)
  581. .style('fill', barColor)
  582. .style('stroke', 'none');
  583. graph.frame.selectAll('text.cr-' + uv.util.formatClassName(category))
  584. .transition().duration(config.effects.hover)
  585. .style('fill', graph.config.label.showlabel ? textColor : 'none');
  586. };
  587. if(config.legend.legendtype === 'categories'){
  588. graph.effects[category].mouseout = effect;
  589. }else{
  590. graph.effects[label].mouseout = effect;
  591. }
  592. return effect;
  593. };
  594. uv.effects.area = {};
  595. uv.effects.area.mouseover = function (graph, idx) {
  596. var config = graph.config,
  597. category = graph.categories[idx];
  598. var effect = function () {
  599. graph.frame.selectAll('.cge-' + uv.util.formatClassName(category)).select('path.' + uv.constants.classes.area + uv.util.formatClassName(category))
  600. .transition().duration(config.effects.hover)
  601. .style('fill',config.effects.hovercolor);
  602. };
  603. graph.effects[category].mouseover = effect;
  604. return effect;
  605. };
  606. uv.effects.area.mouseout = function (graph, idx) {
  607. var config = graph.config,
  608. category = graph.categories[idx];
  609. var effect = function () {
  610. graph.frame.selectAll('.cge-'+ uv.util.formatClassName(category)).select('path.'+ uv.constants.classes.area + uv.util.formatClassName(category));
  611. graph.frame.selectAll('.cge-'+uv.util.formatClassName(category)).select('path.' + uv.constants.classes.area +uv.util.formatClassName(category))
  612. .transition().duration(config.effects.hover)
  613. .style('fill',uv.util.getColorBand(config,idx));
  614. };
  615. graph.effects[category].mouseout = effect;
  616. return effect;
  617. };
  618. uv.effects.line = {};
  619. uv.effects.line.mouseover = function (graph, idx) {
  620. var config = graph.config,
  621. category = graph.categories[idx];
  622. var effect = function () {
  623. graph.frame.selectAll('.cge-' + uv.util.formatClassName(category)).selectAll('circle')
  624. .transition().duration(config.effects.hover)
  625. .style('fill', config.effects.hovercolor)
  626. .style('fill-opacity', 1)
  627. .style('stroke', config.effects.hovercolor);
  628. graph.frame.selectAll('.cge-' + uv.util.formatClassName(category)).select('path')
  629. .transition().duration(config.effects.hover)
  630. .style('stroke', config.effects.hovercolor);
  631. if(config.effects.showhovertext){
  632. graph.frame.selectAll('.cge-' + uv.util.formatClassName(category)).selectAll('text')
  633. .transition().duration(config.effects.hover)
  634. .style('fill', config.effects.textcolor);
  635. }
  636. };
  637. graph.effects[category].mouseover = effect;
  638. return effect;
  639. };
  640. uv.effects.line.mouseout = function (graph, idx, defColor) {
  641. var config = graph.config,
  642. category = graph.categories[idx],
  643. color = defColor || uv.util.getColorBand(graph.config, idx);
  644. var effect = function () {
  645. graph.frame.selectAll('.cge-' + uv.util.formatClassName(category)).selectAll('circle')
  646. .transition().duration(config.effects.hover)
  647. .style('fill', color)
  648. .style('fill-opacity', 0.6)
  649. .style('stroke', '#fff');
  650. graph.frame.selectAll('.cge-' + uv.util.formatClassName(category)).select('path')
  651. .transition().duration(config.effects.hover)
  652. .style('stroke', color);
  653. graph.frame.selectAll('.cge-' + uv.util.formatClassName(category)).selectAll('text')
  654. .transition().duration(config.effects.hover)
  655. .style('fill', graph.config.label.showlabel ? color : 'none');
  656. };
  657. graph.effects[category].mouseout = effect;
  658. return effect;
  659. };
  660. uv.effects.caption = {};
  661. uv.effects.caption.mouseover = function (config) {
  662. return function () {
  663. d3.select(this.parentNode.parentNode).select('.' + uv.constants.classes.hoverbg)
  664. .transition().duration(config.effects.duration)
  665. .style('fill', config.caption.hovercolor);
  666. };
  667. };
  668. uv.effects.caption.mouseout = function (config) {
  669. return function () {
  670. d3.select(this.parentNode.parentNode).select('.' + uv.constants.classes.hoverbg)
  671. .transition().duration(config.effects.duration)
  672. .style('fill', config.graph.bgcolor);
  673. };
  674. };
  675. uv.effects.donut = {};
  676. uv.effects.donut.mouseover = function (center, arcfunc, config, d) {
  677. return function (d) {
  678. var dev = {
  679. x : arcfunc.centroid(d)[0] / 5,
  680. y : arcfunc.centroid(d)[1] / 5
  681. };
  682. d3.select(this.parentNode)
  683. .transition().duration(config.effects.duration)
  684. .attr('transform', 'translate(' + (center.x + dev.x) + ',' + (center.y + dev.y) + ')');
  685. };
  686. };
  687. uv.effects.donut.mouseout = function (center, config) {
  688. return function () {
  689. d3.select(this.parentNode)
  690. .transition().duration(config.effects.duration)
  691. .attr('transform', 'translate(' + center.x + ',' + center.y + ')');
  692. };
  693. };
  694. uv.effects.pie = {};
  695. uv.effects.pie.mouseover = function (graph ,center, arcfunc, config) {
  696. var effect = function (d) {
  697. var dev = {
  698. x : arcfunc.centroid(d)[0] / 5,
  699. y : arcfunc.centroid(d)[1] / 5
  700. };
  701. d3.select(this.parentNode)
  702. .transition().duration(config.effects.duration)
  703. .attr('transform', 'translate(' + (center.x + dev.x) + ',' + (center.y + dev.y) + ')');
  704. };
  705. return effect;
  706. };
  707. uv.effects.pie.mouseout = function (graph, center, config) {
  708. var effect = function () {
  709. d3.select(this.parentNode)
  710. .transition().duration(config.effects.duration)
  711. .attr('transform', 'translate(' + center.x + ',' + center.y + ')');
  712. };
  713. return effect;
  714. };
  715. uv.effects.legend = {};
  716. uv.effects.legend.mouseover = function (self, idx) {
  717. if(self.config.legend.legendtype === 'categories'){
  718. return self.effects.group[self.categories[idx]].mouseover;
  719. }else{
  720. return self.effects.group[self.labels[idx]].mouseover;
  721. }
  722. };
  723. uv.effects.legend.mouseout = function (self, idx) {
  724. if(self.config.legend.legendtype === 'categories'){
  725. return self.effects.group[self.categories[idx]].mouseout;
  726. }else{
  727. return self.effects.group[self.labels[idx]].mouseout;
  728. }
  729. };
  730. uv.effects.legend.click = function (i, ctx, graph) {
  731. var disabled = (d3.select(ctx).attr('disabled') === 'false') ? false : true;
  732. graph.toggleGraphGroup(i);
  733. d3.select(ctx).select('rect').style('fill', disabled ? uv.util.getColorBand(graph.config, i) : uv.config.legend.inactivecolor);
  734. d3.select(ctx).select('text').style('fill', disabled ? null : uv.config.legend.inactivecolor);
  735. d3.select(ctx).attr('disabled', disabled ? 'false' : 'true');
  736. };
  737. uv.palette = {
  738. 'Default': ['#00BBC9', '#EC63AB', '#AA8AE4', '#83CE44', '#ff8f25', '#009EAA', '#CA4F7F', '#9C70C0', '#6BAF3B'],
  739. 'OldDefault' : ['#7E6DA1', '#C2CF30', '#FF8900', '#FE2600', '#E3003F', '#8E1E5F', '#FE2AC2', '#CCF030', '#9900EC', '#3A1AA8', '#3932FE', '#3276FF', '#35B9F6', '#42BC6A', '#91E0CB'],
  740. 'Plain' : ['#B1EB68', '#B1B9B5', '#FFA16C', '#9B64E7', '#CEE113', '#2F9CFA', '#CA6877', '#EC3D8C', '#9CC66D', '#C73640', '#7D9532', '#B064DC' ],
  741. 'Android' : ['#33B5E5', '#AA66CC', '#99CC00', '#FFBB33', '#FF4444', '#0099CC', '#9933CC', '#669900', '#FF8800', '#CC0000'],
  742. 'Soft' : [ '#9ED8D2', '#FFD478', '#F16D9A', '#A8D59D', '#FDC180', '#F05133', '#EDED8A', '#F6A0A5', '#9F218B' ],
  743. 'Simple' : [ '#FF8181', '#FFB081', '#FFE081', '#EFFF81', '#BFFF81', '#90FF81', '#81FFA2', '#81FFD1', '#9681FF', '#C281FF', '#FF81DD' ],
  744. 'Egypt' : [ '#3A3E04','#784818','#FCFCA8','#C03C0C','#F0A830','#A8783C','#FCFCFC','#FCE460','#540C00','#C0C084','#3C303C','#1EA34A','#606C54','#F06048' ],
  745. 'Olive' : [ '#18240C','#3C6C18','#60A824','#90D824','#A8CC60','#789C60','#CCF030','#B4CCA8','#D8F078','#40190D','#E4F0CC' ],
  746. 'Candid' : [ '#AF5E14','#81400C','#E5785D','#FEBFBF','#A66363','#C7B752','#EFF1A7','#83ADB7','#528F98','#BCEDF5','#446B3D','#8BD96F','#E4FFB9' ],
  747. 'Sulphide' : [ '#594440','#0392A7','#FFC343','#E2492F','#007257','#B0BC4A','#2E5493','#7C2738','#FF538B','#A593A1','#EBBA86','#E2D9CA' ],
  748. 'Lint' : ['#A8A878','#F0D89C','#60909C','#242418','#E49C30','#54483C','#306090','#C06C00','#C0C0C0','#847854','#6C3C00','#9C3C3C','#183C60','#FCCC00','#840000','#FCFCFC']
  749. };
  750. /**
  751. * uv.Graph is an abstract class of sorts which serves as the base for all other graphs. Instances of it wouldnt be anything except bare bones needed to create a chart.
  752. * id - unique id corresponding to the graph, created using current timestamp {#TODO: needs improved logic}
  753. * graphdef - definition of the graph, containing data on which the visualization is built
  754. * config - configuration of the graph, affecting the visual styling of the graph
  755. * frame - <svg> element acting as the parent graph container
  756. * panel - <g> element containing everything else, making it easier to move all elements across the svg
  757. * bg - <rect> element which acts as the background for the graph
  758. * effects - object containing functions which cause the various interactions on the graph
  759. * labels - labels from the dataset provided
  760. * categories - categories from the dataset provided
  761. * axes - object containing axes related stuff: group, func, scale, axis, line, label
  762. *
  763. */
  764. uv.Graph = function (graphdef, config) {
  765. var self = this;
  766. self.id = uv.util.getUniqueId();
  767. self.graphdef = null;
  768. self.config = null;
  769. self.frame = null;
  770. self.panel = null;
  771. self.chart = null;
  772. self.bg = null;
  773. self.effects = {};
  774. self.axes = {
  775. hor: { group: null, scale : null, func: null, axis : null, line : null, label : null },
  776. ver: { group: null, scale : null, func: null, axis : null, line : null, label : null },
  777. meta: { min: null, max: null }
  778. };
  779. self.labels = null;
  780. self.categories = null;
  781. self.graphdef = graphdef;
  782. self.config = uv.util.extend({}, uv.config, config);
  783. return this;
  784. };
  785. /**
  786. * As the name suggests, this function initializes graph object construction based on the config and graphdef
  787. * @param {Object} graphdef Definition of the graph, take a look at constants.js for complete documentation
  788. * @param {Object} config Configuration of the graph, take a look at config.js for complete documentation
  789. * @return {Object} The graph object itself, to support method chaining
  790. *
  791. * #TODO: Remove dependency on jQuery/$
  792. */
  793. uv.Graph.prototype.init = function () {
  794. var self = this;
  795. self.max()
  796. .min()
  797. .position(self.config.meta.position || 'body')
  798. .setDimensions()
  799. .setFrame()
  800. .setPanel()
  801. .setBackground()
  802. .setCaption()
  803. .setSubCaption()
  804. .setMetadata()
  805. .setHorizontalAxis()
  806. .setVerticalAxis()
  807. .setEffectsObject();
  808. if(self.config.meta.isDownloadable){
  809. self.setDownloadOptions();
  810. }
  811. if(self.config.legend.showlegends){
  812. self.setLegend();
  813. }
  814. return self;
  815. };
  816. /**
  817. * Sets the dimensions of the graphs, namely height, width and margins: left, right, top and bottom
  818. * @return {Object} The graph object itself, to support method chaining
  819. */
  820. uv.Graph.prototype.setDimensions = function () {
  821. var self = this;
  822. self.height(self.config.dimension.height)
  823. .width(self.config.dimension.width)
  824. .top(self.config.margin.top)
  825. .bottom(self.config.margin.bottom)
  826. .left(self.config.margin.left)
  827. .right(self.config.margin.right);
  828. return this;
  829. };
  830. /**
  831. * This function downloads the graph in png format.
  832. *
  833. */
  834. uv.Graph.prototype.setDownloadOptions = function () {
  835. if (uv.util.isDownloadSupported()) {
  836. var self = this;
  837. self.download = self.panel.append('g').classed(uv.constants.classes.download, true);
  838. self.download.append('text').classed(uv.constants.classes.download, true)
  839. .text(self.config.meta.downloadLabel)
  840. .attr('y', -self.config.margin.top / 2)
  841. .attr('x', self.config.dimension.width-25)
  842. .attr('text-anchor', self.config.caption.textanchor)
  843. .style('font-family', self.config.caption.fontfamily)
  844. .style('font-size', '12')
  845. .style('cursor', self.config.caption.cursor)
  846. .style('stroke', self.config.caption.strokecolor)
  847. .style('text-decoration', 'underline')
  848. .on('mouseover', function() {
  849. var dnldBtn = d3.select(this);
  850. dnldBtn.style('color','#0000FF');
  851. })
  852. .on('mouseout', function() {
  853. var dnldBtn = d3.select(this);
  854. dnldBtn.style('color','#8D8D8D');
  855. })
  856. .on('click', function () {
  857. var dnldBtn = d3.select(this);
  858. dnldBtn.style('display','none');
  859. uv.util.svgToPng(self, function() {
  860. dnldBtn.style('display',null);
  861. });
  862. });
  863. }
  864. };
  865. /**
  866. * Sets the main <svg> element which contains rest of the graph elements
  867. * @return {Object} The graph object itself, to support method chaining
  868. */
  869. uv.Graph.prototype.setFrame = function () {
  870. var self = this;
  871. if (!self.frame) {
  872. self.frame = d3.select(self.position() || 'body').append('div')
  873. .classed(uv.constants.classes.chartdiv, true)
  874. .style('display','inline-block')
  875. .style('width', '100%')
  876. .style('height', '100%')
  877. .append('svg');
  878. }
  879. self.frame.attr('id', uv.constants.classes.uv + '-' + self.id)
  880. .classed(uv.constants.classes.frame, true);
  881. if (self.config.graph.responsive === true) {
  882. self.frame.attr('width', '100%')
  883. .attr('height', '100%')
  884. .attr('preserveAspectRatio', self.config.graph.align + ' ' + self.config.graph.meetOrSlice)
  885. .attr('viewBox', '0 0 ' + (self.width() + self.left() + self.right()) + ' ' + (self.height() + self.top() + self.bottom()));
  886. } else {
  887. self.frame.attr('width', self.width() + self.left() + self.right())
  888. .attr('height', self.height() + self.top() + self.bottom());
  889. }
  890. self.frame.append('rect').classed(uv.constants.classes.framebg, true)
  891. .attr('width', self.width() + self.left() + self.right())
  892. .attr('height', self.height() + self.top() + self.bottom())
  893. .style('fill', self.config.frame.bgcolor);
  894. return this;
  895. };
  896. /**
  897. * Sets the <g> element which serves as the base position for the graph elements
  898. * @return {Object} The graph object itself, to support method chaining
  899. */
  900. uv.Graph.prototype.setPanel = function () {
  901. var self = this;
  902. if (!self.panel) {
  903. self.panel = self.frame.append('g');
  904. }
  905. self.panel.attr('id', uv.constants.classes.panel + '-' + self.id)
  906. .classed(uv.constants.classes.panel, true)
  907. .attr('transform', 'translate(' + self.left() + ',' + self.top() + ')');
  908. return this;
  909. };
  910. /**
  911. * Sets the <rect> element which serves as the background for the chart
  912. * @param {String} color Color code for the background, set to config value if not specified
  913. * @return {Object} The graph object itself, to support method chaining
  914. */
  915. uv.Graph.prototype.setBackground = function (color) {
  916. var self = this;
  917. if (!self.bg) {
  918. self.bg = self.panel.append('rect').classed(uv.constants.classes.bg, true)
  919. .attr('height', self.height())
  920. .attr('width', self.width());
  921. }
  922. self.bg.style('fill', color || self.config.graph.bgcolor);
  923. self.chart = self.panel.append('g').classed(uv.constants.classes.chart, true)
  924. .style('opacity', self.config.graph.opacity);
  925. return this;
  926. };
  927. /**
  928. * Sets the caption for the graph
  929. * @return {Object} The graph object itself, to support method chaining
  930. */
  931. uv.Graph.prototype.setCaption = function () {
  932. var self = this;
  933. self.caption = self.panel.append('g').classed(uv.constants.classes.caption, true);
  934. self.caption.append('text').classed(uv.constants.classes.captiontext, true)
  935. .text(self.config.meta.caption)
  936. .attr('y', -self.config.margin.top / 2)
  937. .attr('x', self.config.dimension.width / 2)
  938. .attr('text-anchor', self.config.caption.textanchor)
  939. .style('font-family', self.config.caption.fontfamily)
  940. .style('font-size', self.config.caption.fontsize)
  941. .style('font-weight', self.config.caption.fontweight)
  942. .style('font-variant', self.config.caption.fontvariant)
  943. .style('text-decoration', self.config.caption.textdecoration)
  944. .on('mouseover', uv.effects.caption.mouseover(self.config))
  945. .on('mouseout', uv.effects.caption.mouseout(self.config));
  946. return this;
  947. };
  948. /**
  949. * Sets the subcaption for the graph
  950. * @return {Object} The graph object itself, to support method chaining
  951. */
  952. uv.Graph.prototype.setSubCaption = function () {
  953. var self = this;
  954. self.subCaption = self.panel.append('g').classed(uv.constants.classes.subcaption, true);
  955. self.subCaption.append('text').classed(uv.constants.classes.subcaptiontext, true)
  956. .text(self.config.meta.subcaption)
  957. .attr('y', -self.config.margin.top / 2 + 1*self.config.caption.fontsize)
  958. .attr('x', self.config.dimension.width / 2)
  959. .attr('text-anchor', self.config.caption.textanchor)
  960. .style('font-family', self.config.subCaption.fontfamily)
  961. .style('font-size', self.config.subCaption.fontsize)
  962. .style('font-weight', self.config.subCaption.fontweight)
  963. .style('font-variant', self.config.subCaption.fontvariant)
  964. .style('text-decoration', self.config.subCaption.textdecoration);
  965. return this;
  966. };
  967. /**
  968. * Sets the metadata for the graph, this includes the labels and the categories
  969. * @return {Object} The graph object itself, to support method chaining
  970. */
  971. uv.Graph.prototype.setMetadata = function () {
  972. var self = this;
  973. self.labels = uv.util.getLabelArray(self.graphdef);
  974. self.categories = uv.util.getCategoryArray(self.graphdef);
  975. return this;
  976. };
  977. /**
  978. * Sets the Horizontal Axis functions but doesnt render it yet
  979. * return {Object} The graph object itself, to support method chaining
  980. */
  981. uv.Graph.prototype.setHorizontalAxis = function () {
  982. var self = this;
  983. var graphdef = self.graphdef;
  984. if (!self.axes.hor.group) {
  985. self.axes.hor.group = self.panel.append('g').classed(uv.constants.classes.horaxis, true)
  986. .attr('transform', 'translate(0,' + self.height() + ')')
  987. .style('shape-rendering','crispEdges');
  988. }
  989. if (self.config.graph.orientation === 'Horizontal') {
  990. self.axes.hor.scale = d3.scale[self.config.scale.type]()
  991. .domain([self.config.scale.type === 'log' ? 1: self.min(), self.max()])
  992. .range([0, self.width()]);
  993. if (self.axes.hor.scale.nice) {
  994. self.axes.hor.scale.nice();
  995. }
  996. if(!self.config.axis.showsubticks){
  997. self.config.axis.subticks = 0;
  998. }
  999. self.axes.hor.func = d3.svg.axis()
  1000. .scale(self.axes.hor.scale)
  1001. .ticks(self.config.axis.ticks)
  1002. .tickSize(-self.height(), self.config.axis.minor, 0)
  1003. .tickPadding(self.config.axis.padding)
  1004. .tickSubdivide(self.config.axis.subticks)
  1005. .orient('bottom');
  1006. } else {
  1007. self.axes.hor.scale = d3.scale.ordinal()
  1008. .rangeRoundBands([0, self.width()], self.config.scale.ordinality);
  1009. self.axes.hor.func = d3.svg.axis()
  1010. .scale(self.axes.hor.scale)
  1011. .tickPadding(self.config.axis.padding)
  1012. .orient('bottom');
  1013. if(!self.config.axis.showtext || !self.config.axis.showhortext) {
  1014. self.axes.hor.func.tickSize(0);
  1015. }
  1016. }
  1017. if(!self.config.axis.showtext || !self.config.axis.showhortext) {
  1018. self.axes.hor.func.tickFormat(function (d) { return ''; });
  1019. }
  1020. return this;
  1021. };
  1022. /**
  1023. * Sets the Vertical axis functions, but doesnt render it yet
  1024. * @return {Object} The graph object itself, to support method chaining
  1025. */
  1026. uv.Graph.prototype.setVerticalAxis = function () {
  1027. var self = this;
  1028. var graphdef = self.graphdef;
  1029. if (!self.axes.ver.group) {
  1030. self.axes.ver.group = self.panel.append('g').classed(uv.constants.classes.veraxis, true)
  1031. .style('shape-rendering','crispEdges');
  1032. }
  1033. if (self.config.graph.orientation === 'Vertical') {
  1034. self.axes.ver.scale = d3.scale[self.config.scale.type]()
  1035. .domain([self.max(), self.config.scale.type === 'log' ? 1 : self.min()])
  1036. .range([0, self.height()]);
  1037. if (self.axes.ver.scale.nice) {
  1038. self.axes.ver.scale.nice();
  1039. }
  1040. if(!self.config.axis.showsubticks){
  1041. self.config.axis.subticks = 0;
  1042. }
  1043. self.axes.ver.func = d3.svg.axis()
  1044. .scale(self.axes.ver.scale)
  1045. .ticks(self.config.axis.ticks)
  1046. .tickSize(-self.width(), self.config.axis.minor, 0)
  1047. .tickPadding(self.config.axis.padding)
  1048. .tickSubdivide(self.config.axis.subticks)
  1049. .orient('left');
  1050. } else {
  1051. self.axes.ver.scale = d3.scale.ordinal()
  1052. .rangeRoundBands([0, self.height()], self.config.scale.ordinality);
  1053. self.axes.ver.func = d3.svg.axis()
  1054. .scale(self.axes.ver.scale)
  1055. .tickPadding(self.config.axis.padding)
  1056. .orient('left');
  1057. if(!self.config.axis.showtext || !self.config.axis.showvertext){
  1058. self.axes.ver.func.tickSize(0);
  1059. }
  1060. }
  1061. if(!self.config.axis.showtext || !self.config.axis.showvertext) {
  1062. self.axes.ver.func.tickFormat(function (d) { return ''; });
  1063. }
  1064. return this;
  1065. };
  1066. /**
  1067. * Creates placeholders for functions which cause the various animations across the graph to be able invoke it from other places
  1068. * @return {Object} The graph object itself, to support method chaining
  1069. */
  1070. uv.Graph.prototype.setEffectsObject = function () {
  1071. var self = this;
  1072. var effectArray = (self.config.legend.legendtype === 'categories') ? self.categories : self.labels;
  1073. for (var i = 0; i < effectArray.length ; i++) {
  1074. self.effects[effectArray[i]] = {};
  1075. }
  1076. return self;
  1077. };
  1078. /**
  1079. * Draws the horizontal axis within the frame based on the orientation and functions already created
  1080. * @return {Object} The graph object itself, to support method chaining
  1081. */
  1082. uv.Graph.prototype.drawHorizontalAxis = function () {
  1083. var self = this;
  1084. self.axes.hor.axis = self.axes.hor.group.append('g')
  1085. .style('font-family', self.config.label.fontfamily)
  1086. .style('font-size', self.config.label.fontsize)
  1087. .style('font-weight', self.config.label.fontweight)
  1088. .call(self.axes.hor.func);
  1089. if (self.config.axis.showticks) {
  1090. self.axes.hor.axis.selectAll('line').style('stroke', self.config.axis.strokecolor)
  1091. .style('opacity', self.config.axis.opacity);
  1092. }
  1093. self.axes.hor.axis.selectAll('path').style('fill','none');
  1094. self.axes.hor.line = self.panel.append('line')
  1095. .classed(uv.constants.classes.horaxis, true)
  1096. .attr('y1', self.config.graph.orientation === 'Horizontal' ? self.height() : self.axes.ver.scale(0))
  1097. .attr('y2', self.config.graph.orientation === 'Horizontal' ? self.height() : self.axes.ver.scale(0))
  1098. .attr('x1', '0')
  1099. .attr('x2', self.width())
  1100. .style('stroke', self.config.axis.strokecolor);
  1101. self.axes.hor.label = self.axes.hor.group.append('g')
  1102. .classed(uv.constants.classes.axeslabelgroup, true)
  1103. .attr('transform', 'translate(' + self.width()/2 + ',' + (1*self.config.margin.bottom/4 + 1*self.config.label.fontsize) + ')');
  1104. self.axes.hor.label.append('text')
  1105. .attr('display','block')
  1106. .classed(uv.constants.classes.axeslabel, true).classed('cal', true)
  1107. .attr('text-anchor','middle')
  1108. .style('font-size', self.config.axis.fontsize)
  1109. .style('font-family', self.config.axis.fontfamily)
  1110. .text(self.config.meta.hlabel);
  1111. self.axes.hor.label.append('text')
  1112. .attr('display','block')
  1113. .attr('y', 1*self.config.axis.fontsize)
  1114. .attr(uv.constants.classes.axessublabel, true).classed('casl', true)
  1115. .attr('text-anchor','middle')
  1116. .style('font-size', self.config.axis.fontsize - 2)
  1117. .style('font-family', self.config.axis.fontfamily)
  1118. .text(self.config.meta.hsublabel);
  1119. return this;
  1120. };
  1121. /**
  1122. * Draws the vertical axis within the frame based on the orientation and functions already created
  1123. * @return {Object} The graph object itself, to support method chaining
  1124. */
  1125. uv.Graph.prototype.drawVerticalAxis = function () {
  1126. var self = this;
  1127. self.axes.ver.axis = self.axes.ver.group.append('g')
  1128. .classed(uv.constants.classes.axes, true)
  1129. .style('font-family', self.config.label.fontfamily)
  1130. .style('font-size', self.config.label.fontsize)
  1131. .style('font-weight', self.config.label.fontweight)
  1132. .call(self.axes.ver.func);
  1133. if (self.config.axis.showticks) {
  1134. self.axes.ver.axis.selectAll('line').style('stroke', self.config.axis.strokecolor)
  1135. .style('opacity', self.config.axis.opacity);
  1136. }
  1137. self.axes.ver.axis.selectAll('path').style('fill','none');
  1138. self.axes.ver.line = self.panel.append('line')
  1139. .classed(uv.constants.classes.veraxis, true)
  1140. .attr('x1', self.config.graph.orientation === 'Horizontal'? self.axes.hor.scale(0): 0)
  1141. .attr('x2', self.config.graph.orientation === 'Horizontal'? self.axes.hor.scale(0): 0)
  1142. .attr('y1', 0)
  1143. .attr('y2', self.height())
  1144. .style('stroke', self.config.axis.strokecolor);
  1145. self.axes.ver.label = self.axes.ver.group.append('g')
  1146. .attr('transform', 'translate(' + -4*self.config.margin.left/5 + ',' + self.height()/2 + ')rotate(270)');
  1147. self.axes.ver.label.append('text').classed(uv.constants.classes.axeslabel, true)
  1148. .attr('text-anchor', 'middle')
  1149. .classed('cal', true)
  1150. .style('font-family', self.config.axis.fontfamily)
  1151. .style('font-size', self.config.axis.fontsize)
  1152. .text(self.config.meta.vlabel);
  1153. self.axes.ver.label.append('text').classed(uv.constants.classes.axessublabel, true)
  1154. .attr('text-anchor', 'middle')
  1155. .attr('y', +self.config.axis.fontsize)
  1156. .classed('casl', true)
  1157. .style('font-family', self.config.axis.fontfamily)
  1158. .style('font-size', self.config.axis.fontsize - 2)
  1159. .text(self.config.meta.vsublabel);
  1160. return this;
  1161. };
  1162. /**
  1163. * Sets the legend and related interactions for the graph based on the configuration
  1164. * @return {Object} The graph object itself, to support method chaining
  1165. */
  1166. uv.Graph.prototype.setLegend = function () {
  1167. var self = this;
  1168. var legendgroup = self.panel.append('g').classed(uv.constants.classes.legend, true)
  1169. .attr('transform', function(d, i){
  1170. if(self.config.legend.position === 'right'){
  1171. return 'translate(' + self.width() + ', 10)';
  1172. }else if(self.config.legend.position === 'bottom'){
  1173. var pos = self.height() + self.config.margin.bottom/2 + Number(self.config.axis.fontsize);
  1174. return 'translate(0, ' + pos + ')';
  1175. }
  1176. });
  1177. self.legends = legendgroup.selectAll('g').data(
  1178. (self.config.legend.legendtype === 'categories') ? self.categories:self.labels
  1179. );
  1180. self.legends.enter().append('g')
  1181. .attr('transform', function (d, i) {
  1182. if(self.config.legend.position === 'right'){
  1183. return 'translate(10,' + 10* (2* i - 1) + ')';
  1184. }else if(self.config.legend.position === 'bottom'){
  1185. var hPos = 100*i - self.config.dimension.width*self.config.legend.legendstart;
  1186. var vPos = 20*self.config.legend.legendstart;
  1187. if(hPos >= self.config.dimension.width){
  1188. self.config.legend.legendstart = self.config.legend.legendstart + 1;
  1189. hPos = 100*i - self.config.dimension.width*self.config.legend.legendstart;
  1190. vPos = 20*self.config.legend.legendstart;
  1191. }
  1192. return 'translate(' + hPos + ',' + vPos + ')';
  1193. }
  1194. })
  1195. .attr('class', function (d, i) {
  1196. var className = (self.config.legend.legendtype === 'categories') ? self.categories[i]:self.labels[i];
  1197. return uv.util.getClassName(this, 'cl-' + className);
  1198. })
  1199. .attr('disabled', 'false')
  1200. .on('mouseover', function (d, i) {
  1201. if (self.effects[d].mouseover && typeof self.effects[d].mouseover === 'function') {
  1202. self.effects[d].mouseover();
  1203. }
  1204. })
  1205. .on('mouseout', function (d, i) {
  1206. if (self.effects[d].mouseout && typeof self.effects[d].mouseout === 'function') {
  1207. self.effects[d].mouseout();
  1208. }
  1209. })
  1210. .on('click', function (d, i) {
  1211. uv.effects.legend.click(i, this, self);
  1212. });
  1213. self.legends.append('rect').classed(uv.constants.classes.legendsign, true)
  1214. .attr('height', self.config.legend.symbolsize)
  1215. .attr('width', self.config.legend.symbolsize)
  1216. .style('fill', function (d, i) { return uv.util.getColorBand(self.config, i); })
  1217. .style('stroke', 'none');
  1218. self.legends.append('text').classed(uv.constants.classes.legendlabel, true)
  1219. .text(function (d, i) { return (self.config.legend.legendtype === 'categories') ? self.categories[i]:self.labels[i]; })
  1220. .attr('dx', self.config.legend.textmargin)
  1221. .attr('dy', '.71em')
  1222. .attr('text-anchor', 'start')
  1223. .style('stroke', self.config.legend.color)
  1224. .style('fill', self.config.legend.color)
  1225. .style('stroke-width', self.config.legend.strokewidth)
  1226. .style('font-family', self.config.legend.fontfamily)
  1227. .style('font-size', self.config.legend.fontsize)
  1228. .style('font-weight', self.config.legend.fontweight);
  1229. return this;
  1230. };
  1231. /**
  1232. * Finalizes stuff related to graph, used in conjuction with init to setup all the generic graph stuff
  1233. * @param {Boolean} isLoggable Specifies whether the graph object should be logged or not, for debug purpose only
  1234. * @return {Object} The graph object itself, to support method chaining
  1235. */
  1236. uv.Graph.prototype.finalize = function (isLoggable) {
  1237. var self = this;
  1238. self.drawHorizontalAxis()
  1239. .drawVerticalAxis();
  1240. // .setLegend();
  1241. // Cursor for text is unset from text to normal
  1242. self.frame.selectAll('text').style('cursor', 'default');
  1243. //Log Graph object if flag set to truthy value
  1244. if (isLoggable) {
  1245. console.log(self);
  1246. }
  1247. return this;
  1248. };
  1249. /*
  1250. * Functions to remove individual elements of an graph
  1251. */
  1252. /**
  1253. * Removes the entire graph object
  1254. * @return {Object} The graph object itself, to support method chaining
  1255. */
  1256. uv.Graph.prototype.remove = function () {
  1257. this.frame.remove();
  1258. return this;
  1259. };
  1260. /**
  1261. * Removes the caption component of the graph
  1262. * @return {Object} The graph object itself, to support method chaining
  1263. */
  1264. uv.Graph.prototype.removeCaption = function () {
  1265. this.caption.remove();
  1266. return this;
  1267. };
  1268. /**
  1269. * Removes the legend component of the graph
  1270. * @return {Object} The graph object itself, to support method chaining
  1271. */
  1272. uv.Graph.prototype.removeLegend = function () {
  1273. if (this.legends[0]) {
  1274. this.legends[0].parentNode.remove();
  1275. }
  1276. return this;
  1277. };
  1278. uv.Graph.prototype.removePanel = function () {
  1279. this.panel.remove();
  1280. return this;
  1281. };
  1282. uv.Graph.prototype.removeHorAxis = function () {
  1283. this.panel.selectAll('g.' + uv.constants.classes.horaxis + " >*").remove();
  1284. this.panel.selectAll('line.' + uv.constants.classes.horaxis).remove();
  1285. return this;
  1286. };
  1287. uv.Graph.prototype.removeVerAxis = function () {
  1288. this.panel.selectAll('g.' + uv.constants.classes.veraxis + " >*").remove();
  1289. this.panel.selectAll('line.' + uv.constants.classes.veraxis).remove();
  1290. return this;
  1291. };
  1292. /*
  1293. * Setters and getters for various common properties of the graph
  1294. */
  1295. uv.Graph.prototype.width = function (w) {
  1296. if (w) {
  1297. this.config.dimension.width = w;
  1298. return this;
  1299. }
  1300. return this.config.dimension.width;
  1301. };
  1302. uv.Graph.prototype.height = function (h) {
  1303. if (h) {
  1304. this.config.dimension.height = h;
  1305. return this;
  1306. }
  1307. return this.config.dimension.height;
  1308. };
  1309. uv.Graph.prototype.top = function (t) {
  1310. if (t) {
  1311. this.config.margin.top = t;
  1312. return this;
  1313. }
  1314. return this.config.margin.top;
  1315. };
  1316. uv.Graph.prototype.bottom = function (b) {
  1317. if (b) {
  1318. this.config.margin.bottom = b;
  1319. return this;
  1320. }
  1321. return this.config.margin.bottom;
  1322. };
  1323. uv.Graph.prototype.left = function (l) {
  1324. if (l) {
  1325. this.config.margin.left = l;
  1326. return this;
  1327. }
  1328. return this.config.margin.left;
  1329. };
  1330. uv.Graph.prototype.right = function (r) {
  1331. if (r) {
  1332. this.config.margin.right = r;
  1333. return this;
  1334. }
  1335. return this.config.margin.right;
  1336. };
  1337. uv.Graph.prototype.position = function (pos) {
  1338. if (pos) {
  1339. this.config.meta.position = pos;
  1340. return this;
  1341. }
  1342. return this.config.meta.position;
  1343. };
  1344. uv.Graph.prototype.caption = function (caption) {
  1345. if (caption) {
  1346. this.config.meta.caption = caption;
  1347. return this;
  1348. }
  1349. return this.config.meta.caption;
  1350. };
  1351. uv.Graph.prototype.subCaption = function (subCaption) {
  1352. if (subCaption) {
  1353. this.config.meta.subCaption = subCaption;
  1354. return this;
  1355. }
  1356. return this.config.meta.caption;
  1357. };
  1358. uv.Graph.prototype.isDownloadable = function (isDownload) {
  1359. if (isDownload) {
  1360. this.config.meta.isDownload = isDownload;
  1361. return this;
  1362. }
  1363. return this.config.meta.isDownload;
  1364. };
  1365. uv.Graph.prototype.max = function () {
  1366. if (this.axes.meta.max !== null) {
  1367. return this.axes.meta.max;
  1368. }
  1369. this.axes.meta.max = uv.util.getMax(this.graphdef, this.graphdef.stepup);
  1370. return this;
  1371. }
  1372. uv.Graph.prototype.min = function () {
  1373. if (this.axes.meta.min !== null) {
  1374. return this.axes.meta.min;
  1375. }
  1376. this.axes.meta.min = uv.util.getMin(this.graphdef, this.graphdef.stepup);
  1377. return this;
  1378. }
  1379. /* Additional Graph functions*/
  1380. uv.Graph.prototype.toggleGraphGroup = function (i) {
  1381. var self = this, category = self.categories[i],
  1382. state = self.frame.select('g.cge-' + uv.util.formatClassName(category)).style('display'),
  1383. color = uv.util.getColorBand(self.config, i);
  1384. self.frame.selectAll('g.cge-' + uv.util.formatClassName(category)).style('display', (state === 'none')? null : 'none');
  1385. return this;
  1386. };
  1387. uv.AreaGraph = function (graphdef, config) {
  1388. var self = this;
  1389. uv.Graph.call(self, graphdef, config).setDefaults().init();
  1390. self.areagroups = [];
  1391. self.dataset = uv.util.getDataArray(self.graphdef);
  1392. var areagroup, areapath, areafunc, idx, len,
  1393. domainData = self.graphdef.dataset[self.graphdef.categories[0]];
  1394. self.axes[self.config.graph.orientation === 'Horizontal' ? 'ver' : 'hor'].scale.domain(domainData.map(function (d) { return d.name; }));
  1395. for (idx = 0, len = self.dataset.length; idx < len; idx = idx + 1) {
  1396. areapath = self.chart.append('g').classed('cg-' + uv.util.formatClassName(self.categories[idx]), true)
  1397. .append('g').classed('cge-' + uv.util.formatClassName(self.categories[idx]), true).datum(self.dataset[idx]);
  1398. areagroup = { path: areapath, linefunc: undefined, areafunc: undefined, line: undefined, area: undefined };
  1399. self['draw' + self.config.graph.orientation + 'Area'](areagroup, idx);
  1400. self.areagroups.push(areagroup);
  1401. }
  1402. self.finalize();
  1403. };
  1404. uv.AreaGraph.prototype = uv.util.inherits(uv.Graph);
  1405. uv.AreaGraph.prototype.setDefaults = function () {
  1406. var self = this;
  1407. self.graphdef.stepup = 'normal';
  1408. return this;
  1409. };
  1410. uv.AreaGraph.prototype.drawHorizontalArea = function (areagroup, idx) {
  1411. var self = this,
  1412. color = uv.util.getColorBand(self.config, idx);
  1413. self.axes.ver.scale.rangePoints([0, self.height()]);
  1414. areagroup.linefunc = d3.svg.line()
  1415. .x(function (d) { return self.axes.hor.scale(d.value); })
  1416. .y(function (d) { return self.axes.ver.scale(d.name) + self.axes.ver.scale.rangeBand() / 2; })
  1417. .interpolate(self.config.area.interpolation);
  1418. areagroup.areafunc = d3.svg.area()
  1419. .x0(self.axes.hor.scale(0))
  1420. .x1(areagroup.linefunc.x())
  1421. .y(areagroup.linefunc.y())
  1422. .interpolate(self.config.area.interpolation);
  1423. areagroup.area = areagroup.path.append('svg:path')
  1424. .classed(uv.constants.classes.areapath + idx, true)
  1425. .attr('d', areagroup.areafunc)
  1426. .style('opacity', self.config.area.opacity)
  1427. .style('-moz-opacity', self.config.area.opacity)
  1428. .style('fill', color);
  1429. areagroup.line = areagroup.path.append('svg:path')
  1430. .classed(uv.constants.classes.linepath + idx, true)
  1431. .attr('d', areagroup.linefunc)
  1432. .style('stroke', 'white')
  1433. .style('fill', 'none');
  1434. areagroup.path.selectAll('.' + uv.constants.classes.dot)
  1435. .data(self.dataset[idx])
  1436. .enter().append('circle')
  1437. .classed(uv.constants.classes.dot, true)
  1438. .attr('cx', areagroup.linefunc.x())
  1439. .attr('cy', areagroup.linefunc.y())
  1440. .attr('r', 3.5)
  1441. .style('fill', 'white');
  1442. };
  1443. uv.AreaGraph.prototype.drawVerticalArea = function (areagroup, idx) {
  1444. var self = this,
  1445. color = uv.util.getColorBand(self.config, idx);
  1446. self.axes.hor.scale.rangePoints([0, self.width()]);
  1447. areagroup.linefunc = d3.svg.line()
  1448. .x(function (d) { return self.axes.hor.scale(d.name) + self.axes.hor.scale.rangeBand() / 2; })
  1449. .y(function (d) { return self.axes.ver.scale(d.value); })
  1450. .interpolate(self.config.area.interpolation);
  1451. areagroup.areafunc = d3.svg.area()
  1452. .x(areagroup.linefunc.x())
  1453. .y0(areagroup.linefunc.y())
  1454. .y1(self.axes.ver.scale(0))
  1455. .interpolate(self.config.area.interpolation);
  1456. areagroup.area = areagroup.path.append('svg:path')
  1457. .classed(uv.constants.classes.areapath + idx, true)
  1458. .attr('d', areagroup.areafunc)
  1459. .style('opacity', self.config.area.opacity)
  1460. .style('-moz-opacity', self.config.area.opacity)
  1461. .style('fill', color);
  1462. areagroup.line = areagroup.path.append('svg:path')
  1463. .classed(uv.constants.classes.linepath + idx, true)
  1464. .attr('d', areagroup.linefunc)
  1465. .style('stroke', 'white')
  1466. .style('fill', 'none');
  1467. areagroup.path.selectAll('.' + uv.constants.classes.dot)
  1468. .data(self.dataset[idx])
  1469. .enter().append('circle')
  1470. .classed(uv.constants.classes.dot, true)
  1471. .attr('cx', areagroup.linefunc.x())
  1472. .attr('cy', areagroup.linefunc.y())
  1473. .attr('r', 3.5)
  1474. .style('fill', 'white');
  1475. };
  1476. /**
  1477. * A normal 2d bar chart capable of being rendered in horizontal and vertical manner
  1478. * @param {Object} graphdef Definition of the graph being rendered
  1479. * @param {Object} config Configuration of the graph being rendered
  1480. */
  1481. uv.BarGraph = function (graphdef, config) {
  1482. var self = this;
  1483. uv.Graph.call(self, graphdef, config).setDefaults().init();
  1484. self.bargroups = {};
  1485. self.axes[self.config.graph.orientation === 'Horizontal' ? 'ver' : 'hor'].scale.domain(self.labels);
  1486. var idx, length = self.categories.length, category;
  1487. for (idx = 0; idx < length; idx = idx + 1) {
  1488. category = self.categories[idx];
  1489. self.bargroups[category] = self.chart.append('g').classed('cg-' + uv.util.formatClassName(category), true);
  1490. self['draw' + self.config.graph.orientation + 'Bars'](idx);
  1491. }
  1492. self.finalize();
  1493. };
  1494. uv.BarGraph.prototype = uv.util.inherits(uv.Graph);
  1495. uv.BarGraph.prototype.setDefaults = function () {
  1496. var self = this;
  1497. self.graphdef.stepup = 'normal';
  1498. return this;
  1499. };
  1500. uv.BarGraph.prototype.drawHorizontalBars = function (idx) {
  1501. var self = this,
  1502. color = uv.util.getColorBand(this.config, idx),
  1503. len = self.categories.length;
  1504. var bars = self.bargroups[self.categories[idx]].selectAll('g').data(self.graphdef.dataset[self.categories[idx]]).enter()
  1505. .append('g').classed('cge-' + uv.util.formatClassName(self.categories[idx]), true)
  1506. .attr('transform', function (d) { if (d.value < 0) return 'scale(-1,1)'; });
  1507. bars.append('rect')
  1508. .classed(uv.util.formatClassName(self.categories[idx]), true)
  1509. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1510. .attr('height', self.axes.ver.scale.rangeBand() / len)
  1511. .attr('x', function (d) {
  1512. return (d.value < 0) ? (-self.axes.hor.scale(0)) : self.axes.hor.scale(0);
  1513. })
  1514. .attr('y', function (d) {return self.axes.ver.scale(d.name); })
  1515. .attr('width', 0)
  1516. .style('stroke', self.config.bar.strokecolor)
  1517. .style('fill', color)
  1518. .transition()
  1519. .duration(self.config.effects.duration)
  1520. .delay(function (d, i) { return i * self.config.effects.duration; })
  1521. .attr('width', function (d) { return self.axes.hor.scale(Math.abs(d.value)) - self.axes.hor.scale(0); })
  1522. .call(uv.util.endAll, function (d,i){
  1523. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseover', uv.effects.bar.mouseover(self, idx));
  1524. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseout', uv.effects.bar.mouseout(self, idx));
  1525. if (typeof self.config.graph.clickCallback === "function") {
  1526. d3.select(this.parentNode.parentNode).selectAll('rect').on('click', function(_d){
  1527. self.config.graph.clickCallback.apply(null, [_d]);
  1528. });
  1529. }
  1530. });
  1531. bars.append('text')
  1532. .attr('x', function(d) { return self.axes.hor.scale(0); })
  1533. .attr('y', function(d) { return self.axes.ver.scale(d.name) + (self.axes.ver.scale.rangeBand()/len)/2; })
  1534. .attr('dx', function (d) { return (d.value < 0)? '-20px': '4px' })
  1535. .attr('dy', '.35em')
  1536. .attr('text-anchor', 'start')
  1537. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1538. .style('fill', self.config.label.showlabel ? uv.util.getColorBand(self.config, idx) : 'none')
  1539. .style('font-family', self.config.bar.fontfamily)
  1540. .style('font-size', self.config.bar.fontsize)
  1541. .style('font-weight', self.config.bar.fontweight)
  1542. .style('transform', function (d) { return d.value < 0? 'scale(-1,1)': 'scale(1,1)'; })
  1543. .style('opacity', 0)
  1544. .text(function(d) { return uv.util.getLabelValue(self, d); })
  1545. .transition()
  1546. .duration(self.config.effects.duration)
  1547. .delay(function (d, i) { return i * self.config.effects.duration; })
  1548. .style('opacity', 1)
  1549. .attr('x', function (d) { return self.axes.hor.scale(d.value); });
  1550. bars.append('svg:title')
  1551. .text( function (d, i) { return uv.util.getTooltipText(self, self.categories[idx], self.labels[i], d);});
  1552. self.bargroups[self.categories[idx]].attr('transform', 'translate(0,' + idx * self.axes.ver.scale.rangeBand() / len + ')');
  1553. };
  1554. uv.BarGraph.prototype.drawVerticalBars = function (idx) {
  1555. var self = this,
  1556. color = uv.util.getColorBand(this.config, idx),
  1557. len = self.categories.length;
  1558. var bars = self.bargroups[self.categories[idx]].selectAll('g').data(self.graphdef.dataset[self.categories[idx]]).enter()
  1559. .append('g').classed('cge-' + uv.util.formatClassName(self.categories[idx]), true)
  1560. .attr('transform', function (d) { if (d.value < 0) return 'scale(1, -1)'; });
  1561. bars.append('rect')
  1562. .classed(uv.util.formatClassName(self.categories[idx]), true)
  1563. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1564. .attr('height', 0)
  1565. .attr('width', self.axes.hor.scale.rangeBand() / len)
  1566. .attr('x', function (d) { return self.axes.hor.scale(d.name); })
  1567. .attr('y', function (d) { return (d.value < 0? -1: 1) * (self.height() - self.axes.ver.scale(0)); })
  1568. .style('stroke', self.config.bar.strokecolor).style('fill', color)
  1569. .transition()
  1570. .duration(self.config.effects.duration)
  1571. .delay(idx * self.config.effects.duration)
  1572. .attr('height', function (d) { return Math.abs(self.axes.ver.scale(0) - self.axes.ver.scale(d.value)); })
  1573. .call(uv.util.endAll, function (d,i){
  1574. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseover', uv.effects.bar.mouseover(self, idx));
  1575. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseout', uv.effects.bar.mouseout(self, idx));
  1576. if(typeof self.config.graph.clickCallback === "function") {
  1577. d3.select(this.parentNode.parentNode).selectAll('rect').on('click', function(_d){
  1578. self.config.graph.clickCallback.apply(null, [_d]);
  1579. });
  1580. }
  1581. });
  1582. bars.append('text').attr('transform', function (d) { return (d.value < 0) ? 'scale(1,1)': 'scale(1,-1)'; })
  1583. .attr('x', function(d) { return self.axes.hor.scale(d.name) + (self.axes.hor.scale.rangeBand()/len)/2; })
  1584. .attr('y', function(d) { return self.height() - self.axes.ver.scale(0) })
  1585. .attr('dx', 0)
  1586. .attr('dy', function (d) { return d.value < 0 ? '2em' : '.35em' })
  1587. .attr('text-anchor', 'middle')
  1588. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1589. .style('fill', self.config.label.showlabel ? uv.util.getColorBand(self.config, idx) : 'none')
  1590. .style('font-family', self.config.bar.fontfamily)
  1591. .style('font-size', self.config.bar.fontsize)
  1592. .style('font-weight', self.config.bar.fontweight)
  1593. .style('opacity', 0)
  1594. .text(function(d) { return uv.util.getLabelValue(self, d); })
  1595. .transition()
  1596. .duration(self.config.effects.duration)
  1597. .delay(idx * self.config.effects.duration)
  1598. .style('opacity', 1)
  1599. .attr('y', function (d) { return -(self.height() - self.axes.ver.scale(d.value)) - 10; });
  1600. bars.append('svg:title')
  1601. .text( function (d, i) { return uv.util.getTooltipText(self, self.categories[idx], self.labels[i], d);});
  1602. self.bargroups[self.categories[idx]].attr('transform', 'translate(' + idx * self.axes.hor.scale.rangeBand() / len + ',' + self.height() + ') scale(1,-1)');
  1603. };
  1604. uv.DonutGraph = function (graphdef, config) {
  1605. var self = this;
  1606. uv.Graph.call(self, graphdef, config).setDefaults().init();
  1607. self.radius = Math.min(self.height(), self.width()) * 2 / 5;
  1608. self.center = {
  1609. x : self.width() / 2,
  1610. y : self.height() / 2
  1611. };
  1612. self.category = graphdef.categories[0];
  1613. var data = uv.util.getCategoryData(self.graphdef, [self.category]),
  1614. arcfunc = d3.svg.arc().innerRadius(self.radius * self.config.donut.factor).outerRadius(self.radius),
  1615. layout = d3.layout.pie();
  1616. self.chart.data(data);
  1617. self.arcs = self.chart.selectAll('g.arc')
  1618. .data(layout).enter()
  1619. .append('g').classed(uv.constants.classes.arc + uv.util.formatClassName(self.category), true)
  1620. .attr('transform', 'translate(' + self.center.x + ',' + self.center.y + ')');
  1621. self.arcs.append('path')
  1622. .attr('d', arcfunc)
  1623. .style('fill', function (d, i) { return uv.util.getColorBand(self.config, i); })
  1624. .style('stroke', self.config.donut.strokecolor)
  1625. .style('stroke-width', self.config.donut.strokewidth)
  1626. .on('mouseover', uv.effects.donut.mouseover(self.center, arcfunc, self.config))
  1627. .on('mouseout', uv.effects.donut.mouseout(self.center, self.config))
  1628. if (typeof self.config.graph.clickCallback === "function") {
  1629. self.arcs.on('click', function (d) {
  1630. self.config.graph.clickCallback.apply(null, [d]);
  1631. });
  1632. }
  1633. self.arcs.append('text')
  1634. .attr('transform', function (d) { return 'translate(' + arcfunc.centroid(d) + ')'; })
  1635. .attr('dy', '.35em')
  1636. .attr('text-anchor', 'middle')
  1637. .style('fill', self.config.label.showlabel ? self.config.donut.fontfill : 'none')
  1638. .style('font-family', self.config.donut.fontfamily)
  1639. .style('font-size', self.config.donut.fontsize)
  1640. .style('font-weight', self.config.donut.fontweight)
  1641. .style('font-variant', self.config.donut.fontvariant)
  1642. .text(function (d) { return uv.util.getLabelValue(self, d); });
  1643. self.arcs.append('svg:title')
  1644. .text(function (d, i) { return uv.util.getTooltipText(self, self.category, self.labels[i], d);});
  1645. };
  1646. uv.DonutGraph.prototype = uv.util.inherits(uv.Graph);
  1647. uv.DonutGraph.prototype.setDefaults = function () {
  1648. var self = this;
  1649. self.graphdef.stepup = 'normal';
  1650. self.config.legend.legendtype = 'labels';
  1651. return this;
  1652. };
  1653. uv.LineGraph = function (graphdef, config) {
  1654. var self = this;
  1655. uv.Graph.call(self, graphdef, config).setDefaults().init();
  1656. self.linegroups = {};
  1657. self.dataset = uv.util.getDataArray(self.graphdef);
  1658. var linegroup, linepath, linefunc, idx, len = self.categories.length,
  1659. domainData = self.labels;
  1660. self.axes[self.config.graph.orientation === 'Horizontal' ? 'ver' : 'hor'].scale.domain(domainData);
  1661. for (idx = 0; idx < len; idx = idx + 1) {
  1662. linepath = self.chart.append('g').classed('cg-' + uv.util.formatClassName(self.categories[idx]), true)
  1663. .append('g').classed('cge-' + uv.util.formatClassName(self.categories[idx]), true).datum(self.dataset[idx]);
  1664. linegroup = {
  1665. path: linepath,
  1666. func: undefined
  1667. };
  1668. self['draw' + self.config.graph.orientation + 'Lines'](linegroup, idx);
  1669. self.linegroups[self.categories[idx]] = linegroup;
  1670. }
  1671. self.finalize();
  1672. };
  1673. uv.LineGraph.prototype = uv.util.inherits(uv.Graph);
  1674. uv.LineGraph.prototype.setDefaults = function () {
  1675. var self = this;
  1676. self.graphdef.stepup = 'normal';
  1677. self.config.scale.ordinality = 0;
  1678. return this;
  1679. };
  1680. uv.LineGraph.prototype.drawHorizontalLines = function (linegroup, idx) {
  1681. var self = this,
  1682. axes = self.axes,
  1683. config = self.config,
  1684. color = uv.util.getColorBand(self.config, idx);
  1685. self.axes.ver.scale.rangePoints([0, self.height()]);
  1686. linegroup.func = d3.svg.line()
  1687. .x(function (d) { return axes.hor.scale(d.value); })
  1688. .y(function (d) { return axes.ver.scale(d.name) + axes.ver.scale.rangeBand() / 2; })
  1689. .interpolate(uv.config.line.interpolation);
  1690. linegroup.path.append('path')
  1691. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1692. .attr('d', linegroup.func)
  1693. .style('fill', 'none')
  1694. .style('stroke', color)
  1695. .style('stroke-width', self.config.line.strokewidth)
  1696. .style('stroke-opacity', self.config.line.strokeopacity)
  1697. .transition()
  1698. .duration(3 * self.config.effects.duration)
  1699. .delay(2 * idx * self.config.effects.duration)
  1700. .style('stroke-opacity', 1)
  1701. .call(uv.util.endAll, function (d,i){
  1702. d3.select(this.parentNode.parentNode).selectAll('path').on('mouseover', uv.effects.line.mouseover(self, idx));
  1703. d3.select(this.parentNode.parentNode).selectAll('path').on('mouseout', uv.effects.line.mouseout(self, idx));
  1704. d3.select(this.parentNode.parentNode).selectAll('circle').on('mouseover', uv.effects.line.mouseover(self, idx));
  1705. d3.select(this.parentNode.parentNode).selectAll('circle').on('mouseout', uv.effects.line.mouseout(self, idx));
  1706. });
  1707. if (self.config.line.showcircles) {
  1708. linegroup.path.selectAll('circle')
  1709. .data(self.dataset[idx])
  1710. .enter().append('circle')
  1711. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1712. .attr('cx', linegroup.func.x())
  1713. .attr('cy', linegroup.func.y())
  1714. .attr('r', self.config.line.circleradius)
  1715. .style('fill', color)
  1716. .style('fill-opacity', self.config.line.circleopacity)
  1717. .style('stroke', '#fff')
  1718. .append('svg:title')
  1719. .text( function (d, i) { return uv.util.getTooltipText(self, self.categories[idx], self.labels[i], d);});
  1720. }
  1721. linegroup.path.selectAll('text')
  1722. .data(self.dataset[idx])
  1723. .enter().append('text')
  1724. .attr('x', function (d) { return axes.hor.scale(d.value); })
  1725. .attr('y', function(d) { return axes.ver.scale(d.name) + axes.ver.scale.rangeBand()/2; })
  1726. .attr('dx', 10)
  1727. .attr('dy', '.35em')
  1728. .attr('text-anchor', 'start')
  1729. .style('opacity', 0)
  1730. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1731. .style('fill', self.config.label.showlabel ? uv.util.getColorBand(self.config, idx) : 'none')
  1732. .style('font-family', self.config.line.fontfamily)
  1733. .style('font-size', self.config.line.fontsize)
  1734. .style('font-weight', self.config.line.fontweight)
  1735. .text(function(d) { return uv.util.getLabelValue(self, d); })
  1736. .transition()
  1737. .duration(3 * self.config.effects.duration)
  1738. .delay(2 * idx * self.config.effects.duration)
  1739. .style('opacity', 1);
  1740. return this;
  1741. };
  1742. uv.LineGraph.prototype.drawVerticalLines = function (linegroup, idx) {
  1743. var self = this,
  1744. axes = self.axes,
  1745. config = self.config,
  1746. color = uv.util.getColorBand(self.config, idx);
  1747. self.axes.hor.scale.rangePoints([0, self.width()]);
  1748. linegroup.func = d3.svg.line()
  1749. .x(function (d) { return axes.hor.scale(d.name) + axes.hor.scale.rangeBand() / 2; })
  1750. .y(function (d) { return axes.ver.scale(d.value); })
  1751. .interpolate(uv.config.line.interpolation);
  1752. linegroup.path.append('path')
  1753. .attr('d', linegroup.func)
  1754. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1755. .style('fill', 'none')
  1756. .style('stroke', color)
  1757. .style('stroke-width', self.config.line.strokewidth)
  1758. .style('stroke-opacity', self.config.line.strokeopacity)
  1759. .transition()
  1760. .duration(self.config.effects.duration)
  1761. .delay(2 * idx * self.config.effects.duration)
  1762. .style('stroke-opacity', 1)
  1763. .call(uv.util.endAll, function (d,i){
  1764. d3.select(this.parentNode.parentNode).selectAll('path').on('mouseover', uv.effects.line.mouseover(self, idx));
  1765. d3.select(this.parentNode.parentNode).selectAll('path').on('mouseout', uv.effects.line.mouseout(self, idx));
  1766. d3.select(this.parentNode.parentNode).selectAll('circle').on('mouseover', uv.effects.line.mouseover(self, idx));
  1767. d3.select(this.parentNode.parentNode).selectAll('circle').on('mouseout', uv.effects.line.mouseout(self, idx));
  1768. });
  1769. if (self.config.line.showcircles) {
  1770. linegroup.path.selectAll('circle')
  1771. .data(self.dataset[idx])
  1772. .enter().append('circle')
  1773. .attr('cx', linegroup.func.x())
  1774. .attr('cy', linegroup.func.y())
  1775. .attr('r', self.config.line.circleradius)
  1776. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1777. .style('fill', color)
  1778. .style('fill-opacity', self.config.line.circleopacity)
  1779. .style('stroke', '#fff')
  1780. .append('svg:title')
  1781. .text( function (d, i) { return uv.util.getTooltipText(self, self.categories[idx], self.labels[i], d);});
  1782. }
  1783. linegroup.path.selectAll('text')
  1784. .data(self.dataset[idx])
  1785. .enter().append('text')
  1786. .attr('x', function (d) { return axes.hor.scale(d.name) + axes.hor.scale.rangeBand() / 2; })
  1787. .attr('y', function (d) { return axes.ver.scale(d.value) - 20; })
  1788. .attr('dx', 0)
  1789. .attr('dy', '.71em')
  1790. .attr('text-anchor', 'middle')
  1791. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1792. .style('fill', self.config.label.showlabel ? uv.util.getColorBand(self.config, idx) : 'none')
  1793. .style('font-family', self.config.line.fontfamily)
  1794. .style('font-size', self.config.line.fontsize)
  1795. .style('font-weight', self.config.line.fontweight)
  1796. .style('opacity', 0)
  1797. .text(function(d) { return uv.util.getLabelValue(self, d); })
  1798. .transition()
  1799. .duration(3 * self.config.effects.duration)
  1800. .delay(2 * idx * self.config.effects.duration)
  1801. .style('opacity', 1);
  1802. return this;
  1803. };
  1804. uv.PercentAreaGraph = function (graphdef, config) {
  1805. var self = this;
  1806. uv.Graph.call(self, graphdef, config).setDefaults().init();
  1807. var stacklayout = d3.layout.stack().offset('zero')(
  1808. self.categories.map(function (d) {
  1809. return graphdef.dataset[d].map(function (d) {
  1810. return {x: d.name, y: +d.value};
  1811. });
  1812. })
  1813. );
  1814. var areagroup, areapath, areafunc,
  1815. domainData = self.labels,
  1816. categories = self.categories;
  1817. self.axes[self.config.graph.orientation === 'Horizontal' ? 'ver' : 'hor'].scale.domain(domainData);
  1818. self.areagroup = self.chart.selectAll('g.areagroup').data(stacklayout).enter().append('g')
  1819. .attr('class', function (d,i) {
  1820. return uv.util.getClassName(this, 'cge-' + self.categories[i]);
  1821. });
  1822. self['draw' + self.config.graph.orientation + 'Area']();
  1823. self.finalize();
  1824. };
  1825. uv.PercentAreaGraph.prototype = uv.util.inherits(uv.Graph);
  1826. uv.PercentAreaGraph.prototype.setDefaults = function () {
  1827. var self = this;
  1828. self.graphdef.stepup = 'percent';
  1829. return this;
  1830. };
  1831. uv.PercentAreaGraph.prototype.drawHorizontalArea = function () {
  1832. var self = this, axes = self.axes,
  1833. categories = self.categories,
  1834. config = self.config,
  1835. sumMap = uv.util.getSumUpArray(self.graphdef);
  1836. axes.ver.scale.rangePoints([0, self.height()]);
  1837. for(var i = 0; i < categories.length; i = i + 1) {
  1838. uv.effects.area.mouseover(self, i);
  1839. uv.effects.area.mouseout(self,i);
  1840. }
  1841. self.areagroup.append('path')
  1842. .attr('class', function (d, i) {
  1843. return uv.util.getClassName(this, uv.constants.classes.area + uv.util.formatClassName(categories[i]));
  1844. })
  1845. .style('fill', function (d, i) { return uv.util.getColorBand(config, i); })
  1846. .attr('d', d3.svg.area()
  1847. .y(function (d) { return axes.ver.scale(d.x) + axes.ver.scale.rangeBand() / 2; })
  1848. .x0(function (d, i) { return axes.hor.scale(uv.util.getPercentage(d.y0, sumMap[i])); })
  1849. .x1(function (d, i) { return axes.hor.scale(uv.util.getPercentage(d.y0 + d.y, sumMap[i])); })
  1850. .interpolate(self.config.area.interpolation)
  1851. )
  1852. .on('mouseover', function (d,i) { self.effects[categories[i]].mouseover(); })
  1853. .on('mouseout', function (d,i) { self.effects[categories[i]].mouseout(); });
  1854. self.areagroup.append('path')
  1855. .attr('class', function (d, i) {
  1856. return uv.util.getClassName(this, uv.constants.classes.line + uv.util.formatClassName(categories[i]));
  1857. })
  1858. .style('stroke', 'white')
  1859. .style('fill', 'none')
  1860. .style('stroke-width', 2)
  1861. .attr('d', d3.svg.line()
  1862. .y(function (d) { return axes.ver.scale(d.x) + axes.ver.scale.rangeBand() / 2; })
  1863. .x(function (d, i) { return axes.hor.scale(uv.util.getPercentage(d.y0 + d.y, sumMap[i])); })
  1864. .interpolate(self.config.area.interpolation)
  1865. );
  1866. };
  1867. uv.PercentAreaGraph.prototype.drawVerticalArea = function () {
  1868. var self = this, axes = self.axes,
  1869. categories = self.categories,
  1870. config = self.config,
  1871. sumMap = uv.util.getSumUpArray(self.graphdef);
  1872. axes.hor.scale.rangePoints([0, self.width()]);
  1873. for(var i = 0; i < categories.length; i = i + 1){
  1874. uv.effects.area.mouseover(self, i);
  1875. uv.effects.area.mouseout(self,i);
  1876. }
  1877. self.areagroup.append('path')
  1878. .attr('class', function (d, i) {
  1879. return uv.util.getClassName(this, uv.constants.classes.area + uv.util.formatClassName(categories[i]));
  1880. })
  1881. .style('fill', function (d, i) { return uv.util.getColorBand(config, i); })
  1882. .attr('d', d3.svg.area()
  1883. .x(function (d) { return axes.hor.scale(d.x) + axes.hor.scale.rangeBand() / 2; })
  1884. .y0(function (d, i) { return axes.ver.scale(uv.util.getPercentage(d.y0, sumMap[i])); })
  1885. .y1(function (d, i) { return axes.ver.scale(uv.util.getPercentage(d.y0 + d.y, sumMap[i])); })
  1886. .interpolate(self.config.area.interpolation)
  1887. )
  1888. .on('mouseover', function (d,i) {self.effects[categories[i]].mouseover(); })
  1889. .on('mouseout', function (d,i) { self.effects[categories[i]].mouseout(); });
  1890. self.areagroup.append('path')
  1891. .attr('class', function (d, i) {
  1892. return uv.util.getClassName(this, uv.constants.classes.line + uv.util.formatClassName(categories[i]));
  1893. })
  1894. .style('stroke', 'white')
  1895. .style('fill', 'none')
  1896. .style('stroke-width', 2)
  1897. .attr('d', d3.svg.line()
  1898. .x(function (d, i) { return axes.hor.scale(d.x) + axes.hor.scale.rangeBand() / 2; })
  1899. .y(function (d, i) { return axes.ver.scale(uv.util.getPercentage(d.y0 + d.y, sumMap[i])); })
  1900. .interpolate(self.config.area.interpolation)
  1901. );
  1902. };
  1903. uv.PercentBarGraph = function (graphdef, config) {
  1904. var self = this;
  1905. uv.Graph.call(self, graphdef, config).setDefaults().init();
  1906. self.bargroups = [];
  1907. var bargroup, bars, idx, len, color,
  1908. domainData = self.labels,
  1909. csum = domainData.map(function (d) {return 0; }),
  1910. tsum = domainData.map(function (d) {return 0; });
  1911. self.axes[self.config.graph.orientation === 'Horizontal' ? 'ver' : 'hor'].scale.domain(domainData);
  1912. for (idx = 0, len = self.categories.length; idx < len; idx = idx + 1) {
  1913. color = uv.util.getColorBand(self.config, idx);
  1914. bargroup = self.chart.append('g').classed('cg-' + self.categories[idx], true);
  1915. bars = bargroup.selectAll('g').data(self.graphdef.dataset[self.categories[idx]]).enter().append('g').classed('cge-' + uv.util.formatClassName(self.categories[idx]), true);
  1916. self['draw' + uv.util.getPascalCasedName(self.config.graph.orientation) + 'Bars'](bars, csum, tsum, idx);
  1917. if (self.config.graph.orientation === 'Vertical') {
  1918. bargroup.attr('transform', 'translate(0,' + 2 * self.height() + ') scale(1,-1)');
  1919. }
  1920. self.bargroups.push(bargroup);
  1921. }
  1922. self.finalize();
  1923. };
  1924. uv.PercentBarGraph.prototype = uv.util.inherits(uv.Graph);
  1925. uv.PercentBarGraph.prototype.setDefaults = function () {
  1926. var self = this;
  1927. self.graphdef.stepup = 'percent';
  1928. self.config.scale.ordinality = 0;
  1929. return this;
  1930. };
  1931. uv.PercentBarGraph.prototype.drawHorizontalBars = function (bars, csum, tsum, idx) {
  1932. var self = this,
  1933. axes = this.axes,
  1934. color = uv.util.getColorBand(this.config, idx),
  1935. config = this.config,
  1936. sumMap = uv.util.getSumUpArray(this.graphdef);
  1937. bars.append('rect')
  1938. .attr('height', axes.ver.scale.rangeBand())
  1939. .attr('width', 0)
  1940. .attr('x', function (d, i) { var value = axes.hor.scale(uv.util.getPercentage(csum[i], sumMap[i])); csum[i] += d.value; return value; })
  1941. .attr('y', function (d) {return axes.ver.scale(d.name); })
  1942. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1943. .style('stroke', 'none')
  1944. .style('fill', color)
  1945. .transition()
  1946. .duration(self.config.effects.duration)
  1947. .delay(idx * self.config.effects.duration)
  1948. .attr('width', function (d, i) { return axes.hor.scale(uv.util.getPercentage(d.value, sumMap[i]));})
  1949. .call(uv.util.endAll, function (d,i){
  1950. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseover', uv.effects.bar.mouseover(self, idx, self.config.effects.textcolor));
  1951. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseout', uv.effects.bar.mouseout(self, idx, self.config.effects.textcolor));
  1952. });
  1953. bars.append('text')
  1954. .attr('y', function(d) { return axes.ver.scale(d.name) + axes.ver.scale.rangeBand()/2; })
  1955. .attr('dx', 0)
  1956. .attr('dy', '.35em')
  1957. .attr('text-anchor', 'end')
  1958. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1959. .style('fill', self.config.label.showlabel ? self.config.effects.textcolor : 'none')
  1960. .style('font-family', this.config.bar.fontfamily)
  1961. .style('font-size', this.config.bar.fontsize)
  1962. .style('font-weight', this.config.bar.fontweight)
  1963. .text(function(d, i) { return ( axes.hor.scale(uv.util.getPercentage(csum[i], sumMap[i])) > 15 ) ? String(Math.round(uv.util.getPercentage(d.value, sumMap[i]))) : null; })
  1964. .transition()
  1965. .duration(self.config.effects.duration)
  1966. .delay(idx * self.config.effects.duration)
  1967. .attr('x', function (d, i) { tsum[i] += d.value; return axes.hor.scale(uv.util.getPercentage(tsum[i], sumMap[i])) - 5; });
  1968. };
  1969. uv.PercentBarGraph.prototype.drawVerticalBars = function (bars, csum, tsum, idx) {
  1970. var self = this,
  1971. height = this.height(),
  1972. axes = this.axes,
  1973. color = uv.util.getColorBand(this.config, idx),
  1974. config = this.config,
  1975. sumMap = uv.util.getSumUpArray(this.graphdef);
  1976. bars.append('rect')
  1977. .attr('height', 0)
  1978. .attr('width', axes.hor.scale.rangeBand())
  1979. .attr('x', function (d) { return axes.hor.scale(d.name); })
  1980. .attr('y', function (d, i) { var value = axes.ver.scale(uv.util.getPercentage(csum[i], sumMap[i])); csum[i] -= d.value; return value; })
  1981. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1982. .style('stroke', 'none')
  1983. .style('fill', color)
  1984. .transition()
  1985. .duration(self.config.effects.duration)
  1986. .delay(idx * self.config.effects.duration)
  1987. .attr('height', function (d, i) { return height - axes.ver.scale(uv.util.getPercentage(d.value, sumMap[i])); })
  1988. .call(uv.util.endAll, function (d,i){
  1989. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseover', uv.effects.bar.mouseover(self, idx, self.config.effects.textcolor));
  1990. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseout', uv.effects.bar.mouseout(self, idx, self.config.effects.textcolor));
  1991. });
  1992. bars.append('text').attr('transform','scale(1,-1)')
  1993. .attr('x', function(d) { return axes.hor.scale(d.name) + axes.hor.scale.rangeBand()/2; })
  1994. .attr('y', -height + 5)
  1995. .attr('dy', '.71em')
  1996. .attr('text-anchor', 'middle')
  1997. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  1998. .style('fill', self.config.label.showlabel ? self.config.effects.textcolor : 'none')
  1999. .style('font-family', this.config.bar.fontfamily)
  2000. .style('font-size', this.config.bar.fontsize)
  2001. .style('font-weight', this.config.bar.fontweight)
  2002. .text(function(d, i) { return ( height - axes.ver.scale(uv.util.getPercentage(d.value, sumMap[i])) > 15) ? String(Math.round(uv.util.getPercentage(d.value, sumMap[i]))) : null; })
  2003. .transition()
  2004. .duration(self.config.effects.duration)
  2005. .delay(idx * self.config.effects.duration)
  2006. .attr('y', function (d, i) { tsum[i] += d.value; return -(2*height - axes.ver.scale(uv.util.getPercentage(tsum[i], sumMap[i]))) + 5; });
  2007. };
  2008. uv.PieGraph = function (graphdef, config) {
  2009. var self = this;
  2010. uv.Graph.call(self, graphdef, config).setDefaults().init();
  2011. self.radius = Math.min(self.height(), self.width()) * 2 / 5;
  2012. self.center = {
  2013. x : self.width() / 2,
  2014. y : self.height() / 2
  2015. };
  2016. self.category = graphdef.categories[0];
  2017. var data = uv.util.getCategoryData(self.graphdef, [self.category]),
  2018. arcfunc = d3.svg.arc().innerRadius(0).outerRadius(self.radius),
  2019. layout = d3.layout.pie();
  2020. self.chart.data(data);
  2021. self.arcs = self.chart.selectAll('g.arc')
  2022. .data(layout).enter()
  2023. .append('g').classed(uv.constants.classes.arc + uv.util.formatClassName(self.category), true)
  2024. .attr('class', function (d, i){
  2025. return uv.util.getClassName(this, 'cge-' + self.labels[i]);
  2026. })
  2027. .attr('transform', 'translate(' + self.center.x + ',' + self.center.y + ')');
  2028. self.arcs.append('path')
  2029. .attr('d', arcfunc)
  2030. .style('fill', function (d, i) { return uv.util.getColorBand(self.config, i); })
  2031. .style('stroke', self.config.pie.strokecolor)
  2032. .style('stroke-width', self.config.pie.strokewidth)
  2033. .on('mouseover', uv.effects.pie.mouseover(self, self.center, arcfunc, self.config))
  2034. .on('mouseout', uv.effects.pie.mouseout(self, self.center, self.config));
  2035. self.arcs.append('text')
  2036. .attr('transform', function (d) { return 'translate(' + arcfunc.centroid(d) + ')'; })
  2037. .attr('dy', '.35em')
  2038. .attr('text-anchor', 'middle')
  2039. .style('fill', self.config.label.showlabel ? self.config.pie.fontfill : 'none')
  2040. .style('font-family', self.config.pie.fontfamily)
  2041. .style('font-size', self.config.pie.fontsize)
  2042. .style('font-weight', self.config.pie.fontweight)
  2043. .style('font-variant', self.config.pie.fontvariant)
  2044. .text(function (d) { return uv.util.getLabelValue(self, d); });
  2045. self.arcs.append('svg:title')
  2046. .text(function (d, i) { return uv.util.getTooltipText(self, self.category, self.labels[i], d);});
  2047. if (typeof self.config.graph.clickCallback === "function") {
  2048. self.arcs.on('click', function (d) {
  2049. self.config.graph.clickCallback.apply(null, [d]);
  2050. });
  2051. }
  2052. };
  2053. uv.PieGraph.prototype = uv.util.inherits(uv.Graph);
  2054. uv.PieGraph.prototype.setDefaults = function () {
  2055. var self = this;
  2056. self.graphdef.stepup = 'normal';
  2057. self.config.legend.legendtype = 'labels';
  2058. return this;
  2059. };
  2060. uv.PolarAreaGraph = function (graphdef, config) {
  2061. var self = this;
  2062. uv.Graph.call(self, graphdef, config).setDefaults().init();
  2063. self.maxRadius = Math.min(self.height(), self.width()) * 2/5;
  2064. self.center = {
  2065. x : self.width() / 2,
  2066. y : self.height() / 2
  2067. };
  2068. self.category = self.categories[0];
  2069. var data = uv.util.getCategoryData(self.graphdef, [self.category]),
  2070. dataMap = data[0].map(function(d,i){ return d; }),
  2071. layout = d3.layout.pie().value(function(d){return self.max()/ data[0].length; }),
  2072. tickRadius = [],
  2073. arcfuncs = d3.svg.arc().innerRadius(0)
  2074. .outerRadius(function(d,i){return ((dataMap[i] * self.maxRadius) / self.max());});
  2075. for (var i=1; i<=self.config.axis.ticks; i++) {
  2076. tickRadius[i] = (self.maxRadius/self.config.axis.ticks) * i;
  2077. }
  2078. self.chart.data(data);
  2079. self.arcs = self.chart.selectAll('g.arc')
  2080. .data(layout).enter()
  2081. .append('g').classed(uv.constants.classes.arc + uv.util.formatClassName(self.category), true)
  2082. .attr('transform', 'translate(' + self.center.x + ',' + self.center.y + ')');
  2083. self.arcs.append('path')
  2084. .attr('d', arcfuncs)
  2085. .style('fill', function (d, i) { return uv.util.getColorBand(self.config, i);})
  2086. .style('stroke', self.config.pie.strokecolor)
  2087. .style('stroke-width', self.config.pie.strokewidth);
  2088. /*self.arcs.append('text')
  2089. .attr('transform', function (d, i) { return 'translate(' + arcfuncs.centroid(d) + ')'; })
  2090. .attr('dy', '.35em')
  2091. .attr('text-anchor', 'middle')
  2092. .style('fill', self.config.pie.fontfill)
  2093. .style('font-family', self.config.pie.fontfamily)
  2094. .style('font-size', self.config.pie.fontsize)
  2095. .style('font-weight', self.config.pie.fontweight)
  2096. .style('font-variant', self.config.pie.fontvariant)
  2097. .text(function (d) { return uv.util.getLabelValue(self, d); }); */
  2098. self.arcs.append('svg:title')
  2099. .text(function (d, i) { return uv.util.getTooltipText(self, self.category, self.labels[i], d);});
  2100. self.chart.selectAll('.' + uv.constants.classes.circleticks)
  2101. .data(tickRadius)
  2102. .enter().append('svg:g').classed(uv.constants.classes.circleticks, true)
  2103. .append("svg:circle")
  2104. .attr("r", function (d, i) { return d; })
  2105. .style("stroke", self.config.axis.strokecolor)
  2106. .style("opacity", self.config.axis.opacity)
  2107. .style("fill", "none")
  2108. .attr('transform', 'translate(' + self.center.x + ',' + self.center.y + ')');
  2109. if (typeof self.config.graph.clickCallback === "function") {
  2110. self.arcs.on('click', function (d) {
  2111. self.config.graph.clickCallback.apply(null, [d]);
  2112. });
  2113. }
  2114. };
  2115. uv.PolarAreaGraph.prototype = uv.util.inherits(uv.Graph);
  2116. uv.PolarAreaGraph.prototype.setDefaults = function () {
  2117. var self = this;
  2118. self.graphdef.stepup = 'normal';
  2119. self.config.legend.legendtype = 'labels';
  2120. return this;
  2121. };
  2122. uv.StackedAreaGraph = function (graphdef, config) {
  2123. var self = this;
  2124. uv.Graph.call(self, graphdef, config).setDefaults().init();
  2125. var stacklayout = d3.layout.stack().offset(self.config.area.offset)(self.categories.map(function (d) {
  2126. return graphdef.dataset[d].map(function (d) { return {x: d.name, y: +d.value}; });
  2127. }));
  2128. self.axes[self.config.graph.orientation === 'Horizontal' ? 'ver' : 'hor'].scale.domain(self.labels.map(function (d) { return d; }));
  2129. self.areagroup = self.chart.append('g').selectAll('g')
  2130. .data(stacklayout).enter().append('g').attr('class', function (d, i) {
  2131. return uv.util.getClassName(this, 'cge-' + self.categories[i]);
  2132. });
  2133. self['draw' + self.config.graph.orientation + 'Area']();
  2134. self.finalize();
  2135. };
  2136. uv.StackedAreaGraph.prototype = uv.util.inherits(uv.Graph);
  2137. uv.StackedAreaGraph.prototype.setDefaults = function () {
  2138. var self = this;
  2139. self.graphdef.stepup = 'stepup';
  2140. return this;
  2141. };
  2142. uv.StackedAreaGraph.prototype.drawHorizontalArea = function () {
  2143. var self = this, axes = self.axes,
  2144. categories = self.categories,
  2145. config = self.config;
  2146. axes.ver.scale.rangePoints([0, self.height()]);
  2147. for(var i = 0; i < categories.length; i = i + 1){
  2148. uv.effects.area.mouseover(self, i);
  2149. uv.effects.area.mouseout(self, i);
  2150. }
  2151. self.areagroup.append('path')
  2152. .attr('class', function (d, i) {
  2153. return uv.util.getClassName(this, uv.constants.classes.area + categories[i]);
  2154. })
  2155. .style('fill', function (d, i) { return uv.util.getColorBand(config, i); })
  2156. .attr('d', d3.svg.area()
  2157. .y(function (d) { return axes.ver.scale(d.x) + axes.ver.scale.rangeBand() / 2; })
  2158. .x0(function (d) { return axes.hor.scale(d.y0); })
  2159. .x1(function (d) { return axes.hor.scale(d.y0 + d.y); })
  2160. .interpolate(self.config.area.interpolation)
  2161. )
  2162. .on('mouseover', function (d,i){ self.effects[categories[i]].mouseover(); })
  2163. .on('mouseout', function (d,i) { self.effects[categories[i]].mouseout(); });
  2164. self.areagroup.append('path')
  2165. .attr('class', function (d, i) {
  2166. return uv.util.getClassName(this, uv.constants.classes.line + categories[i]);
  2167. })
  2168. .style('stroke', 'white')
  2169. .style('fill', 'none')
  2170. .style('stroke-width', 2)
  2171. .attr('d', d3.svg.line()
  2172. .y(function (d) { return axes.ver.scale(d.x) + axes.ver.scale.rangeBand() / 2; })
  2173. .x(function (d) { return axes.hor.scale(d.y0 + d.y); })
  2174. .interpolate(self.config.area.interpolation)
  2175. );
  2176. return self;
  2177. };
  2178. uv.StackedAreaGraph.prototype.drawVerticalArea = function () {
  2179. var self = this, axes = self.axes,
  2180. categories = self.categories,
  2181. config = self.config;
  2182. axes.hor.scale.rangePoints([0, self.width()]);
  2183. for(var i = 0; i < categories.length; i = i + 1){
  2184. uv.effects.area.mouseover(self, i);
  2185. uv.effects.area.mouseout(self, i);
  2186. }
  2187. self.areagroup.append('path')
  2188. .attr('class', function (d, i) {
  2189. return uv.util.getClassName(this, uv.constants.classes.area + categories[i]);
  2190. })
  2191. .style('fill', function (d, i) { return uv.util.getColorBand(config, i); })
  2192. .attr('d', d3.svg.area()
  2193. .x(function (d) { return axes.hor.scale(d.x) + axes.hor.scale.rangeBand() / 2; })
  2194. .y0(function (d) { return axes.ver.scale(d.y0); })
  2195. .y1(function (d) { return axes.ver.scale(d.y0 + d.y); })
  2196. .interpolate(self.config.area.interpolation)
  2197. )
  2198. .on('mouseover', function (d,i){ self.effects[categories[i]].mouseover(); })
  2199. .on('mouseout', function (d,i) { self.effects[categories[i]].mouseout(); });
  2200. self.areagroup.append('path')
  2201. .attr('class', function (d, i) {
  2202. return uv.util.getClassName(this, uv.constants.classes.line + categories[i]);
  2203. })
  2204. .style('stroke', 'white')
  2205. .style('fill', 'none')
  2206. .style('stroke-width', 2)
  2207. .attr('d', d3.svg.line()
  2208. .x(function (d) { return axes.hor.scale(d.x) + axes.hor.scale.rangeBand() / 2; })
  2209. .y(function (d) { return axes.ver.scale(d.y0 + d.y); })
  2210. .interpolate(self.config.area.interpolation)
  2211. );
  2212. return self;
  2213. };
  2214. uv.StackedBarGraph = function (graphdef, config) {
  2215. var self = this;
  2216. uv.Graph.call(self, graphdef, config).setDefaults().init();
  2217. self.bargroups = {};
  2218. var bargroup, bars, idx, len, color,
  2219. domainData = self.labels,
  2220. csum = domainData.map(function (d) {return 0; }),
  2221. tsum = domainData.map(function (d) {return 0; });
  2222. self.axes[self.config.graph.orientation === 'Horizontal' ? 'ver' : 'hor'].scale.domain(domainData);
  2223. for (idx = 0, len = self.categories.length; idx < len; idx = idx + 1) {
  2224. self.bargroups[self.categories[idx]] = self.chart.append('g').classed('cg-' + uv.util.formatClassName(self.categories[idx]), true);
  2225. self['draw' + self.config.graph.orientation + 'Bars'](idx, csum, tsum);
  2226. }
  2227. self.finalize();
  2228. };
  2229. uv.StackedBarGraph.prototype = uv.util.inherits(uv.Graph);
  2230. uv.StackedBarGraph.prototype.setDefaults = function () {
  2231. var self = this;
  2232. self.graphdef.stepup = 'stepup';
  2233. return this;
  2234. };
  2235. uv.StackedBarGraph.prototype.drawHorizontalBars = function (idx, csum, tsum) {
  2236. var self = this,
  2237. axes = this.axes,
  2238. color = uv.util.getColorBand(this.config, idx),
  2239. config = this.config,
  2240. bargroup = this.bargroups[this.categories[idx]];
  2241. var bars = bargroup.selectAll('g').data(this.graphdef.dataset[self.categories[idx]])
  2242. .enter().append('g').classed('cge-' + uv.util.formatClassName(self.categories[idx]), true);
  2243. bars.append('rect')
  2244. .attr('height', axes.ver.scale.rangeBand())
  2245. .attr('width', 0)
  2246. .attr('x', function (d, i) { var value = axes.hor.scale(csum[i]); csum[i] += d.value; return value; })
  2247. .attr('y', function (d) {return axes.ver.scale(d.name); })
  2248. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  2249. .style('stroke', 'none')
  2250. .style('fill', color)
  2251. .transition()
  2252. .duration(self.config.effects.duration)
  2253. .delay(idx * self.config.effects.duration)
  2254. .attr('width', function (d,i) { return axes.hor.scale(csum[i]) - axes.hor.scale(csum[i]-d.value); })
  2255. .each("end", function (d,i){
  2256. d3.select(this).on('mouseover', uv.effects.bar.mouseover(self, idx, self.config.effects.textcolor));
  2257. d3.select(this).on('mouseout', uv.effects.bar.mouseout(self, idx, self.config.effects.textcolor));
  2258. if(typeof self.config.graph.clickCallback === "function") {
  2259. d3.select(this).on('click', function(_d){
  2260. self.config.graph.clickCallback.apply(null, [_d]);
  2261. });
  2262. }
  2263. });
  2264. bars.append('text')
  2265. .attr('y', function(d) { return axes.ver.scale(d.name) + axes.ver.scale.rangeBand()/2; })
  2266. .attr('dx', 0)
  2267. .attr('dy', '.35em')
  2268. .attr('text-anchor', 'end')
  2269. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  2270. .style('fill', self.config.label.showlabel ? self.config.effects.textcolor : 'none')
  2271. .style('font-family', config.bar.fontfamily)
  2272. .style('font-size', config.bar.fontsize)
  2273. .style('font-weight', config.bar.fontweight)
  2274. .style('opacity', 0)
  2275. .text(function(d) { return ( axes.hor.scale(d.value) > 15 ) ? uv.util.getLabelValue(self, d) : null; })
  2276. .transition()
  2277. .duration(self.config.effects.duration)
  2278. .delay(idx * self.config.effects.duration)
  2279. .style('opacity', 1)
  2280. .attr('x', function (d, i) { tsum[i] += d.value; return axes.hor.scale(tsum[i]) - 5; });
  2281. bars.append('svg:title')
  2282. .text( function (d, i) { return uv.util.getTooltipText(self, self.categories[idx], self.labels[i], d);});
  2283. };
  2284. uv.StackedBarGraph.prototype.drawVerticalBars = function (idx, csum, tsum) {
  2285. var self = this,
  2286. height = this.height(),
  2287. axes = this.axes,
  2288. color = uv.util.getColorBand(this.config, idx),
  2289. config = this.config,
  2290. bargroup = this.bargroups[self.categories[idx]];
  2291. var bars = bargroup.selectAll('g').data(this.graphdef.dataset[self.categories[idx]])
  2292. .enter().append('g').classed('cge-' + uv.util.formatClassName(self.categories[idx]), true);
  2293. bars.append('rect')
  2294. .attr('height', 0)
  2295. .attr('width', axes.hor.scale.rangeBand())
  2296. .attr('x', function (d) { return axes.hor.scale(d.name); })
  2297. .attr('y', function (d, i) { var value = axes.ver.scale(csum[i]); csum[i] -= d.value; return value; })
  2298. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  2299. .style('stroke', 'none')
  2300. .style('fill', color)
  2301. .transition()
  2302. .duration(self.config.effects.duration)
  2303. .delay(idx * self.config.effects.duration)
  2304. .attr('height', function (d,i) { return -(axes.ver.scale(-csum[i]) - axes.ver.scale(-csum[i]-d.value)); })
  2305. .each("end", function (d,i){
  2306. d3.select(this).on('mouseover', uv.effects.bar.mouseover(self, idx, self.config.effects.textcolor));
  2307. d3.select(this).on('mouseout', uv.effects.bar.mouseout(self, idx, self.config.effects.textcolor));
  2308. if(typeof self.config.graph.clickCallback === "function") {
  2309. d3.select(this).on('click', function(_d){
  2310. self.config.graph.clickCallback.apply(null, [_d]);
  2311. });
  2312. }
  2313. });
  2314. bars.append('text').attr('transform','scale(1,-1)')
  2315. .attr('x', function(d) { return axes.hor.scale(d.name) + axes.hor.scale.rangeBand()/2; })
  2316. .attr('y', -height + 5)
  2317. .attr('dy', '.71em')
  2318. .attr('text-anchor', 'middle')
  2319. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  2320. .style('fill', self.config.label.showlabel ? self.config.effects.textcolor : 'none')
  2321. .style('font-family', config.bar.fontfamily)
  2322. .style('font-size', config.bar.fontsize)
  2323. .style('font-weight', config.bar.fontweight)
  2324. .style('opacity', 0)
  2325. .text(function(d) { return ( height - axes.ver.scale(d.value) > 15) ? uv.util.getLabelValue(self, d) : null; })
  2326. .transition()
  2327. .duration(self.config.effects.duration)
  2328. .delay(idx * self.config.effects.duration)
  2329. .style('opacity', 1)
  2330. .attr('y', function (d, i) { tsum[i] += d.value; return -(2*height - axes.ver.scale(tsum[i])) + 5; });
  2331. bars.append('svg:title')
  2332. .text( function (d, i) { return uv.util.getTooltipText(self, self.categories[idx], self.labels[i], d);});
  2333. bargroup.attr('transform', 'translate(0,' + 2 * this.height() + ') scale(1,-1)');
  2334. };
  2335. uv.StepUpBarGraph = function (graphdef, config) {
  2336. var self = this;
  2337. uv.Graph.call(self, graphdef, config).setDefaults().init();
  2338. this.bargroups = {};
  2339. var idx, length = self.categories.length,
  2340. csum = self.labels.map(function (d) {return 0; }),
  2341. tsum = self.labels.map(function (d) {return 0; });
  2342. self.axes[this.config.graph.orientation === 'Horizontal' ? 'ver' : 'hor'].scale.domain(this.labels);
  2343. for (idx = 0; idx < length; idx = idx + 1) {
  2344. self.bargroups[self.categories[idx]] = this.chart.append('g').classed('cg-' + uv.util.formatClassName(self.categories[idx]), true);
  2345. self['draw' + self.config.graph.orientation + 'Bars'](idx, csum, tsum);
  2346. }
  2347. self.finalize();
  2348. };
  2349. uv.StepUpBarGraph.prototype = uv.util.inherits(uv.Graph);
  2350. uv.StepUpBarGraph.prototype.setDefaults = function () {
  2351. var self = this;
  2352. self.graphdef.stepup = 'stepup';
  2353. return this;
  2354. };
  2355. uv.StepUpBarGraph.prototype.drawHorizontalBars = function (idx, csum, tsum) {
  2356. var self = this, len = self.categories.length,
  2357. color = uv.util.getColorBand(self.config, idx),
  2358. bargroup = self.bargroups[self.categories[idx]];
  2359. var bars = bargroup.selectAll('g').data(self.graphdef.dataset[self.categories[idx]]).enter().append('g').classed('cge-' + uv.util.formatClassName(self.categories[idx]), true);
  2360. bars.append('rect')
  2361. .attr('height', self.axes.ver.scale.rangeBand() / len)
  2362. .attr('width', 0)
  2363. .attr('transform',
  2364. function (d) {
  2365. return (d.value < 0) ? 'scale(-1,1)': 'scale(1,1)';
  2366. })
  2367. .attr('x', function (d, i) {
  2368. if (d.resetSum === true) csum[i] = 0;
  2369. var value = self.axes.hor.scale(csum[i]);
  2370. csum[i] += d.value;
  2371. return d.value < 0 ? -value: value;
  2372. })
  2373. .attr('y', function (d) {return self.axes.ver.scale(d.name); })
  2374. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  2375. .style('stroke', 'none')
  2376. .style('fill', color)
  2377. .transition()
  2378. .duration(self.config.effects.duration)
  2379. .delay(idx * self.config.effects.duration)
  2380. .attr('width', function (d, i) { return Math.abs(self.axes.hor.scale(csum[i]) - self.axes.hor.scale(csum[i]-d.value)); })
  2381. .call(uv.util.endAll, function (d,i){
  2382. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseover', uv.effects.bar.mouseover(self, idx));
  2383. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseout', uv.effects.bar.mouseout(self, idx));
  2384. });
  2385. bars.append('text')
  2386. .attr('y', function(d) { return self.axes.ver.scale(d.name) + (self.axes.ver.scale.rangeBand()/len)/2; })
  2387. .attr('dx', function (d) { return (d.value < 0)? -16: 4; })
  2388. .attr('dy', '.35em')
  2389. .attr('text-anchor', 'start')
  2390. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  2391. .style('fill', self.config.label.showlabel ? uv.util.getColorBand(self.config, idx) : 'none')
  2392. .style('opacity', 0)
  2393. .style('font-family', self.config.bar.fontfamily)
  2394. .style('font-size', self.config.bar.fontsize)
  2395. .style('font-weight', self.config.bar.fontweight)
  2396. .text(function(d) { return uv.util.getLabelValue(self, d); })
  2397. .transition()
  2398. .duration(self.config.effects.duration)
  2399. .delay(idx * self.config.effects.duration)
  2400. .style('opacity', 1)
  2401. .attr('x', function (d, i) {
  2402. if (d.resetSum === true) tsum[i] = 0;
  2403. tsum[i] += d.value;
  2404. return self.axes.hor.scale(tsum[i]);
  2405. });
  2406. bars.append('svg:title')
  2407. .text( function (d, i) { return uv.util.getTooltipText(self, self.categories[idx], self.labels[i], d);});
  2408. bargroup.attr('transform', 'translate(0,' + idx * self.axes.ver.scale.rangeBand() / len + ')');
  2409. };
  2410. uv.StepUpBarGraph.prototype.drawVerticalBars = function (idx, csum, tsum) {
  2411. var self = this, len = self.categories.length,
  2412. color = uv.util.getColorBand(self.config, idx),
  2413. bargroup = self.bargroups[self.categories[idx]],
  2414. scaledSum = 0;
  2415. var bars = bargroup.selectAll('g').data(self.graphdef.dataset[self.categories[idx]]).enter().append('g').classed('cge-' + uv.util.formatClassName(self.categories[idx]), true);
  2416. bars.append('rect')
  2417. .attr('height', 0)
  2418. .attr('width', self.axes.hor.scale.rangeBand() / len)
  2419. .attr('transform',
  2420. function (d) {
  2421. return (d.value < 0) ? 'scale(1,-1)': 'scale(1,1)';
  2422. })
  2423. .attr('x', function (d) { return self.axes.hor.scale(d.name); })
  2424. .attr('y', function (d, i) {
  2425. if (d.resetSum === true) csum[i] = 0;
  2426. var value = (2*self.height() - self.axes.ver.scale(csum[i]));
  2427. csum[i] += d.value;
  2428. return (d.value < 0)? -value: value;
  2429. })
  2430. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  2431. .style('stroke', 'none')
  2432. .style('fill', color)
  2433. .transition()
  2434. .duration(self.config.effects.duration)
  2435. .delay(idx * self.config.effects.duration)
  2436. .attr('height', function (d, i) {
  2437. return Math.abs(self.axes.ver.scale(-csum[i]) - self.axes.ver.scale(-csum[i]-d.value));
  2438. })
  2439. .call(uv.util.endAll, function (d,i){
  2440. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseover', uv.effects.bar.mouseover(self, idx));
  2441. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseout', uv.effects.bar.mouseout(self, idx));
  2442. });
  2443. bars.append('text').attr('transform','scale(1,-1)')
  2444. .attr('x', function(d) { return self.axes.hor.scale(d.name) + (self.axes.hor.scale.rangeBand()/len)/2; })
  2445. .attr('y', -self.height() - 10)
  2446. .attr('dy', function (d) { return (d.value < 0)? '2.3em': '.71em'})
  2447. .attr('text-anchor', 'middle')
  2448. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  2449. .style('fill', self.config.label.showlabel ? uv.util.getColorBand(self.config, idx) : 'none')
  2450. .style('font-family', self.config.bar.fontfamily)
  2451. .style('font-size', self.config.bar.fontsize)
  2452. .style('font-weight', self.config.bar.fontweight)
  2453. .style('opacity', 0)
  2454. .text(function(d) { return uv.util.getLabelValue(self, d); })
  2455. .transition()
  2456. .duration(self.config.effects.duration)
  2457. .delay(idx * self.config.effects.duration)
  2458. .style('opacity', 1)
  2459. .attr('y', function (d, i) {
  2460. if (d.resetSum === true) tsum[i] = 0;
  2461. tsum[i] += d.value;
  2462. return -(2*self.height() - self.axes.ver.scale(tsum[i])) - 10;
  2463. });
  2464. bars.append('svg:title')
  2465. .text( function (d, i) { return uv.util.getTooltipText(self, self.categories[idx], self.labels[i], d);});
  2466. bargroup.attr('transform', 'translate(' + idx * self.axes.hor.scale.rangeBand() / len + ',' + 2 * self.height() + ') scale(1,-1)');
  2467. };
  2468. uv.Table = function () {
  2469. this.caption = undefined;
  2470. this.position = undefined;
  2471. this.graphdef = undefined;
  2472. this.table = undefined;
  2473. this.header = undefined;
  2474. this.body = undefined;
  2475. this.bodyrows = {};
  2476. };
  2477. uv.Table.prototype.init = function (graphdef, config) {
  2478. this.graphdef = graphdef;
  2479. this.config = uv.util.extend({}, config);
  2480. this.position = this.config.meta.pos || 'body';
  2481. this.table = d3.select(this.position).append('table').classed(this.config.table.tableclass, true);
  2482. this.header = this.table.append('thead').classed(this.config.table.headerclass, true);
  2483. this.body = this.table.append('tbody').classed(this.config.table.bodyclass, true);
  2484. this.footer = this.table.append('tfoot').classed(this.config.table.footerclass, true);
  2485. };
  2486. uv.Table.prototype.finalize = function () {
  2487. //console.log(this);
  2488. };
  2489. uv.TableGraph = function (graphdef, config) {
  2490. uv.Table.apply(this, [graphdef]);
  2491. this.init(graphdef, config);
  2492. if (this.config.graph.orientation === 'Horizontal') {
  2493. this.setHorTable();
  2494. } else {
  2495. this.setVerTable();
  2496. }
  2497. this.finalize();
  2498. };
  2499. uv.TableGraph.prototype = uv.util.inherits(uv.Table);
  2500. uv.TableGraph.prototype.setHorTable = function () {
  2501. var categories = this.graphdef.categories, tableData = uv.util.getTabularArray(this.graphdef);
  2502. categories.unshift('');
  2503. this.header.append('tr').selectAll('td').data(categories).enter().append('td').text(function (d) { return d; });
  2504. categories.shift();
  2505. this.bodyrows = this.body.selectAll('tr').data(tableData)
  2506. .enter().append('tr');
  2507. this.bodyrows.selectAll('td').data(function (d, i) { return tableData[i]; })
  2508. .enter().append('td')
  2509. .attr('class', function (d, i) {
  2510. var classNameString = (i === 0) ? 'chart3rtablelabel' : 'chart3rtabledata';
  2511. return d3.select(this).attr('class') + classNameString;
  2512. })
  2513. .text(function (d) {return d; });
  2514. };
  2515. uv.TableGraph.prototype.setVerTable = function () {
  2516. var labels = uv.util.getLabelArray(this.graphdef), dataset = this.graphdef.dataset;
  2517. labels.unshift('');
  2518. this.header.append('tr').selectAll('td').data(labels).enter().append('td').text(function (d) { return d; });
  2519. labels.shift();
  2520. this.bodyrows = this.body.selectAll('tr').data(this.graphdef.categories)
  2521. .enter().append('tr');
  2522. this.bodyrows.selectAll('td')
  2523. .data(function (d) {
  2524. var arr = [], i, len;
  2525. arr.push(d);
  2526. for (i = 0, len = dataset[d].length; i < len; i = i + 1) { arr.push(dataset[d][i].value); }
  2527. return arr;
  2528. }).enter().append('td')
  2529. .attr('class', function (d, i) {
  2530. var classNameString = (i === 0) ? 'chart3rtablelabel' : 'chart3rtabledata';
  2531. return d3.select(this).attr('class') + classNameString;
  2532. })
  2533. .text(function (d) {return d; });
  2534. };
  2535. /**
  2536. * A waterfall chart capable of being rendered in horizontal and vertical manner
  2537. * @param {Object} graphdef Definition of the graph being rendered
  2538. * @param {Object} config Configuration of the graph being rendered
  2539. */
  2540. uv.WaterfallGraph = function (graphdef, config) {
  2541. var self = this;
  2542. uv.Graph.call(self, graphdef, config).setDefaults().init();
  2543. self.bargroups = {};
  2544. self.axes[self.config.graph.orientation === 'Horizontal' ? 'ver' : 'hor'].scale.domain(self.labels);
  2545. var idx, length = self.categories.length, category;
  2546. category = self.categories[0];
  2547. self.bargroups[category] = self.chart.append('g').classed('cg-' + uv.util.formatClassName(category), true);
  2548. self['draw' + self.config.graph.orientation + 'Bars'](0);
  2549. self.finalize();
  2550. };
  2551. uv.WaterfallGraph.prototype = uv.util.inherits(uv.Graph);
  2552. uv.WaterfallGraph.prototype.setDefaults = function () {
  2553. var self = this;
  2554. self.graphdef.stepup = 'waterfall';
  2555. self.config.legend.showlegends = false;
  2556. return this;
  2557. };
  2558. uv.WaterfallGraph.prototype.drawHorizontalBars = function (idx) {
  2559. var self = this, len = self.categories.length,
  2560. color = uv.util.getColorBand(self.config, idx),
  2561. bargroup = self.bargroups[self.categories[idx]];
  2562. var csum = 0, tsum =0;
  2563. var bars = bargroup.selectAll('g').data(self.graphdef.dataset[self.categories[idx]]).enter().append('g').classed('cge-' + uv.util.formatClassName(self.categories[idx]), true);
  2564. bars.append('rect')
  2565. .attr('height', (self.axes.ver.scale.rangeBand() / len)-2)
  2566. .attr('width', 0)
  2567. .attr('x', function (d, i) {
  2568. var value = (d.value < 0) ? csum + d.value : csum;
  2569. csum += d.value;
  2570. return self.axes.hor.scale(value); })
  2571. .attr('y', function (d) {return self.axes.ver.scale(d.name); })
  2572. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  2573. .style('stroke', 'none')
  2574. .style('fill', color)
  2575. .transition()
  2576. .duration(self.config.effects.duration)
  2577. .delay(idx * self.config.effects.duration)
  2578. .attr('width', function (d) { return self.axes.hor.scale(Math.abs(d.value)); })
  2579. .call(uv.util.endAll, function (d,i){
  2580. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseover', uv.effects.bar.mouseover(self, idx));
  2581. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseout', uv.effects.bar.mouseout(self, idx));
  2582. });
  2583. bars.append('text')
  2584. .attr('y', function(d) { return self.axes.ver.scale(d.name) + (self.axes.ver.scale.rangeBand()/len)/2; })
  2585. .attr('dx', 4)
  2586. .attr('dy', '.35em')
  2587. .attr('text-anchor', 'start')
  2588. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  2589. .style('fill', self.config.label.showlabel ? uv.util.getColorBand(self.config, idx) : 'none')
  2590. .style('font-family', self.config.bar.fontfamily)
  2591. .style('font-size', self.config.bar.fontsize)
  2592. .style('font-weight', self.config.bar.fontweight)
  2593. .text(function(d) { return uv.util.getLabelValue(self, d); })
  2594. .transition()
  2595. .duration(self.config.effects.duration)
  2596. .delay(idx * self.config.effects.duration)
  2597. .attr('x', function (d, i) {
  2598. var value = d.value < 0 ? tsum : tsum + d.value;
  2599. tsum += d.value;
  2600. return self.axes.hor.scale(value);
  2601. });
  2602. bars.append('svg:title')
  2603. .text( function (d, i) { return uv.util.getTooltipText(self, self.categories[idx], self.labels[i], d);});
  2604. bargroup.attr('transform', 'translate(0,' + idx * self.axes.ver.scale.rangeBand() / len + ')');
  2605. };
  2606. uv.WaterfallGraph.prototype.drawVerticalBars = function (idx) {
  2607. var self = this,
  2608. color = uv.util.getColorBand(this.config, idx),
  2609. len = self.categories.length;
  2610. var csum =0, tsum = 0;
  2611. var bars = self.bargroups[self.categories[idx]].selectAll('g').data(self.graphdef.dataset[self.categories[idx]]).enter()
  2612. .append('g').classed('cge-' + uv.util.formatClassName(self.categories[idx]), true);
  2613. bars.append('rect')
  2614. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  2615. .attr('height', 0)
  2616. .attr('width', 0)
  2617. .attr('x', function (d) {return self.axes.hor.scale(d.name); })
  2618. .attr('y', function(d) {
  2619. var value = (d.value < 0) ? csum + d.value : csum;
  2620. csum += d.value;
  2621. return self.height() - self.axes.ver.scale(value);
  2622. })
  2623. .style('stroke', self.config.bar.strokecolor).style('fill', color)
  2624. .transition()
  2625. .duration(self.config.effects.duration)
  2626. .delay(idx * self.config.effects.duration)
  2627. .attr('height', function (d) { return self.height() - self.axes.ver.scale(Math.abs(d.value)); })
  2628. .attr('width', (self.axes.hor.scale.rangeBand() / len)-2)
  2629. .call(uv.util.endAll, function (d,i){
  2630. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseover', uv.effects.bar.mouseover(self, idx));
  2631. d3.select(this.parentNode.parentNode).selectAll('rect').on('mouseout', uv.effects.bar.mouseout(self, idx));
  2632. });
  2633. bars.append('text').attr('transform','scale(1,-1)')
  2634. .attr('x', function(d) { return self.axes.hor.scale(d.name) + (self.axes.hor.scale.rangeBand()/len)/2; })
  2635. .attr('y', -10)
  2636. .attr('dx', 0)
  2637. .attr('dy', '.35em')
  2638. .attr('text-anchor', 'middle')
  2639. .classed('cr-' + uv.util.formatClassName(self.categories[idx]), true)
  2640. .style('fill', self.config.label.showlabel ? uv.util.getColorBand(self.config, idx) : 'none')
  2641. .style('font-family', self.config.bar.fontfamily)
  2642. .style('font-size', self.config.bar.fontsize)
  2643. .style('font-weight', self.config.bar.fontweight)
  2644. .text(function(d) { return uv.util.getLabelValue(self, d); })
  2645. .transition()
  2646. .duration(self.config.effects.duration)
  2647. .delay(idx * self.config.effects.duration)
  2648. .attr('y', function (d) {
  2649. tsum += d.value;
  2650. var value = d.value < 0 ? tsum - d.value : tsum;
  2651. return -(self.height() - self.axes.ver.scale(value)) - 10; });
  2652. bars.append('svg:title')
  2653. .text( function (d, i) { return uv.util.getTooltipText(self, self.categories[idx], self.labels[i], d);});
  2654. self.bargroups[self.categories[idx]].attr('transform', 'translate(' + idx * self.axes.hor.scale.rangeBand() / len + ',' + self.height() + ') scale(1,-1)');
  2655. };
  2656. if (!noGlobal) {
  2657. window.uv = {
  2658. chart: uv.chart
  2659. };
  2660. }
  2661. return {
  2662. chart: uv.chart
  2663. };
  2664. }));