dashboard_boxed.js 98 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988
  1. /* ------------------------------------------------------------------------------
  2. *
  3. * # Dashboard configuration for boxed layout
  4. *
  5. * Demo dashboard configuration. Contains charts and plugin initializations
  6. *
  7. * ---------------------------------------------------------------------------- */
  8. // Setup module
  9. // ------------------------------
  10. var Dashboard = function () {
  11. //
  12. // Setup module components
  13. //
  14. // Setup Switchery
  15. var _componentSwitchery = function() {
  16. if (typeof Switchery == 'undefined') {
  17. console.warn('Warning - switchery.min.js is not loaded.');
  18. return;
  19. }
  20. // Initialize multiple switches
  21. var switches = Array.prototype.slice.call(document.querySelectorAll('.form-input-switchery'));
  22. switches.forEach(function(html) {
  23. var switchery = new Switchery(html);
  24. });
  25. };
  26. // Setup Daterangepicker
  27. var _componentDaterange = function() {
  28. if (!$().daterangepicker) {
  29. console.warn('Warning - daterangepicker.js is not loaded.');
  30. return;
  31. }
  32. // Initialize
  33. $('.daterange-ranges').daterangepicker(
  34. {
  35. startDate: moment().subtract(29, 'days'),
  36. endDate: moment(),
  37. minDate: '01/01/2015',
  38. maxDate: '12/31/2019',
  39. dateLimit: { days: 60 },
  40. ranges: {
  41. 'Today': [moment(), moment()],
  42. 'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
  43. 'Last 7 Days': [moment().subtract(6, 'days'), moment()],
  44. 'Last 30 Days': [moment().subtract(29, 'days'), moment()],
  45. 'This Month': [moment().startOf('month'), moment().endOf('month')],
  46. 'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
  47. },
  48. opens: $('html').attr('dir') == 'rtl' ? 'right' : 'left',
  49. applyClass: 'btn-sm bg-slate-600 btn-block',
  50. cancelClass: 'btn-sm btn-light btn-block',
  51. locale: {
  52. format: 'MM/DD/YYYY',
  53. direction: $('html').attr('dir') == 'rtl' ? 'rtl' : 'ltr'
  54. }
  55. },
  56. function(start, end) {
  57. $('.daterange-ranges span').html(start.format('MMMM D') + ' - ' + end.format('MMMM D'));
  58. }
  59. );
  60. $('.daterange-ranges span').html(moment().subtract(29, 'days').format('MMMM D') + ' - ' + moment().format('MMMM D'));
  61. };
  62. // Use first letter as an icon
  63. var _componentIconLetter = function() {
  64. // Grab first letter and insert to the icon
  65. $('.table tr').each(function() {
  66. // Title
  67. var $title = $(this).find('.letter-icon-title'),
  68. letter = $title.eq(0).text().charAt(0).toUpperCase();
  69. // Icon
  70. var $icon = $(this).find('.letter-icon');
  71. $icon.eq(0).text(letter);
  72. });
  73. };
  74. //
  75. // Charts configs
  76. //
  77. // Traffic sources stream chart
  78. var _TrafficSourcesStreamChart = function(element, height) {
  79. if (typeof d3 == 'undefined') {
  80. console.warn('Warning - d3.min.js is not loaded.');
  81. return;
  82. }
  83. // Initialize chart only if element exsists in the DOM
  84. if($(element).length > 0) {
  85. // Basic setup
  86. // ------------------------------
  87. // Define main variables
  88. var d3Container = d3.select(element),
  89. margin = {top: 5, right: 50, bottom: 40, left: 50},
  90. width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right,
  91. height = height - margin.top - margin.bottom,
  92. tooltipOffset = 30;
  93. // Tooltip
  94. var tooltip = d3Container
  95. .append('div')
  96. .attr('class', 'd3-tip e')
  97. .style('display', 'none')
  98. // Format date
  99. var format = d3.time.format('%m/%d/%y %H:%M');
  100. var formatDate = d3.time.format('%H:%M');
  101. // Colors
  102. var colorrange = ['#03A9F4', '#29B6F6', '#4FC3F7', '#81D4FA', '#B3E5FC', '#E1F5FE'];
  103. // Construct scales
  104. // ------------------------------
  105. // Horizontal
  106. var x = d3.time.scale().range([0, width]);
  107. // Vertical
  108. var y = d3.scale.linear().range([height, 0]);
  109. // Colors
  110. var z = d3.scale.ordinal().range(colorrange);
  111. // Create axes
  112. // ------------------------------
  113. // Horizontal
  114. var xAxis = d3.svg.axis()
  115. .scale(x)
  116. .orient('bottom')
  117. .ticks(d3.time.hours, 4)
  118. .innerTickSize(4)
  119. .tickPadding(8)
  120. .tickFormat(d3.time.format('%H:%M')); // Display hours and minutes in 24h format
  121. // Left vertical
  122. var yAxis = d3.svg.axis()
  123. .scale(y)
  124. .ticks(6)
  125. .innerTickSize(4)
  126. .outerTickSize(0)
  127. .tickPadding(8)
  128. .tickFormat(function (d) { return (d/1000) + 'k'; });
  129. // Right vertical
  130. var yAxis2 = yAxis;
  131. // Dash lines
  132. var gridAxis = d3.svg.axis()
  133. .scale(y)
  134. .orient('left')
  135. .ticks(6)
  136. .tickPadding(8)
  137. .tickFormat('')
  138. .tickSize(-width, 0, 0);
  139. // Create chart
  140. // ------------------------------
  141. // Container
  142. var container = d3Container.append('svg')
  143. // SVG element
  144. var svg = container
  145. .attr('width', width + margin.left + margin.right)
  146. .attr('height', height + margin.top + margin.bottom)
  147. .append('g')
  148. .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  149. // Construct chart layout
  150. // ------------------------------
  151. // Stack
  152. var stack = d3.layout.stack()
  153. .offset('silhouette')
  154. .values(function(d) { return d.values; })
  155. .x(function(d) { return d.date; })
  156. .y(function(d) { return d.value; });
  157. // Nest
  158. var nest = d3.nest()
  159. .key(function(d) { return d.key; });
  160. // Area
  161. var area = d3.svg.area()
  162. .interpolate('cardinal')
  163. .x(function(d) { return x(d.date); })
  164. .y0(function(d) { return y(d.y0); })
  165. .y1(function(d) { return y(d.y0 + d.y); });
  166. // Load data
  167. // ------------------------------
  168. d3.csv('../../../../global_assets/demo_data/dashboard/traffic_sources.csv', function (error, data) {
  169. // Pull out values
  170. data.forEach(function (d) {
  171. d.date = format.parse(d.date);
  172. d.value = +d.value;
  173. });
  174. // Stack and nest layers
  175. var layers = stack(nest.entries(data));
  176. // Set input domains
  177. // ------------------------------
  178. // Horizontal
  179. x.domain(d3.extent(data, function(d, i) { return d.date; }));
  180. // Vertical
  181. y.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]);
  182. // Add grid
  183. // ------------------------------
  184. // Horizontal grid. Must be before the group
  185. svg.append('g')
  186. .attr('class', 'd3-grid-dashed')
  187. .call(gridAxis);
  188. //
  189. // Append chart elements
  190. //
  191. // Stream layers
  192. // ------------------------------
  193. // Create group
  194. var group = svg.append('g')
  195. .attr('class', 'streamgraph-layers-group');
  196. // And append paths to this group
  197. var layer = group.selectAll('.streamgraph-layer')
  198. .data(layers)
  199. .enter()
  200. .append('path')
  201. .attr('class', 'streamgraph-layer')
  202. .attr('d', function(d) { return area(d.values); })
  203. .style('stroke', '#fff')
  204. .style('stroke-width', 0.5)
  205. .style('fill', function(d, i) { return z(i); });
  206. // Add transition
  207. var layerTransition = layer
  208. .style('opacity', 0)
  209. .transition()
  210. .duration(750)
  211. .delay(function(d, i) { return i * 50; })
  212. .style('opacity', 1)
  213. // Append axes
  214. // ------------------------------
  215. //
  216. // Left vertical
  217. //
  218. svg.append('g')
  219. .attr('class', 'd3-axis d3-axis-left d3-axis-solid')
  220. .call(yAxis.orient('left'));
  221. // Hide first tick
  222. d3.select(svg.selectAll('.d3-axis-left .tick text')[0][0])
  223. .style('visibility', 'hidden');
  224. //
  225. // Right vertical
  226. //
  227. svg.append('g')
  228. .attr('class', 'd3-axis d3-axis-right d3-axis-solid')
  229. .attr('transform', 'translate(' + width + ', 0)')
  230. .call(yAxis2.orient('right'));
  231. // Hide first tick
  232. d3.select(svg.selectAll('.d3-axis-right .tick text')[0][0])
  233. .style('visibility', 'hidden');
  234. //
  235. // Horizontal
  236. //
  237. var xaxisg = svg.append('g')
  238. .attr('class', 'd3-axis d3-axis-horizontal d3-axis-solid')
  239. .attr('transform', 'translate(0,' + height + ')')
  240. .call(xAxis);
  241. // Add extra subticks for hidden hours
  242. xaxisg.selectAll('.d3-axis-subticks')
  243. .data(x.ticks(d3.time.hours), function(d) { return d; })
  244. .enter()
  245. .append('line')
  246. .attr('class', 'd3-axis-subticks')
  247. .attr('y1', 0)
  248. .attr('y2', 4)
  249. .attr('x1', x)
  250. .attr('x2', x);
  251. // Add hover line and pointer
  252. // ------------------------------
  253. // Append group to the group of paths to prevent appearance outside chart area
  254. var hoverLineGroup = group.append('g')
  255. .attr('class', 'hover-line');
  256. // Add line
  257. var hoverLine = hoverLineGroup
  258. .append('line')
  259. .attr('y1', 0)
  260. .attr('y2', height)
  261. .style('fill', 'none')
  262. .style('stroke', '#fff')
  263. .style('stroke-width', 1)
  264. .style('pointer-events', 'none')
  265. .style('shape-rendering', 'crispEdges')
  266. .style('opacity', 0);
  267. // Add pointer
  268. var hoverPointer = hoverLineGroup
  269. .append('rect')
  270. .attr('x', 2)
  271. .attr('y', 2)
  272. .attr('width', 6)
  273. .attr('height', 6)
  274. .style('fill', '#03A9F4')
  275. .style('stroke', '#fff')
  276. .style('stroke-width', 1)
  277. .style('shape-rendering', 'crispEdges')
  278. .style('pointer-events', 'none')
  279. .style('opacity', 0);
  280. // Append events to the layers group
  281. // ------------------------------
  282. layerTransition.each('end', function() {
  283. layer
  284. .on('mouseover', function (d, i) {
  285. svg.selectAll('.streamgraph-layer')
  286. .transition()
  287. .duration(250)
  288. .style('opacity', function (d, j) {
  289. return j != i ? 0.75 : 1; // Mute all except hovered
  290. });
  291. })
  292. .on('mousemove', function (d, i) {
  293. mouse = d3.mouse(this);
  294. mousex = mouse[0];
  295. mousey = mouse[1];
  296. datearray = [];
  297. var invertedx = x.invert(mousex);
  298. invertedx = invertedx.getHours();
  299. var selected = (d.values);
  300. for (var k = 0; k < selected.length; k++) {
  301. datearray[k] = selected[k].date
  302. datearray[k] = datearray[k].getHours();
  303. }
  304. mousedate = datearray.indexOf(invertedx);
  305. pro = d.values[mousedate].value;
  306. // Display mouse pointer
  307. hoverPointer
  308. .attr('x', mousex - 3)
  309. .attr('y', mousey - 6)
  310. .style('opacity', 1);
  311. hoverLine
  312. .attr('x1', mousex)
  313. .attr('x2', mousex)
  314. .style('opacity', 1);
  315. //
  316. // Tooltip
  317. //
  318. // Tooltip data
  319. tooltip.html(
  320. '<ul class="list-unstyled mb-1">' +
  321. '<li>' + '<div class="font-size-base my-1"><i class="icon-circle-left2 mr-2"></i>' + d.key + '</div>' + '</li>' +
  322. '<li>' + 'Visits: &nbsp;' + "<span class='font-weight-semibold float-right'>" + pro + '</span>' + '</li>' +
  323. '<li>' + 'Time: &nbsp; ' + '<span class="font-weight-semibold float-right">' + formatDate(d.values[mousedate].date) + '</span>' + '</li>' +
  324. '</ul>'
  325. )
  326. .style('display', 'block');
  327. // Tooltip arrow
  328. tooltip.append('div').attr('class', 'd3-tip-arrow');
  329. })
  330. .on('mouseout', function (d, i) {
  331. // Revert full opacity to all paths
  332. svg.selectAll('.streamgraph-layer')
  333. .transition()
  334. .duration(250)
  335. .style('opacity', 1);
  336. // Hide cursor pointer
  337. hoverPointer.style('opacity', 0);
  338. // Hide tooltip
  339. tooltip.style('display', 'none');
  340. hoverLine.style('opacity', 0);
  341. });
  342. });
  343. // Append events to the chart container
  344. // ------------------------------
  345. d3Container
  346. .on('mousemove', function (d, i) {
  347. mouse = d3.mouse(this);
  348. mousex = mouse[0];
  349. mousey = mouse[1];
  350. // Move tooltip vertically
  351. tooltip.style('top', (mousey - ($('.d3-tip').outerHeight() / 2)) - 2 + 'px') // Half tooltip height - half arrow width
  352. // Move tooltip horizontally
  353. if(mousex >= ($(element).outerWidth() - $('.d3-tip').outerWidth() - margin.right - (tooltipOffset * 2))) {
  354. tooltip
  355. .style('left', (mousex - $('.d3-tip').outerWidth() - tooltipOffset) + 'px') // Change tooltip direction from right to left to keep it inside graph area
  356. .attr('class', 'd3-tip w');
  357. }
  358. else {
  359. tooltip
  360. .style('left', (mousex + tooltipOffset) + 'px' )
  361. .attr('class', 'd3-tip e');
  362. }
  363. });
  364. });
  365. // Resize chart
  366. // ------------------------------
  367. // Call function on window resize
  368. $(window).on('resize', resizeStream);
  369. // Call function on sidebar width change
  370. $(document).on('click', '.sidebar-control', resizeStream);
  371. // Resize function
  372. //
  373. // Since D3 doesn't support SVG resize by default,
  374. // we need to manually specify parts of the graph that need to
  375. // be updated on window resize
  376. function resizeStream() {
  377. // Layout
  378. // -------------------------
  379. // Define width
  380. width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right;
  381. // Main svg width
  382. container.attr('width', width + margin.left + margin.right);
  383. // Width of appended group
  384. svg.attr('width', width + margin.left + margin.right);
  385. // Horizontal range
  386. x.range([0, width]);
  387. // Chart elements
  388. // -------------------------
  389. // Horizontal axis
  390. svg.selectAll('.d3-axis-horizontal').call(xAxis);
  391. // Horizontal axis subticks
  392. svg.selectAll('.d3-axis-subticks').attr('x1', x).attr('x2', x);
  393. // Grid lines width
  394. svg.selectAll('.d3-grid-dashed').call(gridAxis.tickSize(-width, 0, 0))
  395. // Right vertical axis
  396. svg.selectAll('.d3-axis-right').attr('transform', 'translate(' + width + ', 0)');
  397. // Area paths
  398. svg.selectAll('.streamgraph-layer').attr('d', function(d) { return area(d.values); });
  399. }
  400. }
  401. };
  402. // App sales line chart
  403. var _AppSalesLinesChart = function(element, height) {
  404. if (typeof d3 == 'undefined' || typeof d3.tip == 'undefined') {
  405. console.warn('Warning - d3.min.js is not loaded.');
  406. return;
  407. }
  408. // Initialize chart only if element exsists in the DOM
  409. if($(element).length > 0) {
  410. // Basic setup
  411. // ------------------------------
  412. // Define main variables
  413. var d3Container = d3.select(element),
  414. margin = {top: 5, right: 30, bottom: 30, left: 50},
  415. width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right,
  416. height = height - margin.top - margin.bottom;
  417. // Tooltip
  418. var tooltip = d3.tip()
  419. .attr('class', 'd3-tip')
  420. .html(function (d) {
  421. return '<ul class="list-unstyled mb-1">' +
  422. '<li>' + '<div class="font-size-base my-1"><i class="icon-circle-left2 mr-2"></i>' + d.name + ' app' + '</div>' + '</li>' +
  423. '<li>' + 'Sales: &nbsp;' + '<span class="font-weight-semibold float-right">' + d.value + '</span>' + '</li>' +
  424. '<li>' + 'Revenue: &nbsp; ' + '<span class="font-weight-semibold float-right">' + '$' + (d.value * 25).toFixed(2) + '</span>' + '</li>' +
  425. '</ul>';
  426. });
  427. // Format date
  428. var parseDate = d3.time.format('%Y/%m/%d').parse,
  429. formatDate = d3.time.format('%b %d, %y');
  430. // Line colors
  431. var scale = ['#4CAF50', '#FF5722', '#5C6BC0'],
  432. color = d3.scale.ordinal().range(scale);
  433. // Create chart
  434. // ------------------------------
  435. // Container
  436. var container = d3Container.append('svg');
  437. // SVG element
  438. var svg = container
  439. .attr('width', width + margin.left + margin.right)
  440. .attr('height', height + margin.top + margin.bottom)
  441. .append('g')
  442. .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
  443. .call(tooltip);
  444. // Add date range switcher
  445. // ------------------------------
  446. // Menu
  447. var menu = $('#select_date').multiselect({
  448. buttonClass: 'text-default font-weight-semibold bg-transparent border-0 cursor-pointer outline-0 py-0 pl-0',
  449. enableHTML: true,
  450. dropRight: $('html').attr('dir') == 'rtl' ? false : true,
  451. onChange: function() {
  452. change();
  453. },
  454. buttonText: function (options, element) {
  455. var selected = '';
  456. options.each(function() {
  457. selected += $(this).html() + ', ';
  458. });
  459. return '<span class="badge badge-mark border-warning mr-2"></span>' + selected.substr(0, selected.length -2);
  460. }
  461. });
  462. // Load data
  463. // ------------------------------
  464. d3.csv('../../../../global_assets/demo_data/dashboard/app_sales.csv', function(error, data) {
  465. formatted = data;
  466. redraw();
  467. });
  468. // Construct layout
  469. // ------------------------------
  470. // Add events
  471. var altKey;
  472. d3.select(window)
  473. .on('keydown', function() { altKey = d3.event.altKey; })
  474. .on('keyup', function() { altKey = false; });
  475. // Set terms of transition on date change
  476. function change() {
  477. d3.transition()
  478. .duration(altKey ? 7500 : 500)
  479. .each(redraw);
  480. }
  481. // Main chart drawing function
  482. // ------------------------------
  483. function redraw() {
  484. // Construct chart layout
  485. // ------------------------------
  486. // Create data nests
  487. var nested = d3.nest()
  488. .key(function(d) { return d.type; })
  489. .map(formatted)
  490. // Get value from menu selection
  491. // the option values correspond
  492. //to the [type] value we used to nest the data
  493. var series = menu.val();
  494. // Only retrieve data from the selected series using nest
  495. var data = nested[series];
  496. // For object constancy we will need to set 'keys', one for each type of data (column name) exclude all others.
  497. color.domain(d3.keys(data[0]).filter(function(key) { return (key !== 'date' && key !== 'type'); }));
  498. // Setting up color map
  499. var linedata = color.domain().map(function(name) {
  500. return {
  501. name: name,
  502. values: data.map(function(d) {
  503. return {name: name, date: parseDate(d.date), value: parseFloat(d[name], 10)};
  504. })
  505. };
  506. });
  507. // Draw the line
  508. var line = d3.svg.line()
  509. .x(function(d) { return x(d.date); })
  510. .y(function(d) { return y(d.value); })
  511. .interpolate('cardinal');
  512. // Construct scales
  513. // ------------------------------
  514. // Horizontal
  515. var x = d3.time.scale()
  516. .domain([
  517. d3.min(linedata, function(c) { return d3.min(c.values, function(v) { return v.date; }); }),
  518. d3.max(linedata, function(c) { return d3.max(c.values, function(v) { return v.date; }); })
  519. ])
  520. .range([0, width]);
  521. // Vertical
  522. var y = d3.scale.linear()
  523. .domain([
  524. d3.min(linedata, function(c) { return d3.min(c.values, function(v) { return v.value; }); }),
  525. d3.max(linedata, function(c) { return d3.max(c.values, function(v) { return v.value; }); })
  526. ])
  527. .range([height, 0]);
  528. // Create axes
  529. // ------------------------------
  530. // Horizontal
  531. var xAxis = d3.svg.axis()
  532. .scale(x)
  533. .orient('bottom')
  534. .tickPadding(8)
  535. .ticks(d3.time.days)
  536. .innerTickSize(4)
  537. .tickFormat(d3.time.format('%a')); // Display hours and minutes in 24h format
  538. // Vertical
  539. var yAxis = d3.svg.axis()
  540. .scale(y)
  541. .orient('left')
  542. .ticks(6)
  543. .tickSize(0 -width)
  544. .tickPadding(8);
  545. //
  546. // Append chart elements
  547. //
  548. // Append axes
  549. // ------------------------------
  550. // Horizontal
  551. svg.append('g')
  552. .attr('class', 'd3-axis d3-axis-horizontal d3-axis-solid')
  553. .attr('transform', 'translate(0,' + height + ')');
  554. // Vertical
  555. svg.append('g')
  556. .attr('class', 'd3-axis d3-axis-vertical d3-axis-transparent');
  557. // Append lines
  558. // ------------------------------
  559. // Bind the data
  560. var lines = svg.selectAll('.lines')
  561. .data(linedata)
  562. // Append a group tag for each line
  563. var lineGroup = lines
  564. .enter()
  565. .append('g')
  566. .attr('class', 'lines')
  567. .attr('id', function(d){ return d.name + '-line'; });
  568. // Append the line to the graph
  569. lineGroup.append('path')
  570. .attr('class', 'd3-line d3-line-medium')
  571. .style('stroke', function(d) { return color(d.name); })
  572. .style('opacity', 0)
  573. .attr('d', function(d) { return line(d.values[0]); })
  574. .transition()
  575. .duration(500)
  576. .delay(function(d, i) { return i * 200; })
  577. .style('opacity', 1);
  578. // Append circles
  579. // ------------------------------
  580. var circles = lines.selectAll('circle')
  581. .data(function(d) { return d.values; })
  582. .enter()
  583. .append('circle')
  584. .attr('class', 'd3-line-circle d3-line-circle-medium')
  585. .attr('cx', function(d,i){return x(d.date)})
  586. .attr('cy',function(d,i){return y(d.value)})
  587. .attr('r', 3)
  588. .style('fill', '#fff')
  589. .style('stroke', function(d) { return color(d.name); });
  590. // Add transition
  591. circles
  592. .style('opacity', 0)
  593. .transition()
  594. .duration(500)
  595. .delay(500)
  596. .style('opacity', 1);
  597. // Append tooltip
  598. // ------------------------------
  599. // Add tooltip on circle hover
  600. circles
  601. .on('mouseover', function (d) {
  602. tooltip.offset([-15, 0]).show(d);
  603. // Animate circle radius
  604. d3.select(this).transition().duration(250).attr('r', 4);
  605. })
  606. .on('mouseout', function (d) {
  607. tooltip.hide(d);
  608. // Animate circle radius
  609. d3.select(this).transition().duration(250).attr('r', 3);
  610. });
  611. // Change tooltip direction of first point
  612. // to always keep it inside chart, useful on mobiles
  613. lines.each(function (d) {
  614. d3.select(d3.select(this).selectAll('circle')[0][0])
  615. .on('mouseover', function (d) {
  616. tooltip.offset([0, 15]).direction('e').show(d);
  617. // Animate circle radius
  618. d3.select(this).transition().duration(250).attr('r', 4);
  619. })
  620. .on('mouseout', function (d) {
  621. tooltip.direction('n').hide(d);
  622. // Animate circle radius
  623. d3.select(this).transition().duration(250).attr('r', 3);
  624. });
  625. })
  626. // Change tooltip direction of last point
  627. // to always keep it inside chart, useful on mobiles
  628. lines.each(function (d) {
  629. d3.select(d3.select(this).selectAll('circle')[0][d3.select(this).selectAll('circle').size() - 1])
  630. .on('mouseover', function (d) {
  631. tooltip.offset([0, -15]).direction('w').show(d);
  632. // Animate circle radius
  633. d3.select(this).transition().duration(250).attr('r', 4);
  634. })
  635. .on('mouseout', function (d) {
  636. tooltip.direction('n').hide(d);
  637. // Animate circle radius
  638. d3.select(this).transition().duration(250).attr('r', 3);
  639. })
  640. })
  641. // Update chart on date change
  642. // ------------------------------
  643. // Set variable for updating visualization
  644. var lineUpdate = d3.transition(lines);
  645. // Update lines
  646. lineUpdate.select('path')
  647. .attr('d', function(d, i) { return line(d.values); });
  648. // Update circles
  649. lineUpdate.selectAll('circle')
  650. .attr('cy',function(d,i){return y(d.value)})
  651. .attr('cx', function(d,i){return x(d.date)});
  652. // Update vertical axes
  653. d3.transition(svg)
  654. .select('.d3-axis-vertical')
  655. .call(yAxis);
  656. // Update horizontal axes
  657. d3.transition(svg)
  658. .select('.d3-axis-horizontal')
  659. .attr('transform', 'translate(0,' + height + ')')
  660. .call(xAxis);
  661. // Resize chart
  662. // ------------------------------
  663. // Call function on window resize
  664. $(window).on('resize', appSalesResize);
  665. // Call function on sidebar width change
  666. $(document).on('click', '.sidebar-control', appSalesResize);
  667. // Resize function
  668. //
  669. // Since D3 doesn't support SVG resize by default,
  670. // we need to manually specify parts of the graph that need to
  671. // be updated on window resize
  672. function appSalesResize() {
  673. // Layout
  674. // -------------------------
  675. // Define width
  676. width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right;
  677. // Main svg width
  678. container.attr('width', width + margin.left + margin.right);
  679. // Width of appended group
  680. svg.attr('width', width + margin.left + margin.right);
  681. // Horizontal range
  682. x.range([0, width]);
  683. // Vertical range
  684. y.range([height, 0]);
  685. // Chart elements
  686. // -------------------------
  687. // Horizontal axis
  688. svg.select('.d3-axis-horizontal').call(xAxis);
  689. // Vertical axis
  690. svg.select('.d3-axis-vertical').call(yAxis.tickSize(0-width));
  691. // Lines
  692. svg.selectAll('.d3-line').attr('d', function(d, i) { return line(d.values); });
  693. // Circles
  694. svg.selectAll('.d3-line-circle').attr('cx', function(d,i){return x(d.date)})
  695. }
  696. }
  697. }
  698. };
  699. // Monthly sales area chart
  700. var _MonthlySalesAreaChart = function(element, height, color) {
  701. if (typeof d3 == 'undefined') {
  702. console.warn('Warning - d3.min.js is not loaded.');
  703. return;
  704. }
  705. // Initialize chart only if element exsists in the DOM
  706. if($(element).length > 0) {
  707. // Basic setup
  708. // ------------------------------
  709. // Define main variables
  710. var d3Container = d3.select(element),
  711. margin = {top: 20, right: 35, bottom: 40, left: 35},
  712. width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right,
  713. height = height - margin.top - margin.bottom;
  714. // Date and time format
  715. var parseDate = d3.time.format('%Y-%m-%d').parse,
  716. bisectDate = d3.bisector(function(d) { return d.date; }).left,
  717. formatDate = d3.time.format('%b %d');
  718. // Create SVG
  719. // ------------------------------
  720. // Container
  721. var container = d3Container.append('svg');
  722. // SVG element
  723. var svg = container
  724. .attr('width', width + margin.left + margin.right)
  725. .attr('height', height + margin.top + margin.bottom)
  726. .append('g')
  727. .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
  728. // Construct chart layout
  729. // ------------------------------
  730. // Area
  731. var area = d3.svg.area()
  732. .x(function(d) { return x(d.date); })
  733. .y0(height)
  734. .y1(function(d) { return y(d.value); })
  735. .interpolate('monotone')
  736. // Construct scales
  737. // ------------------------------
  738. // Horizontal
  739. var x = d3.time.scale().range([0, width ]);
  740. // Vertical
  741. var y = d3.scale.linear().range([height, 0]);
  742. // Create axes
  743. // ------------------------------
  744. // Horizontal
  745. var xAxis = d3.svg.axis()
  746. .scale(x)
  747. .orient('bottom')
  748. .ticks(d3.time.days, 6)
  749. .innerTickSize(4)
  750. .tickPadding(8)
  751. .tickFormat(d3.time.format('%b %d'));
  752. // Load data
  753. // ------------------------------
  754. d3.json('../../../../global_assets/demo_data/dashboard/monthly_sales.json', function (error, data) {
  755. // Show what's wrong if error
  756. if (error) return console.error(error);
  757. // Pull out values
  758. data.forEach(function (d) {
  759. d.date = parseDate(d.date);
  760. d.value = +d.value;
  761. });
  762. // Get the maximum value in the given array
  763. var maxY = d3.max(data, function(d) { return d.value; });
  764. // Reset start data for animation
  765. var startData = data.map(function(datum) {
  766. return {
  767. date: datum.date,
  768. value: 0
  769. };
  770. });
  771. // Set input domains
  772. // ------------------------------
  773. // Horizontal
  774. x.domain(d3.extent(data, function(d, i) { return d.date; }));
  775. // Vertical
  776. y.domain([0, d3.max( data, function(d) { return d.value; })]);
  777. //
  778. // Append chart elements
  779. //
  780. // Append axes
  781. // -------------------------
  782. // Horizontal
  783. var horizontalAxis = svg.append('g')
  784. .attr('class', 'd3-axis d3-axis-horizontal d3-axis-solid')
  785. .attr('transform', 'translate(0,' + height + ')')
  786. .call(xAxis);
  787. // Add extra subticks for hidden hours
  788. horizontalAxis.selectAll('.d3-axis-subticks')
  789. .data(x.ticks(d3.time.days), function(d) { return d; })
  790. .enter()
  791. .append('line')
  792. .attr('class', 'd3-axis-subticks')
  793. .attr('y1', 0)
  794. .attr('y2', 4)
  795. .attr('x1', x)
  796. .attr('x2', x);
  797. // Append area
  798. // -------------------------
  799. // Add area path
  800. svg.append('path')
  801. .datum(data)
  802. .attr('class', 'd3-area')
  803. .attr('d', area)
  804. .style('fill', color)
  805. .transition() // begin animation
  806. .duration(1000)
  807. .attrTween('d', function() {
  808. var interpolator = d3.interpolateArray(startData, data);
  809. return function (t) {
  810. return area(interpolator (t));
  811. }
  812. });
  813. // Append crosshair and tooltip
  814. // -------------------------
  815. //
  816. // Line
  817. //
  818. // Line group
  819. var focusLine = svg.append('g')
  820. .attr('class', 'd3-crosshair-line')
  821. .style('display', 'none');
  822. // Line element
  823. focusLine.append('line')
  824. .attr('class', 'vertical-crosshair')
  825. .attr('y1', 0)
  826. .attr('y2', -maxY)
  827. .style('stroke', '#e5e5e5')
  828. .style('shape-rendering', 'crispEdges')
  829. //
  830. // Pointer
  831. //
  832. // Pointer group
  833. var focusPointer = svg.append('g')
  834. .attr('class', 'd3-crosshair-pointer')
  835. .style('display', 'none');
  836. // Pointer element
  837. focusPointer.append('circle')
  838. .attr('r', 3)
  839. .style('fill', '#fff')
  840. .style('stroke', color)
  841. .style('stroke-width', 1)
  842. //
  843. // Text
  844. //
  845. // Text group
  846. var focusText = svg.append('g')
  847. .attr('class', 'd3-crosshair-text')
  848. .style('display', 'none');
  849. // Text element
  850. focusText.append('text')
  851. .attr('dy', -10)
  852. .style('font-size', 12);
  853. //
  854. // Overlay with events
  855. //
  856. svg.append('rect')
  857. .attr('class', 'd3-crosshair-overlay')
  858. .style('fill', 'none')
  859. .style('pointer-events', 'all')
  860. .attr('width', width)
  861. .attr('height', height)
  862. .on('mouseover', function() {
  863. focusPointer.style('display', null);
  864. focusLine.style('display', null)
  865. focusText.style('display', null);
  866. })
  867. .on('mouseout', function() {
  868. focusPointer.style('display', 'none');
  869. focusLine.style('display', 'none');
  870. focusText.style('display', 'none');
  871. })
  872. .on('mousemove', mousemove);
  873. // Display tooltip on mousemove
  874. function mousemove() {
  875. // Define main variables
  876. var mouse = d3.mouse(this),
  877. mousex = mouse[0],
  878. mousey = mouse[1],
  879. x0 = x.invert(mousex),
  880. i = bisectDate(data, x0),
  881. d0 = data[i - 1],
  882. d1 = data[i],
  883. d = x0 - d0.date > d1.date - x0 ? d1 : d0;
  884. // Move line
  885. focusLine.attr('transform', 'translate(' + x(d.date) + ',' + height + ')');
  886. // Move pointer
  887. focusPointer.attr('transform', 'translate(' + x(d.date) + ',' + y(d.value) + ')');
  888. // Reverse tooltip at the end point
  889. if(mousex >= (d3Container.node().getBoundingClientRect().width - focusText.select('text').node().getBoundingClientRect().width - margin.right - margin.left)) {
  890. focusText.select('text').attr('text-anchor', 'end').attr('x', function () { return (x(d.date) - 15) + 'px' }).text(formatDate(d.date) + ' - ' + d.value + ' sales');
  891. }
  892. else {
  893. focusText.select('text').attr('text-anchor', 'start').attr('x', function () { return (x(d.date) + 15) + 'px' }).text(formatDate(d.date) + ' - ' + d.value + ' sales');
  894. }
  895. }
  896. // Resize chart
  897. // ------------------------------
  898. // Call function on window resize
  899. $(window).on('resize', monthlySalesAreaResize);
  900. // Call function on sidebar width change
  901. $(document).on('click', '.sidebar-control', monthlySalesAreaResize);
  902. // Resize function
  903. //
  904. // Since D3 doesn't support SVG resize by default,
  905. // we need to manually specify parts of the graph that need to
  906. // be updated on window resize
  907. function monthlySalesAreaResize() {
  908. // Layout variables
  909. width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right;
  910. // Layout
  911. // -------------------------
  912. // Main svg width
  913. container.attr('width', width + margin.left + margin.right);
  914. // Width of appended group
  915. svg.attr('width', width + margin.left + margin.right);
  916. // Axes
  917. // -------------------------
  918. // Horizontal range
  919. x.range([0, width]);
  920. // Horizontal axis
  921. svg.selectAll('.d3-axis-horizontal').call(xAxis);
  922. // Horizontal axis subticks
  923. svg.selectAll('.d3-axis-subticks').attr('x1', x).attr('x2', x);
  924. // Chart elements
  925. // -------------------------
  926. // Area path
  927. svg.selectAll('.d3-area').datum(data).attr('d', area);
  928. // Crosshair
  929. svg.selectAll('.d3-crosshair-overlay').attr('width', width);
  930. }
  931. });
  932. }
  933. };
  934. // Messages area chart
  935. var _MessagesAreaChart = function(element, height, color) {
  936. if (typeof d3 == 'undefined') {
  937. console.warn('Warning - d3.min.js is not loaded.');
  938. return;
  939. }
  940. // Initialize chart only if element exsists in the DOM
  941. if($(element).length > 0) {
  942. // Basic setup
  943. // ------------------------------
  944. // Define main variables
  945. var d3Container = d3.select(element),
  946. margin = {top: 0, right: 0, bottom: 0, left: 0},
  947. width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right,
  948. height = height - margin.top - margin.bottom;
  949. // Date and time format
  950. var parseDate = d3.time.format('%Y-%m-%d').parse;
  951. // Create SVG
  952. // ------------------------------
  953. // Container
  954. var container = d3Container.append('svg');
  955. // SVG element
  956. var svg = container
  957. .attr('width', width + margin.left + margin.right)
  958. .attr('height', height + margin.top + margin.bottom)
  959. .append('g')
  960. .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
  961. // Construct chart layout
  962. // ------------------------------
  963. // Area
  964. var area = d3.svg.area()
  965. .x(function(d) { return x(d.date); })
  966. .y0(height)
  967. .y1(function(d) { return y(d.value); })
  968. .interpolate('monotone')
  969. // Construct scales
  970. // ------------------------------
  971. // Horizontal
  972. var x = d3.time.scale().range([0, width ]);
  973. // Vertical
  974. var y = d3.scale.linear().range([height, 0]);
  975. // Load data
  976. // ------------------------------
  977. d3.json('../../../../global_assets/demo_data/dashboard/monthly_sales.json', function (error, data) {
  978. // Show what's wrong if error
  979. if (error) return console.error(error);
  980. // Pull out values
  981. data.forEach(function (d) {
  982. d.date = parseDate(d.date);
  983. d.value = +d.value;
  984. });
  985. // Get the maximum value in the given array
  986. var maxY = d3.max(data, function(d) { return d.value; });
  987. // Reset start data for animation
  988. var startData = data.map(function(datum) {
  989. return {
  990. date: datum.date,
  991. value: 0
  992. };
  993. });
  994. // Set input domains
  995. // ------------------------------
  996. // Horizontal
  997. x.domain(d3.extent(data, function(d, i) { return d.date; }));
  998. // Vertical
  999. y.domain([0, d3.max( data, function(d) { return d.value; })]);
  1000. //
  1001. // Append chart elements
  1002. //
  1003. // Add area path
  1004. svg.append('path')
  1005. .datum(data)
  1006. .attr('class', 'd3-area')
  1007. .style('fill', color)
  1008. .attr('d', area)
  1009. .transition() // begin animation
  1010. .duration(1000)
  1011. .attrTween('d', function() {
  1012. var interpolator = d3.interpolateArray(startData, data);
  1013. return function (t) {
  1014. return area(interpolator (t));
  1015. }
  1016. });
  1017. // Resize chart
  1018. // ------------------------------
  1019. // Call function on window resize
  1020. $(window).on('resize', messagesAreaResize);
  1021. // Call function on sidebar width change
  1022. $(document).on('click', '.sidebar-control', messagesAreaResize);
  1023. // Resize function
  1024. //
  1025. // Since D3 doesn't support SVG resize by default,
  1026. // we need to manually specify parts of the graph that need to
  1027. // be updated on window resize
  1028. function messagesAreaResize() {
  1029. // Layout variables
  1030. width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right;
  1031. // Layout
  1032. // -------------------------
  1033. // Main svg width
  1034. container.attr('width', width + margin.left + margin.right);
  1035. // Width of appended group
  1036. svg.attr('width', width + margin.left + margin.right);
  1037. // Horizontal range
  1038. x.range([0, width]);
  1039. // Chart elements
  1040. // -------------------------
  1041. // Area path
  1042. svg.selectAll('.d3-area').datum( data ).attr('d', area);
  1043. }
  1044. });
  1045. }
  1046. };
  1047. // Sparklines chart
  1048. var _chartSparkline = function(element, chartType, qty, height, interpolation, duration, interval, color) {
  1049. if (typeof d3 == 'undefined') {
  1050. console.warn('Warning - d3.min.js is not loaded.');
  1051. return;
  1052. }
  1053. // Initialize chart only if element exsists in the DOM
  1054. if($(element).length > 0) {
  1055. // Basic setup
  1056. // ------------------------------
  1057. // Define main variables
  1058. var d3Container = d3.select(element),
  1059. margin = {top: 0, right: 0, bottom: 0, left: 0},
  1060. width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right,
  1061. height = height - margin.top - margin.bottom;
  1062. // Generate random data (for demo only)
  1063. var data = [];
  1064. for (var i=0; i < qty; i++) {
  1065. data.push(Math.floor(Math.random() * qty) + 5)
  1066. }
  1067. // Construct scales
  1068. // ------------------------------
  1069. // Horizontal
  1070. var x = d3.scale.linear().range([0, width]);
  1071. // Vertical
  1072. var y = d3.scale.linear().range([height - 5, 5]);
  1073. // Set input domains
  1074. // ------------------------------
  1075. // Horizontal
  1076. x.domain([1, qty - 3])
  1077. // Vertical
  1078. y.domain([0, qty])
  1079. // Construct chart layout
  1080. // ------------------------------
  1081. // Line
  1082. var line = d3.svg.line()
  1083. .interpolate(interpolation)
  1084. .x(function(d, i) { return x(i); })
  1085. .y(function(d, i) { return y(d); });
  1086. // Area
  1087. var area = d3.svg.area()
  1088. .interpolate(interpolation)
  1089. .x(function(d, i) {
  1090. return x(i);
  1091. })
  1092. .y0(height)
  1093. .y1(function(d) {
  1094. return y(d);
  1095. });
  1096. // Create SVG
  1097. // ------------------------------
  1098. // Container
  1099. var container = d3Container.append('svg');
  1100. // SVG element
  1101. var svg = container
  1102. .attr('width', width + margin.left + margin.right)
  1103. .attr('height', height + margin.top + margin.bottom)
  1104. .append("g")
  1105. .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
  1106. // Add mask for animation
  1107. // ------------------------------
  1108. // Add clip path
  1109. var clip = svg.append('defs')
  1110. .append('clipPath')
  1111. .attr('id', function(d, i) { return 'load-clip-' + element.substring(1) })
  1112. // Add clip shape
  1113. var clips = clip.append('rect')
  1114. .attr('class', 'load-clip')
  1115. .attr('width', 0)
  1116. .attr('height', height);
  1117. // Animate mask
  1118. clips
  1119. .transition()
  1120. .duration(1000)
  1121. .ease('linear')
  1122. .attr('width', width);
  1123. //
  1124. // Append chart elements
  1125. //
  1126. // Main path
  1127. var path = svg.append('g')
  1128. .attr('clip-path', function(d, i) { return 'url(#load-clip-' + element.substring(1) + ')'})
  1129. .append('path')
  1130. .datum(data)
  1131. .attr('transform', 'translate(' + x(0) + ',0)');
  1132. // Add path based on chart type
  1133. if(chartType == 'area') {
  1134. path.attr('d', area).attr('class', 'd3-area').style('fill', color); // area
  1135. }
  1136. else {
  1137. path.attr('d', line).attr('class', 'd3-line d3-line-medium').style('stroke', color); // line
  1138. }
  1139. // Animate path
  1140. path
  1141. .style('opacity', 0)
  1142. .transition()
  1143. .duration(750)
  1144. .style('opacity', 1);
  1145. // Set update interval. For demo only
  1146. // ------------------------------
  1147. setInterval(function() {
  1148. // push a new data point onto the back
  1149. data.push(Math.floor(Math.random() * qty) + 5);
  1150. // pop the old data point off the front
  1151. data.shift();
  1152. update();
  1153. }, interval);
  1154. // Update random data. For demo only
  1155. // ------------------------------
  1156. function update() {
  1157. // Redraw the path and slide it to the left
  1158. path
  1159. .attr('transform', null)
  1160. .transition()
  1161. .duration(duration)
  1162. .ease('linear')
  1163. .attr('transform', 'translate(' + x(0) + ',0)');
  1164. // Update path type
  1165. if(chartType == 'area') {
  1166. path.attr('d', area).attr('class', 'd3-area').style('fill', color)
  1167. }
  1168. else {
  1169. path.attr('d', line).attr('class', 'd3-line d3-line-medium').style('stroke', color);
  1170. }
  1171. }
  1172. // Resize chart
  1173. // ------------------------------
  1174. // Call function on window resize
  1175. $(window).on('resize', resizeSparklines);
  1176. // Call function on sidebar width change
  1177. $(document).on('click', '.sidebar-control', resizeSparklines);
  1178. // Resize function
  1179. //
  1180. // Since D3 doesn't support SVG resize by default,
  1181. // we need to manually specify parts of the graph that need to
  1182. // be updated on window resize
  1183. function resizeSparklines() {
  1184. // Layout variables
  1185. width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right;
  1186. // Layout
  1187. // -------------------------
  1188. // Main svg width
  1189. container.attr('width', width + margin.left + margin.right);
  1190. // Width of appended group
  1191. svg.attr('width', width + margin.left + margin.right);
  1192. // Horizontal range
  1193. x.range([0, width]);
  1194. // Chart elements
  1195. // -------------------------
  1196. // Clip mask
  1197. clips.attr('width', width);
  1198. // Line
  1199. svg.select('.d3-line').attr('d', line);
  1200. // Area
  1201. svg.select('.d3-area').attr('d', area);
  1202. }
  1203. }
  1204. };
  1205. // Daily revenue line chart
  1206. var _DailyRevenueLineChart = function(element, height) {
  1207. if (typeof d3 == 'undefined') {
  1208. console.warn('Warning - d3.min.js is not loaded.');
  1209. return;
  1210. }
  1211. // Initialize chart only if element exsists in the DOM
  1212. if($(element).length > 0) {
  1213. // Basic setup
  1214. // ------------------------------
  1215. // Add data set
  1216. var dataset = [
  1217. {
  1218. 'date': '04/13/14',
  1219. 'alpha': '60'
  1220. }, {
  1221. 'date': '04/14/14',
  1222. 'alpha': '35'
  1223. }, {
  1224. 'date': '04/15/14',
  1225. 'alpha': '65'
  1226. }, {
  1227. 'date': '04/16/14',
  1228. 'alpha': '50'
  1229. }, {
  1230. 'date': '04/17/14',
  1231. 'alpha': '65'
  1232. }, {
  1233. 'date': '04/18/14',
  1234. 'alpha': '20'
  1235. }, {
  1236. 'date': '04/19/14',
  1237. 'alpha': '60'
  1238. }
  1239. ];
  1240. // Main variables
  1241. var d3Container = d3.select(element),
  1242. margin = {top: 0, right: 0, bottom: 0, left: 0},
  1243. width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right,
  1244. height = height - margin.top - margin.bottom,
  1245. padding = 20;
  1246. // Format date
  1247. var parseDate = d3.time.format('%m/%d/%y').parse,
  1248. formatDate = d3.time.format('%a, %B %e');
  1249. // Add tooltip
  1250. // ------------------------------
  1251. var tooltip = d3.tip()
  1252. .attr('class', 'd3-tip')
  1253. .html(function (d) {
  1254. return '<ul class="list-unstyled mb-1">' +
  1255. '<li>' + '<div class="font-size-base my-1"><i class="icon-check2 mr-2"></i>' + formatDate(d.date) + '</div>' + '</li>' +
  1256. '<li>' + 'Sales: &nbsp;' + '<span class="font-weight-semibold float-right">' + d.alpha + '</span>' + '</li>' +
  1257. '<li>' + 'Revenue: &nbsp; ' + '<span class="font-weight-semibold float-right">' + '$' + (d.alpha * 25).toFixed(2) + '</span>' + '</li>' +
  1258. '</ul>';
  1259. });
  1260. // Create chart
  1261. // ------------------------------
  1262. // Add svg element
  1263. var container = d3Container.append('svg');
  1264. // Add SVG group
  1265. var svg = container
  1266. .attr('width', width + margin.left + margin.right)
  1267. .attr('height', height + margin.top + margin.bottom)
  1268. .append('g')
  1269. .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
  1270. .call(tooltip);
  1271. // Load data
  1272. // ------------------------------
  1273. dataset.forEach(function (d) {
  1274. d.date = parseDate(d.date);
  1275. d.alpha = +d.alpha;
  1276. });
  1277. // Construct scales
  1278. // ------------------------------
  1279. // Horizontal
  1280. var x = d3.time.scale()
  1281. .range([padding, width - padding]);
  1282. // Vertical
  1283. var y = d3.scale.linear()
  1284. .range([height, 5]);
  1285. // Set input domains
  1286. // ------------------------------
  1287. // Horizontal
  1288. x.domain(d3.extent(dataset, function (d) {
  1289. return d.date;
  1290. }));
  1291. // Vertical
  1292. y.domain([0, d3.max(dataset, function (d) {
  1293. return Math.max(d.alpha);
  1294. })]);
  1295. // Construct chart layout
  1296. // ------------------------------
  1297. // Line
  1298. var line = d3.svg.line()
  1299. .x(function(d) {
  1300. return x(d.date);
  1301. })
  1302. .y(function(d) {
  1303. return y(d.alpha)
  1304. });
  1305. //
  1306. // Append chart elements
  1307. //
  1308. // Add mask for animation
  1309. // ------------------------------
  1310. // Add clip path
  1311. var clip = svg.append('defs')
  1312. .append('clipPath')
  1313. .attr('id', 'clip-line-small');
  1314. // Add clip shape
  1315. var clipRect = clip.append('rect')
  1316. .attr('class', 'clip')
  1317. .attr('width', 0)
  1318. .attr('height', height);
  1319. // Animate mask
  1320. clipRect
  1321. .transition()
  1322. .duration(1000)
  1323. .ease('linear')
  1324. .attr('width', width);
  1325. // Line
  1326. // ------------------------------
  1327. // Path
  1328. var path = svg.append('path')
  1329. .attr({
  1330. 'd': line(dataset),
  1331. 'clip-path': 'url(#clip-line-small)',
  1332. 'class': 'd3-line d3-line-medium'
  1333. })
  1334. .style('stroke', '#fff');
  1335. // Animate path
  1336. svg.select('.line-tickets')
  1337. .transition()
  1338. .duration(1000)
  1339. .ease('linear');
  1340. // Add vertical guide lines
  1341. // ------------------------------
  1342. // Bind data
  1343. var guide = svg.append('g')
  1344. .selectAll('.d3-line-guides-group')
  1345. .data(dataset);
  1346. // Append lines
  1347. guide
  1348. .enter()
  1349. .append('line')
  1350. .attr('class', 'd3-line-guides')
  1351. .attr('x1', function (d, i) {
  1352. return x(d.date);
  1353. })
  1354. .attr('y1', function (d, i) {
  1355. return height;
  1356. })
  1357. .attr('x2', function (d, i) {
  1358. return x(d.date);
  1359. })
  1360. .attr('y2', function (d, i) {
  1361. return height;
  1362. })
  1363. .style('stroke', 'rgba(255,255,255,0.3)')
  1364. .style('stroke-dasharray', '4,2')
  1365. .style('shape-rendering', 'crispEdges');
  1366. // Animate guide lines
  1367. guide
  1368. .transition()
  1369. .duration(1000)
  1370. .delay(function(d, i) { return i * 150; })
  1371. .attr('y2', function (d, i) {
  1372. return y(d.alpha);
  1373. });
  1374. // Alpha app points
  1375. // ------------------------------
  1376. // Add points
  1377. var points = svg.insert('g')
  1378. .selectAll('.d3-line-circle')
  1379. .data(dataset)
  1380. .enter()
  1381. .append('circle')
  1382. .attr('class', 'd3-line-circle d3-line-circle-medium')
  1383. .attr('cx', line.x())
  1384. .attr('cy', line.y())
  1385. .attr('r', 3)
  1386. .style('stroke', '#fff')
  1387. .style('fill', '#29B6F6');
  1388. // Animate points on page load
  1389. points
  1390. .style('opacity', 0)
  1391. .transition()
  1392. .duration(250)
  1393. .ease('linear')
  1394. .delay(1000)
  1395. .style('opacity', 1);
  1396. // Add user interaction
  1397. points
  1398. .on('mouseover', function (d) {
  1399. tooltip.offset([-10, 0]).show(d);
  1400. // Animate circle radius
  1401. d3.select(this).transition().duration(250).attr('r', 4);
  1402. })
  1403. // Hide tooltip
  1404. .on('mouseout', function (d) {
  1405. tooltip.hide(d);
  1406. // Animate circle radius
  1407. d3.select(this).transition().duration(250).attr('r', 3);
  1408. });
  1409. // Change tooltip direction of first point
  1410. d3.select(points[0][0])
  1411. .on('mouseover', function (d) {
  1412. tooltip.offset([0, 10]).direction('e').show(d);
  1413. // Animate circle radius
  1414. d3.select(this).transition().duration(250).attr('r', 4);
  1415. })
  1416. .on('mouseout', function (d) {
  1417. tooltip.direction('n').hide(d);
  1418. // Animate circle radius
  1419. d3.select(this).transition().duration(250).attr('r', 3);
  1420. });
  1421. // Change tooltip direction of last point
  1422. d3.select(points[0][points.size() - 1])
  1423. .on('mouseover', function (d) {
  1424. tooltip.offset([0, -10]).direction('w').show(d);
  1425. // Animate circle radius
  1426. d3.select(this).transition().duration(250).attr('r', 4);
  1427. })
  1428. .on('mouseout', function (d) {
  1429. tooltip.direction('n').hide(d);
  1430. // Animate circle radius
  1431. d3.select(this).transition().duration(250).attr('r', 3);
  1432. })
  1433. // Resize chart
  1434. // ------------------------------
  1435. // Call function on window resize
  1436. $(window).on('resize', revenueResize);
  1437. // Call function on sidebar width change
  1438. $(document).on('click', '.sidebar-control', revenueResize);
  1439. // Resize function
  1440. //
  1441. // Since D3 doesn't support SVG resize by default,
  1442. // we need to manually specify parts of the graph that need to
  1443. // be updated on window resize
  1444. function revenueResize() {
  1445. // Layout variables
  1446. width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right;
  1447. // Layout
  1448. // -------------------------
  1449. // Main svg width
  1450. container.attr('width', width + margin.left + margin.right);
  1451. // Width of appended group
  1452. svg.attr('width', width + margin.left + margin.right);
  1453. // Horizontal range
  1454. x.range([padding, width - padding]);
  1455. // Chart elements
  1456. // -------------------------
  1457. // Mask
  1458. clipRect.attr('width', width);
  1459. // Line path
  1460. svg.selectAll('.d3-line').attr('d', line(dataset));
  1461. // Circles
  1462. svg.selectAll('.d3-line-circle').attr('cx', line.x());
  1463. // Guide lines
  1464. svg.selectAll('.d3-line-guides')
  1465. .attr('x1', function (d, i) {
  1466. return x(d.date);
  1467. })
  1468. .attr('x2', function (d, i) {
  1469. return x(d.date);
  1470. });
  1471. }
  1472. }
  1473. };
  1474. // Small progress pie chart
  1475. var _ProgressPieChart = function(element, width, height, color) {
  1476. if (typeof d3 == 'undefined') {
  1477. console.warn('Warning - d3.min.js is not loaded.');
  1478. return;
  1479. }
  1480. // Initialize chart only if element exsists in the DOM
  1481. if($(element).length > 0) {
  1482. // Basic setup
  1483. // ------------------------------
  1484. // Main variables
  1485. var d3Container = d3.select(element),
  1486. border = 2,
  1487. radius = Math.min(width / 2, height / 2) - border,
  1488. twoPi = 2 * Math.PI,
  1489. progress = $(element).data('progress'),
  1490. total = 100;
  1491. // Construct chart layout
  1492. // ------------------------------
  1493. // Arc
  1494. var arc = d3.svg.arc()
  1495. .startAngle(0)
  1496. .innerRadius(0)
  1497. .outerRadius(radius)
  1498. .endAngle(function(d) {
  1499. return (d.value / d.size) * 2 * Math.PI;
  1500. })
  1501. // Create chart
  1502. // ------------------------------
  1503. // Add svg element
  1504. var container = d3Container.append('svg');
  1505. // Add SVG group
  1506. var svg = container
  1507. .attr('width', width)
  1508. .attr('height', height)
  1509. .append('g')
  1510. .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
  1511. //
  1512. // Append chart elements
  1513. //
  1514. // Progress group
  1515. var meter = svg.append('g')
  1516. .attr('class', 'progress-meter');
  1517. // Background
  1518. meter.append('path')
  1519. .attr('d', arc.endAngle(twoPi))
  1520. .style('fill', '#fff')
  1521. .style('stroke', color)
  1522. .style('stroke-width', 1.5);
  1523. // Foreground
  1524. var foreground = meter.append('path')
  1525. .style('fill', color);
  1526. // Animate foreground path
  1527. foreground
  1528. .transition()
  1529. .ease('cubic-out')
  1530. .duration(2500)
  1531. .attrTween('d', arcTween);
  1532. // Tween arcs
  1533. function arcTween() {
  1534. var i = d3.interpolate(0, progress);
  1535. return function(t) {
  1536. var currentProgress = progress / (100/t);
  1537. var endAngle = arc.endAngle(twoPi * (currentProgress));
  1538. return arc(i(endAngle));
  1539. };
  1540. }
  1541. }
  1542. };
  1543. // Marketing campaigns donut chart
  1544. var _MarketingCampaignsDonutChart = function(element, size) {
  1545. if (typeof d3 == 'undefined') {
  1546. console.warn('Warning - d3.min.js is not loaded.');
  1547. return;
  1548. }
  1549. // Initialize chart only if element exsists in the DOM
  1550. if($(element).length > 0) {
  1551. // Basic setup
  1552. // ------------------------------
  1553. // Add data set
  1554. var data = [
  1555. {
  1556. "browser": "Google Adwords",
  1557. "icon": "<i class='icon-google mr-2'></i>",
  1558. "value": 1047,
  1559. "color" : "#66BB6A"
  1560. }, {
  1561. "browser": "Social media",
  1562. "icon": "<i class='icon-share4 mr-2'></i>",
  1563. "value": 2948,
  1564. "color": "#9575CD"
  1565. }, {
  1566. "browser": "Youtube video",
  1567. "icon": "<i class='icon-youtube mr-2'></i>",
  1568. "value": 3909,
  1569. "color": "#FF7043"
  1570. }
  1571. ];
  1572. // Main variables
  1573. var d3Container = d3.select(element),
  1574. distance = 2, // reserve 2px space for mouseover arc moving
  1575. radius = (size/2) - distance,
  1576. sum = d3.sum(data, function(d) { return d.value; });
  1577. // Tooltip
  1578. // ------------------------------
  1579. var tip = d3.tip()
  1580. .attr('class', 'd3-tip')
  1581. .offset([-10, 0])
  1582. .direction('e')
  1583. .html(function (d) {
  1584. return '<ul class="list-unstyled mb-1">' +
  1585. '<li>' + '<div class="font-size-base mb-1 mt-1">' + d.data.icon + d.data.browser + '</div>' + '</li>' +
  1586. '<li>' + 'Visits: &nbsp;' + '<span class="font-weight-semibold float-right">' + d.value + '</span>' + '</li>' +
  1587. '<li>' + 'Share: &nbsp;' + '<span class="font-weight-semibold float-right">' + (100 / (sum / d.value)).toFixed(2) + '%' + '</span>' + '</li>' +
  1588. '</ul>';
  1589. });
  1590. // Create chart
  1591. // ------------------------------
  1592. // Add svg element
  1593. var container = d3Container.append('svg').call(tip);
  1594. // Add SVG group
  1595. var svg = container
  1596. .attr('width', size)
  1597. .attr('height', size)
  1598. .append('g')
  1599. .attr('transform', 'translate(' + (size / 2) + ',' + (size / 2) + ')');
  1600. // Construct chart layout
  1601. // ------------------------------
  1602. // Pie
  1603. var pie = d3.layout.pie()
  1604. .sort(null)
  1605. .startAngle(Math.PI)
  1606. .endAngle(3 * Math.PI)
  1607. .value(function (d) {
  1608. return d.value;
  1609. });
  1610. // Arc
  1611. var arc = d3.svg.arc()
  1612. .outerRadius(radius)
  1613. .innerRadius(radius / 2);
  1614. //
  1615. // Append chart elements
  1616. //
  1617. // Group chart elements
  1618. var arcGroup = svg.selectAll('.d3-arc')
  1619. .data(pie(data))
  1620. .enter()
  1621. .append('g')
  1622. .attr('class', 'd3-arc')
  1623. .style('stroke', '#fff')
  1624. .style('cursor', 'pointer');
  1625. // Append path
  1626. var arcPath = arcGroup
  1627. .append('path')
  1628. .style('fill', function (d) { return d.data.color; });
  1629. // Add tooltip
  1630. arcPath
  1631. .on('mouseover', function (d, i) {
  1632. // Transition on mouseover
  1633. d3.select(this)
  1634. .transition()
  1635. .duration(500)
  1636. .ease('elastic')
  1637. .attr('transform', function (d) {
  1638. d.midAngle = ((d.endAngle - d.startAngle) / 2) + d.startAngle;
  1639. var x = Math.sin(d.midAngle) * distance;
  1640. var y = -Math.cos(d.midAngle) * distance;
  1641. return 'translate(' + x + ',' + y + ')';
  1642. });
  1643. })
  1644. .on('mousemove', function (d) {
  1645. // Show tooltip on mousemove
  1646. tip.show(d)
  1647. .style('top', (d3.event.pageY - 40) + 'px')
  1648. .style('left', (d3.event.pageX + 30) + 'px');
  1649. })
  1650. .on('mouseout', function (d, i) {
  1651. // Mouseout transition
  1652. d3.select(this)
  1653. .transition()
  1654. .duration(500)
  1655. .ease('bounce')
  1656. .attr('transform', 'translate(0,0)');
  1657. // Hide tooltip
  1658. tip.hide(d);
  1659. });
  1660. // Animate chart on load
  1661. arcPath
  1662. .transition()
  1663. .delay(function(d, i) { return i * 500; })
  1664. .duration(500)
  1665. .attrTween('d', function(d) {
  1666. var interpolate = d3.interpolate(d.startAngle,d.endAngle);
  1667. return function(t) {
  1668. d.endAngle = interpolate(t);
  1669. return arc(d);
  1670. };
  1671. });
  1672. }
  1673. };
  1674. // Campaign status donut chart
  1675. var _CampaignStatusDonutChart = function(element, size) {
  1676. if (typeof d3 == 'undefined') {
  1677. console.warn('Warning - d3.min.js is not loaded.');
  1678. return;
  1679. }
  1680. // Initialize chart only if element exsists in the DOM
  1681. if($(element).length > 0) {
  1682. // Basic setup
  1683. // ------------------------------
  1684. // Add data set
  1685. var data = [
  1686. {
  1687. "status": "Active campaigns",
  1688. "icon": "<span class='status-mark border-blue-300 mr-2'></span>",
  1689. "value": 439,
  1690. "color": "#29B6F6"
  1691. }, {
  1692. "status": "Closed campaigns",
  1693. "icon": "<span class='status-mark border-danger-300 mr-2'></span>",
  1694. "value": 290,
  1695. "color": "#EF5350"
  1696. }, {
  1697. "status": "Pending campaigns",
  1698. "icon": "<span class='status-mark border-success-300 mr-2'></span>",
  1699. "value": 190,
  1700. "color": "#81C784"
  1701. }, {
  1702. "status": "Campaigns on hold",
  1703. "icon": "<span class='status-mark border-grey-300 mr-2'></span>",
  1704. "value": 148,
  1705. "color": "#999"
  1706. }
  1707. ];
  1708. // Main variables
  1709. var d3Container = d3.select(element),
  1710. distance = 2, // reserve 2px space for mouseover arc moving
  1711. radius = (size/2) - distance,
  1712. sum = d3.sum(data, function(d) { return d.value; })
  1713. // Tooltip
  1714. // ------------------------------
  1715. var tip = d3.tip()
  1716. .attr('class', 'd3-tip')
  1717. .offset([-10, 0])
  1718. .direction('e')
  1719. .html(function (d) {
  1720. return '<ul class="list-unstyled mb-1">' +
  1721. '<li>' + '<div class="font-size-base mb-1 mt-1">' + d.data.icon + d.data.status + '</div>' + '</li>' +
  1722. '<li>' + 'Total: &nbsp;' + '<span class="font-weight-semibold float-right">' + d.value + '</span>' + '</li>' +
  1723. '<li>' + 'Share: &nbsp;' + '<span class="font-weight-semibold float-right">' + (100 / (sum / d.value)).toFixed(2) + '%' + '</span>' + '</li>' +
  1724. '</ul>';
  1725. });
  1726. // Create chart
  1727. // ------------------------------
  1728. // Add svg element
  1729. var container = d3Container.append('svg').call(tip);
  1730. // Add SVG group
  1731. var svg = container
  1732. .attr('width', size)
  1733. .attr('height', size)
  1734. .append('g')
  1735. .attr('transform', 'translate(' + (size / 2) + ',' + (size / 2) + ')');
  1736. // Construct chart layout
  1737. // ------------------------------
  1738. // Pie
  1739. var pie = d3.layout.pie()
  1740. .sort(null)
  1741. .startAngle(Math.PI)
  1742. .endAngle(3 * Math.PI)
  1743. .value(function (d) {
  1744. return d.value;
  1745. });
  1746. // Arc
  1747. var arc = d3.svg.arc()
  1748. .outerRadius(radius)
  1749. .innerRadius(radius / 2);
  1750. //
  1751. // Append chart elements
  1752. //
  1753. // Group chart elements
  1754. var arcGroup = svg.selectAll('.d3-arc')
  1755. .data(pie(data))
  1756. .enter()
  1757. .append('g')
  1758. .attr('class', 'd3-arc')
  1759. .style('stroke', '#fff')
  1760. .style('cursor', 'pointer');
  1761. // Append path
  1762. var arcPath = arcGroup
  1763. .append('path')
  1764. .style('fill', function (d) { return d.data.color; });
  1765. // Add tooltip
  1766. arcPath
  1767. .on('mouseover', function (d, i) {
  1768. // Transition on mouseover
  1769. d3.select(this)
  1770. .transition()
  1771. .duration(500)
  1772. .ease('elastic')
  1773. .attr('transform', function (d) {
  1774. d.midAngle = ((d.endAngle - d.startAngle) / 2) + d.startAngle;
  1775. var x = Math.sin(d.midAngle) * distance;
  1776. var y = -Math.cos(d.midAngle) * distance;
  1777. return 'translate(' + x + ',' + y + ')';
  1778. });
  1779. })
  1780. .on('mousemove', function (d) {
  1781. // Show tooltip on mousemove
  1782. tip.show(d)
  1783. .style('top', (d3.event.pageY - 40) + 'px')
  1784. .style('left', (d3.event.pageX + 30) + 'px');
  1785. })
  1786. .on('mouseout', function (d, i) {
  1787. // Mouseout transition
  1788. d3.select(this)
  1789. .transition()
  1790. .duration(500)
  1791. .ease('bounce')
  1792. .attr('transform', 'translate(0,0)');
  1793. // Hide tooltip
  1794. tip.hide(d);
  1795. });
  1796. // Animate chart on load
  1797. arcPath
  1798. .transition()
  1799. .delay(function(d, i) { return i * 500; })
  1800. .duration(500)
  1801. .attrTween('d', function(d) {
  1802. var interpolate = d3.interpolate(d.startAngle,d.endAngle);
  1803. return function(t) {
  1804. d.endAngle = interpolate(t);
  1805. return arc(d);
  1806. };
  1807. });
  1808. }
  1809. };
  1810. // Tickets status donut chart
  1811. var _TicketStatusDonutChart = function(element, size) {
  1812. if (typeof d3 == 'undefined') {
  1813. console.warn('Warning - d3.min.js is not loaded.');
  1814. return;
  1815. }
  1816. // Initialize chart only if element exsists in the DOM
  1817. if($(element).length > 0) {
  1818. // Basic setup
  1819. // ------------------------------
  1820. // Add data set
  1821. var data = [
  1822. {
  1823. "status": "Pending tickets",
  1824. "icon": "<i class='status-mark border-blue-300 mr-2'></i>",
  1825. "value": 295,
  1826. "color": "#29B6F6"
  1827. }, {
  1828. "status": "Resolved tickets",
  1829. "icon": "<i class='status-mark border-success-300 mr-2'></i>",
  1830. "value": 189,
  1831. "color": "#66BB6A"
  1832. }, {
  1833. "status": "Closed tickets",
  1834. "icon": "<i class='status-mark border-danger-300 mr-2'></i>",
  1835. "value": 277,
  1836. "color": "#EF5350"
  1837. }
  1838. ];
  1839. // Main variables
  1840. var d3Container = d3.select(element),
  1841. distance = 2, // reserve 2px space for mouseover arc moving
  1842. radius = (size/2) - distance,
  1843. sum = d3.sum(data, function(d) { return d.value; })
  1844. // Tooltip
  1845. // ------------------------------
  1846. var tip = d3.tip()
  1847. .attr('class', 'd3-tip')
  1848. .offset([-10, 0])
  1849. .direction('e')
  1850. .html(function (d) {
  1851. return '<ul class="list-unstyled mb-1">' +
  1852. '<li>' + '<div class="font-size-base mb-1 mt-1">' + d.data.icon + d.data.status + '</div>' + '</li>' +
  1853. '<li>' + 'Total: &nbsp;' + '<span class="font-weight-semibold float-right">' + d.value + '</span>' + '</li>' +
  1854. '<li>' + 'Share: &nbsp;' + '<span class="font-weight-semibold float-right">' + (100 / (sum / d.value)).toFixed(2) + '%' + '</span>' + '</li>' +
  1855. '</ul>';
  1856. })
  1857. // Create chart
  1858. // ------------------------------
  1859. // Add svg element
  1860. var container = d3Container.append('svg').call(tip);
  1861. // Add SVG group
  1862. var svg = container
  1863. .attr('width', size)
  1864. .attr('height', size)
  1865. .append('g')
  1866. .attr('transform', 'translate(' + (size / 2) + ',' + (size / 2) + ')');
  1867. // Construct chart layout
  1868. // ------------------------------
  1869. // Pie
  1870. var pie = d3.layout.pie()
  1871. .sort(null)
  1872. .startAngle(Math.PI)
  1873. .endAngle(3 * Math.PI)
  1874. .value(function (d) {
  1875. return d.value;
  1876. });
  1877. // Arc
  1878. var arc = d3.svg.arc()
  1879. .outerRadius(radius)
  1880. .innerRadius(radius / 2);
  1881. //
  1882. // Append chart elements
  1883. //
  1884. // Group chart elements
  1885. var arcGroup = svg.selectAll('.d3-arc')
  1886. .data(pie(data))
  1887. .enter()
  1888. .append('g')
  1889. .attr('class', 'd3-arc')
  1890. .style('stroke', '#fff')
  1891. .style('cursor', 'pointer');
  1892. // Append path
  1893. var arcPath = arcGroup
  1894. .append('path')
  1895. .style('fill', function (d) { return d.data.color; });
  1896. // Add tooltip
  1897. arcPath
  1898. .on('mouseover', function (d, i) {
  1899. // Transition on mouseover
  1900. d3.select(this)
  1901. .transition()
  1902. .duration(500)
  1903. .ease('elastic')
  1904. .attr('transform', function (d) {
  1905. d.midAngle = ((d.endAngle - d.startAngle) / 2) + d.startAngle;
  1906. var x = Math.sin(d.midAngle) * distance;
  1907. var y = -Math.cos(d.midAngle) * distance;
  1908. return 'translate(' + x + ',' + y + ')';
  1909. });
  1910. })
  1911. .on('mousemove', function (d) {
  1912. // Show tooltip on mousemove
  1913. tip.show(d)
  1914. .style('top', (d3.event.pageY - 40) + 'px')
  1915. .style('left', (d3.event.pageX + 30) + 'px');
  1916. })
  1917. .on('mouseout', function (d, i) {
  1918. // Mouseout transition
  1919. d3.select(this)
  1920. .transition()
  1921. .duration(500)
  1922. .ease('bounce')
  1923. .attr('transform', 'translate(0,0)');
  1924. // Hide tooltip
  1925. tip.hide(d);
  1926. });
  1927. // Animate chart on load
  1928. arcPath
  1929. .transition()
  1930. .delay(function(d, i) { return i * 500; })
  1931. .duration(500)
  1932. .attrTween('d', function(d) {
  1933. var interpolate = d3.interpolate(d.startAngle,d.endAngle);
  1934. return function(t) {
  1935. d.endAngle = interpolate(t);
  1936. return arc(d);
  1937. };
  1938. });
  1939. }
  1940. };
  1941. // Bar charts
  1942. var _BarChart = function(element, barQty, height, animate, easing, duration, delay, color, tooltip) {
  1943. if (typeof d3 == 'undefined') {
  1944. console.warn('Warning - d3.min.js is not loaded.');
  1945. return;
  1946. }
  1947. // Initialize chart only if element exsists in the DOM
  1948. if($(element).length > 0) {
  1949. // Basic setup
  1950. // ------------------------------
  1951. // Add data set
  1952. var bardata = [];
  1953. for (var i=0; i < barQty; i++) {
  1954. bardata.push(Math.round(Math.random()*10) + 10);
  1955. }
  1956. // Main variables
  1957. var d3Container = d3.select(element),
  1958. width = d3Container.node().getBoundingClientRect().width;
  1959. // Construct scales
  1960. // ------------------------------
  1961. // Horizontal
  1962. var x = d3.scale.ordinal()
  1963. .rangeBands([0, width], 0.3);
  1964. // Vertical
  1965. var y = d3.scale.linear()
  1966. .range([0, height]);
  1967. // Set input domains
  1968. // ------------------------------
  1969. // Horizontal
  1970. x.domain(d3.range(0, bardata.length));
  1971. // Vertical
  1972. y.domain([0, d3.max(bardata)]);
  1973. // Create chart
  1974. // ------------------------------
  1975. // Add svg element
  1976. var container = d3Container.append('svg');
  1977. // Add SVG group
  1978. var svg = container
  1979. .attr('width', width)
  1980. .attr('height', height)
  1981. .append('g');
  1982. //
  1983. // Append chart elements
  1984. //
  1985. // Bars
  1986. var bars = svg.selectAll('rect')
  1987. .data(bardata)
  1988. .enter()
  1989. .append('rect')
  1990. .attr('class', 'd3-random-bars')
  1991. .attr('width', x.rangeBand())
  1992. .attr('x', function(d,i) {
  1993. return x(i);
  1994. })
  1995. .style('fill', color);
  1996. // Tooltip
  1997. // ------------------------------
  1998. var tip = d3.tip()
  1999. .attr('class', 'd3-tip')
  2000. .offset([-10, 0]);
  2001. // Show and hide
  2002. if(tooltip == 'hours' || tooltip == 'goal' || tooltip == 'members') {
  2003. bars.call(tip)
  2004. .on('mouseover', tip.show)
  2005. .on('mouseout', tip.hide);
  2006. }
  2007. // Daily meetings tooltip content
  2008. if(tooltip == 'hours') {
  2009. tip.html(function (d, i) {
  2010. return '<div class="text-center">' +
  2011. '<h6 class="m-0">' + d + '</h6>' +
  2012. '<span class="font-size-sm">meetings</span>' +
  2013. '<div class="font-size-sm">' + i + ':00' + '</div>' +
  2014. '</div>'
  2015. });
  2016. }
  2017. // Statements tooltip content
  2018. if(tooltip == 'goal') {
  2019. tip.html(function (d, i) {
  2020. return '<div class="text-center">' +
  2021. '<h6 class="m-0">' + d + '</h6>' +
  2022. '<span class="font-size-sm">statements</span>' +
  2023. '<div class="font-size-sm">' + i + ':00' + '</div>' +
  2024. '</div>'
  2025. });
  2026. }
  2027. // Online members tooltip content
  2028. if(tooltip == 'members') {
  2029. tip.html(function (d, i) {
  2030. return '<div class="text-center">' +
  2031. '<h6 class="m-0">' + d + '0' + '</h6>' +
  2032. '<span class="font-size-sm">members</span>' +
  2033. '<div class="font-size-sm">' + i + ':00' + '</div>' +
  2034. '</div>'
  2035. });
  2036. }
  2037. // Bar loading animation
  2038. // ------------------------------
  2039. // Choose between animated or static
  2040. if(animate) {
  2041. withAnimation();
  2042. } else {
  2043. withoutAnimation();
  2044. }
  2045. // Animate on load
  2046. function withAnimation() {
  2047. bars
  2048. .attr('height', 0)
  2049. .attr('y', height)
  2050. .transition()
  2051. .attr('height', function(d) {
  2052. return y(d);
  2053. })
  2054. .attr('y', function(d) {
  2055. return height - y(d);
  2056. })
  2057. .delay(function(d, i) {
  2058. return i * delay;
  2059. })
  2060. .duration(duration)
  2061. .ease(easing);
  2062. }
  2063. // Load without animateion
  2064. function withoutAnimation() {
  2065. bars
  2066. .attr('height', function(d) {
  2067. return y(d);
  2068. })
  2069. .attr('y', function(d) {
  2070. return height - y(d);
  2071. })
  2072. }
  2073. // Resize chart
  2074. // ------------------------------
  2075. // Call function on window resize
  2076. $(window).on('resize', barsResize);
  2077. // Call function on sidebar width change
  2078. $(document).on('click', '.sidebar-control', barsResize);
  2079. // Resize function
  2080. //
  2081. // Since D3 doesn't support SVG resize by default,
  2082. // we need to manually specify parts of the graph that need to
  2083. // be updated on window resize
  2084. function barsResize() {
  2085. // Layout variables
  2086. width = d3Container.node().getBoundingClientRect().width;
  2087. // Layout
  2088. // -------------------------
  2089. // Main svg width
  2090. container.attr('width', width);
  2091. // Width of appended group
  2092. svg.attr('width', width);
  2093. // Horizontal range
  2094. x.rangeBands([0, width], 0.3);
  2095. // Chart elements
  2096. // -------------------------
  2097. // Bars
  2098. svg.selectAll('.d3-random-bars')
  2099. .attr('width', x.rangeBand())
  2100. .attr('x', function(d,i) {
  2101. return x(i);
  2102. });
  2103. }
  2104. }
  2105. };
  2106. // Rounded progress charts
  2107. var _RoundedProgressChart = function(element, radius, border, color, end, iconClass, textTitle, textAverage) {
  2108. if (typeof d3 == 'undefined') {
  2109. console.warn('Warning - d3.min.js is not loaded.');
  2110. return;
  2111. }
  2112. // Initialize chart only if element exsists in the DOM
  2113. if($(element).length > 0) {
  2114. // Basic setup
  2115. // ------------------------------
  2116. // Main variables
  2117. var d3Container = d3.select(element),
  2118. startPercent = 0,
  2119. iconSize = 32,
  2120. endPercent = end,
  2121. twoPi = Math.PI * 2,
  2122. formatPercent = d3.format('.0%'),
  2123. boxSize = radius * 2;
  2124. // Values count
  2125. var count = Math.abs((endPercent - startPercent) / 0.01);
  2126. // Values step
  2127. var step = endPercent < startPercent ? -0.01 : 0.01;
  2128. // Create chart
  2129. // ------------------------------
  2130. // Add SVG element
  2131. var container = d3Container.append('svg');
  2132. // Add SVG group
  2133. var svg = container
  2134. .attr('width', boxSize)
  2135. .attr('height', boxSize)
  2136. .append('g')
  2137. .attr('transform', 'translate(' + (boxSize / 2) + ',' + (boxSize / 2) + ')');
  2138. // Construct chart layout
  2139. // ------------------------------
  2140. // Arc
  2141. var arc = d3.svg.arc()
  2142. .startAngle(0)
  2143. .innerRadius(radius)
  2144. .outerRadius(radius - border);
  2145. //
  2146. // Append chart elements
  2147. //
  2148. // Paths
  2149. // ------------------------------
  2150. // Background path
  2151. svg.append('path')
  2152. .attr('class', 'd3-progress-background')
  2153. .attr('d', arc.endAngle(twoPi))
  2154. .style('fill', '#eee');
  2155. // Foreground path
  2156. var foreground = svg.append('path')
  2157. .attr('class', 'd3-progress-foreground')
  2158. .attr('filter', 'url(#blur)')
  2159. .style('fill', color)
  2160. .style('stroke', color);
  2161. // Front path
  2162. var front = svg.append('path')
  2163. .attr('class', 'd3-progress-front')
  2164. .style('fill', color)
  2165. .style('fill-opacity', 1);
  2166. // Text
  2167. // ------------------------------
  2168. // Percentage text value
  2169. var numberText = d3.select(element)
  2170. .append('h2')
  2171. .attr('class', 'pt-1 mt-2 mb-1')
  2172. // Icon
  2173. d3.select(element)
  2174. .append('i')
  2175. .attr('class', iconClass + ' counter-icon')
  2176. .attr('style', 'top: ' + ((boxSize - iconSize) / 2) + 'px');
  2177. // Title
  2178. d3.select(element)
  2179. .append('div')
  2180. .text(textTitle);
  2181. // Subtitle
  2182. d3.select(element)
  2183. .append('div')
  2184. .attr('class', 'font-size-sm text-muted mb-3')
  2185. .text(textAverage);
  2186. // Animation
  2187. // ------------------------------
  2188. // Animate path
  2189. function updateProgress(progress) {
  2190. foreground.attr('d', arc.endAngle(twoPi * progress));
  2191. front.attr('d', arc.endAngle(twoPi * progress));
  2192. numberText.text(formatPercent(progress));
  2193. }
  2194. // Animate text
  2195. var progress = startPercent;
  2196. (function loops() {
  2197. updateProgress(progress);
  2198. if (count > 0) {
  2199. count--;
  2200. progress += step;
  2201. setTimeout(loops, 10);
  2202. }
  2203. })();
  2204. }
  2205. };
  2206. //
  2207. // Return objects assigned to module
  2208. //
  2209. return {
  2210. initComponents: function() {
  2211. _componentSwitchery();
  2212. _componentDaterange();
  2213. _componentIconLetter();
  2214. },
  2215. initCharts: function() {
  2216. // Sparklines
  2217. _chartSparkline('#new-visitors', 'line', 30, 35, 'basis', 750, 2000, '#26A69A');
  2218. _chartSparkline('#new-sessions', 'line', 30, 35, 'basis', 750, 2000, '#FF7043');
  2219. _chartSparkline('#total-online', 'line', 30, 35, 'basis', 750, 2000, '#5C6BC0');
  2220. _chartSparkline('#server-load', 'area', 30, 50, 'basis', 750, 2000, 'rgba(255,255,255,0.5)');
  2221. // Streamgraph
  2222. _TrafficSourcesStreamChart('#traffic-sources', 330);
  2223. // Line charts
  2224. _AppSalesLinesChart('#app_sales', 255);
  2225. _DailyRevenueLineChart('#today-revenue', 50);
  2226. // Area charts
  2227. _MonthlySalesAreaChart('#monthly-sales-stats', 100, '#4DB6AC');
  2228. _MessagesAreaChart('#messages-stats', 40, '#5C6BC0');
  2229. // Progress charts
  2230. _ProgressPieChart('#today-progress', 20, 20, '#7986CB');
  2231. _ProgressPieChart('#yesterday-progress', 20, 20, '#7986CB');
  2232. _RoundedProgressChart('#hours-available-progress', 38, 2, '#F06292', 0.68, 'icon-watch text-pink-400', 'Hours available', '64% average');
  2233. _RoundedProgressChart('#goal-progress', 38, 2, '#5C6BC0', 0.82, 'icon-trophy3 text-indigo-400', 'Productivity goal', '87% average');
  2234. // Donut charts
  2235. _MarketingCampaignsDonutChart('#campaigns-donut', 42);
  2236. _CampaignStatusDonutChart('#campaign-status-pie', 42);
  2237. _TicketStatusDonutChart('#tickets-status', 42);
  2238. // Bar charts
  2239. _BarChart('#hours-available-bars', 24, 40, true, 'elastic', 1200, 50, '#EC407A', 'hours');
  2240. _BarChart('#goal-bars', 24, 40, true, 'elastic', 1200, 50, '#5C6BC0', 'goal');
  2241. _BarChart('#members-online', 24, 50, true, 'elastic', 1200, 50, 'rgba(255,255,255,0.5)', 'members');
  2242. }
  2243. }
  2244. }();
  2245. // Initialize module
  2246. // ------------------------------
  2247. document.addEventListener('DOMContentLoaded', function() {
  2248. Dashboard.initComponents();
  2249. Dashboard.initCharts();
  2250. });