@@ -49,10 +49,10 @@ class Timeseries {
4949 const button = event . target ;
5050 const tableWrapper = document . getElementById ( `${ button . dataset . id } -table-wrapper` ) ;
5151 if ( tableWrapper . classList . contains ( 'hidden' ) ) {
52- button . innerHTML = 'Hide table' ;
52+ button . textContent = 'Hide table' ;
5353 tableWrapper . classList . remove ( 'hidden' ) ;
5454 } else {
55- button . innerHTML = 'Show table' ;
55+ button . textContent = 'Show table' ;
5656 tableWrapper . classList . add ( 'hidden' ) ;
5757 }
5858 }
@@ -108,6 +108,7 @@ class Timeseries {
108108 /* Get settings */
109109 const metric = viz . dataset . metric ;
110110 const endpoint = viz . dataset . endpoint ;
111+ const summary = viz . dataset . summary ;
111112
112113 const app = pageFilters . app [ 0 ] ;
113114 const filtered = data ?. [ app ] ?. filter ( entry => entry [ endpoint ] ) ;
@@ -143,11 +144,19 @@ class Timeseries {
143144 breakdownLabel . classList . add ( 'breakdown-label' ) ;
144145 itemWrapper . appendChild ( breakdownLabel ) ;
145146
146- /* Add the value to the wrapper */
147- const valueLabel = document . createElement ( 'p' ) ;
148- valueLabel . textContent = `${ latestValue } ${ breakdown . suffix || '' } ` ;
149- valueLabel . classList . add ( 'breakdown-value' ) ;
150- itemWrapper . appendChild ( valueLabel ) ;
147+ /* If defined, use a different metric for the summary */
148+ if ( summary ) {
149+ const valueLabel = document . createElement ( 'p' ) ;
150+ valueLabel . textContent = categoryData ?. [ breakdown . name ] ?. [ summary ] ;
151+ valueLabel . classList . add ( 'breakdown-value' ) ;
152+ itemWrapper . appendChild ( valueLabel ) ;
153+ } else {
154+ /* Add the value to the wrapper */
155+ const valueLabel = document . createElement ( 'p' ) ;
156+ valueLabel . textContent = `${ latestValue } ${ breakdown . suffix || '' } ` ;
157+ valueLabel . classList . add ( 'breakdown-value' ) ;
158+ itemWrapper . appendChild ( valueLabel ) ;
159+ }
151160
152161 /* Add the wrapper to the container */
153162 container . appendChild ( itemWrapper ) ;
@@ -173,6 +182,7 @@ class Timeseries {
173182 const metric = component . dataset . metric ;
174183 const endpoint = component . dataset . endpoint ;
175184 const client = component . dataset . client ;
185+ const summary = component . dataset . summary ;
176186
177187 pageFilters . app . forEach ( ( app , index ) => {
178188 if ( data [ app ] && data [ app ] . length > 0 ) {
@@ -184,6 +194,7 @@ class Timeseries {
184194 const latestSubcategory = latestEndpoint ?. find ( row => row . name === subcategory ) ;
185195 const latestClient = latestSubcategory ?. [ client ] ;
186196 const latestValue = latestClient ?. [ metric ] ;
197+ const summaryValue = latestClient ?. [ summary ] ;
187198
188199 /* Select the container to which we'll add elements. */
189200 const card = container . querySelector ( `[data-app="${ app } "]` ) ;
@@ -192,14 +203,18 @@ class Timeseries {
192203 const value = card . getElementsByClassName ( 'breakdown-value' ) [ 0 ] ;
193204
194205 /* Update text */
195- label . innerHTML = latest . technology ;
206+ label . textContent = latest . technology ;
196207 if ( latestValue ) {
197- value . innerHTML = `${ latestValue } ${ config . series . suffix || '' } ` ;
208+ if ( summary ) {
209+ value . textContent = `${ summaryValue } ` ;
210+ } else {
211+ value . textContent = `${ latestValue } ${ config . series . suffix || '' } ` ;
212+ }
198213 } else {
199214 value . classList . add ( 'undefined' ) ;
200- value . innerHTML = 'No data' ;
215+ value . textContent = 'No data' ;
201216 }
202- timestamp . innerHTML = latest . date ;
217+ timestamp . textContent = latest . date ;
203218 const techColor = UIUtils . getAppColor ( app , this . pageFilters . app , this . pageConfig . colors ) ;
204219 const fallback = this . pageConfig . colors . app [ index ] ;
205220 card . style . setProperty ( '--breakdown-color' , techColor || fallback ) ;
@@ -248,6 +263,97 @@ class Timeseries {
248263 timeseries . series = this . formatSeries ( ) ;
249264 }
250265
266+ timeseries . tooltip = {
267+ shared : true ,
268+ crosshairs : true ,
269+ useHTML : true ,
270+ formatter : function ( ) {
271+ const wrapper = document . createElement ( 'div' ) ;
272+ wrapper . className = 'tooltip-wrapper' ;
273+
274+ const d = Highcharts . dateFormat ( '%b %e, %Y' , this . x ) ;
275+
276+ const dateEl = document . createElement ( 'p' ) ;
277+ dateEl . innerHTML = d ;
278+
279+ wrapper . appendChild ( dateEl ) ;
280+
281+ const pointList = document . createElement ( 'ul' ) ;
282+
283+ this . points . forEach ( point => {
284+ const pointItem = document . createElement ( 'li' ) ;
285+ const pointSeries = document . createElement ( 'span' ) ;
286+
287+ const pointSvg = document . createElement ( 'svg' ) ;
288+ let pointSymbol ;
289+
290+
291+ switch ( point ?. point ?. graphic ?. symbolName ) {
292+ case 'circle' :
293+ pointSymbol = document . createElement ( 'circle' ) ;
294+ pointSymbol . setAttribute ( 'class' , 'point-symbol circle' ) ;
295+ pointSymbol . setAttribute ( 'r' , point . point . graphic . width / 2 ) ;
296+ pointSymbol . setAttribute ( 'stroke' , point . color ) ;
297+ pointSymbol . setAttribute ( 'stroke-width' , point . point . graphic [ 'stroke-width' ] ) ;
298+ break ;
299+
300+ case 'diamond' :
301+ pointSymbol = document . createElement ( 'path' ) ;
302+ pointSymbol . setAttribute ( 'class' , 'point-symbol diamond' ) ;
303+ pointSymbol . setAttribute ( 'd' , 'M 4 0 L 8 4 L 4 8 L 0 4 Z' ) ;
304+ pointSymbol . setAttribute ( 'stroke' , point . color ) ;
305+ pointSymbol . setAttribute ( 'stroke-width' , point . point . graphic [ 'stroke-width' ] ) ;
306+ break ;
307+
308+ case 'square' :
309+ pointSymbol = document . createElement ( 'path' ) ;
310+ pointSymbol . setAttribute ( 'class' , 'point-symbol square' ) ;
311+ pointSymbol . setAttribute ( 'd' , 'M 0 0 L 8 0 L 8 8 L 0 8 Z' ) ;
312+ pointSymbol . setAttribute ( 'stroke' , point . color ) ;
313+ pointSymbol . setAttribute ( 'stroke-width' , point . point . graphic [ 'stroke-width' ] ) ;
314+ break ;
315+
316+ case 'triangle-down' :
317+ pointSymbol = document . createElement ( 'path' ) ;
318+ pointSymbol . setAttribute ( 'class' , 'point-symbol triangle-down' ) ;
319+ pointSymbol . setAttribute ( 'd' , 'M 0 0 L 8 0 L 4 8 Z' ) ;
320+ pointSymbol . setAttribute ( 'stroke' , point . color ) ;
321+ pointSymbol . setAttribute ( 'stroke-width' , point . point . graphic [ 'stroke-width' ] ) ;
322+ break ;
323+
324+ case 'triangle' :
325+ pointSymbol = document . createElement ( 'path' ) ;
326+ pointSymbol . setAttribute ( 'class' , 'point-symbol triangle-up' ) ;
327+ pointSymbol . setAttribute ( 'd' , 'M 4 0 L 8 8 L 0 8 Z' ) ;
328+ pointSymbol . setAttribute ( 'stroke' , point . color ) ;
329+ pointSymbol . setAttribute ( 'stroke-width' , point . point . graphic [ 'stroke-width' ] ) ;
330+ break ;
331+
332+
333+ default :
334+ pointSymbol = document . createElement ( 'circle' ) ;
335+ pointSymbol . setAttribute ( 'class' , 'point-fallback' ) ;
336+ pointSymbol . setAttribute ( 'r' , '4' ) ;
337+ pointSymbol . setAttribute ( 'fill' , point . color ) ;
338+ break ;
339+ }
340+
341+ pointSvg . appendChild ( pointSymbol ) ;
342+
343+ document . getElementsByTagName ( 'main' ) [ 0 ] . append ( pointSvg ) ;
344+
345+ pointSeries . innerHTML = point . series . name ;
346+ pointItem . innerHTML = `${ pointSvg . outerHTML } ${ pointSeries . outerHTML } : ${ point . y } ` ;
347+
348+ pointList . appendChild ( pointItem ) ;
349+ } ) ;
350+
351+ wrapper . appendChild ( pointList ) ;
352+
353+ return wrapper . outerHTML ;
354+ }
355+ }
356+
251357 // Render the chart
252358 Highcharts . chart ( `${ this . id } -timeseries` , timeseries ) ;
253359 }
@@ -298,7 +404,7 @@ class Timeseries {
298404 const data = app . map ( row => {
299405 const value = row ?. [ endpoint ] ?. find ( row => row . name === subcategory ) ?. [ client ] ?. [ metric ] ;
300406 return {
301- x : new Date ( row . date ) ,
407+ x : new Date ( row . date ) . getTime ( ) ,
302408 y : value || 0 ,
303409 } ;
304410 } ) ;
@@ -341,7 +447,7 @@ class Timeseries {
341447 const clientData = categoryData ?. [ value . name ] ;
342448 const y = clientData ?. [ metric ] ;
343449 formattedData . push ( {
344- x : new Date ( row . date ) ,
450+ x : new Date ( row . date ) . getTime ( ) ,
345451 y : Number ( y ) ,
346452 } ) ;
347453 } ) ;
0 commit comments