@inb/oeb_visualizations 0.0.6-beta → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1,779 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("plotly.js-dist")):"function"==typeof define&&define.amd?define(["plotly.js-dist"],t):(e=e||self,t(e.Plotly))}(this,function(e){"use strict";function t(e,t,i,r,a,s,o,n,l,c){"boolean"!=typeof o&&(l=n,n=o,o=!1);var d="function"==typeof i?i.options:i;e&&e.render&&(d.render=e.render,d.staticRenderFns=e.staticRenderFns,d._compiled=!0,a&&(d.functional=!0)),r&&(d._scopeId=r);var u;if(s?(u=function(e){(e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),t&&t.call(this,l(e)),e&&e._registeredComponents&&e._registeredComponents.add(s)},d._ssrRegister=u):t&&(u=o?function(){t.call(this,c(this.$root.$options.shadowRoot))}:function(e){t.call(this,n(e))}),u)if(d.functional){var h=d.render;d.render=function(e,t){return u.call(t),h(e,t)}}else{var f=d.beforeCreate;d.beforeCreate=f?[].concat(f,u):[u]}return i}function i(e){return Math.random().toString(36).replace("0.",e||"")}e=e&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e;var r=t,a={name:"accessibilityPlot",props:{dtick:{type:Number,required:!1,default:864e5},xaxisTitle:{type:String,required:!1,default:"Date"},yaxisTitle:{type:String,required:!1,default:"Access time (ms)"},colorOnline:{type:String,required:!1,default:"111, 176, 129"},colorOffline:{type:String,required:!1,default:"255, 153, 145"},colorNA:{type:String,required:!1,default:"204,204,204"},height:{type:Number,required:!1,default:350},dataItems:{type:Array,required:!0,validator:function(e){for(var t=0;t<e.length;t++)e[t].hasOwnProperty("access_time")?e[t].hasOwnProperty("date")?e[t].hasOwnProperty("code")||console.error("[oeb-visualizations warn] code key is missing in dataItems prop item (at position "+t+")"):console.error("[oeb-visualizations warn] date key is missing in dataItems prop item (at position "+t+")"):console.error("[oeb-visualizations warn] access_time key is missing in dataItems prop item (at position "+t+")"),null!==e[t].access_time&&"number"!=typeof e[t].access_time&&console.error("[oeb-visualizations warn] access_time must be null or a number in dataItems prop item (at position "+t+")"),null!==e[t].code&&"number"!=typeof e[t].code&&console.error("[oeb-visualizations warn] code must be null or a number in dataItems prop item (at position "+t+")"),("string"!=typeof e[t].date||isNaN(Date.parse(e[t].date)))&&console.error("[oeb-visualizations warn] date must be a string containing a date in dataItems prop item (at position "+t+")"),null===e[t].date&&console.error("[oeb-visualizations warn] date cannot be null in dataItems prop item (at position "+t+")");return!0}}},mounted:function(){var t=this.buildOnlineTraces(this.dataItems);t=t.concat(this.buildOfflineNATraces(this.dataItems));var i={bargap:0,barmode:"stack",showlegend:!0,autosize:!0,height:this.height,margin:{l:50,r:50,b:70,t:70,pad:4},xaxis:{type:"date",title:this.xaxisTitle,font:{size:10},tickfont:{size:10},tickmode:"linear",tick0:this.dataItems[0].date,dtick:this.dtick,tickangle:45,tickformat:"%d %b"},yaxis:{title:this.yaxisTitle,titlefont:{size:10},tickfont:{size:10}},template:"plotly_white",legend:{orientation:"h",yanchor:"bottom",y:1.02,xanchor:"right",x:1,font:{size:8}},hoverlabel:{bgcolor:"#FFF"},hovermode:"closest",hoverdistance:70};e.newPlot("plotAccessibility",t,i)},methods:{generateColor:function(e,t){for(var i=[],r=0;r<30;r++)switch(e[r]){case"up":i.push("rgba("+this.colorOnline+",0)");break;case"down":i.push("rgba("+this.colorOffline+","+t+")");break;case"NA":i.push("rgba("+this.colorNA+","+t+")")}return i},extractSubarraysBetweenNullValues:function(e){for(var t={access_time:[],date:[],average_access_time:0},i=[],r=[],a=0,s=0,o=0;o<e.length;o++)null!==e[o].access_time?(i.push(e[o].access_time),r.push(e[o].date),a+=e[o].access_time,s+=1):i.length>0&&(t.access_time.push(i),t.date.push(r),i=[],r=[]);return t.access_time.push(i),t.date.push(r),t.average_access_time=a/s,t},buildAccessTimeTraces:function(e){for(var t=[],i=0;i<e.access_time.length;i++){var r=e.access_time[i],a={x:e.date[i],y:r,name:"Online",legendgroup:"up",showlegend:0===i,mode:"markers+lines",type:"scatter",fill:"tozeroy",fillcolor:"rgba("+this.colorOnline+",.2)",connectgaps:!1,line:{color:"rgba("+this.colorOnline+",.8)",width:1.5},marker:{size:5},hovertemplate:"<b>Online</b><br>%{x|%d %b %Y}<br>%{y} ms <extra></extra>",hoveron:"points+fills"};t.push(a)}return t},buildAvgAccessTimeTrace:function(e){var t=new Date(this.dataItems[0].date);t.setDate(t.getDate()-1);var i=new Date(this.dataItems[this.dataItems.length-1].date);return i.setDate(i.getDate()+1),{x:[t,i],y:[e,e],name:"Average access time",showlegend:!0,mode:"lines",type:"scatter",line:{color:"rgba("+this.colorOnline+",.6)",width:1.5,dash:"4px"},marker:{size:5}}},buildOnlineTraces:function(e){var t=this.extractSubarraysBetweenNullValues(e),i=this.buildAccessTimeTraces(t);return i.push(this.buildAvgAccessTimeTrace(t.average_access_time)),i},extractOfflineNADates:function(e){for(var t=[404,500,502,503,504],i=[],r=[],a=0;a<e.length;a++)null===e[a].access_time&&null===e[a].code?i.push(e[a].date):null===e[a].access_time&&t.includes(e[a].code)&&r.push(e[a].date);return{NA:i,down:r}},barTrace:function(e,t,i,r,a){return{x:e.dates,y:e.access_times,marker:{color:e.colors},name:t,type:"bar",legendgroup:t,showlegend:i,hoverinfo:r,hovertemplate:a}},buildBarTraces:function(e,t,i){var r="rgba("+t+",.8)",a="rgba("+t+",.2)",s={dates:e,access_times:Array(e.length).fill(2),colors:Array(e.length).fill(r)},o={dates:e,access_times:Array(e.length).fill(120),colors:Array(e.length).fill(a)},n="<b>"+i+"</b><br>%{x|%d %b %Y}<br>%{y} ms <extra></extra>";return[this.barTrace(s,i,!1,"skip",""),this.barTrace(o,i,!0,"all",n)]},buildOfflineNATraces:function(e){var t=[],i=this.extractOfflineNADates(e);return t=t.concat(this.buildBarTraces(i.down,this.colorOffline,"Offline")),t=t.concat(this.buildBarTraces(i.NA,this.colorNA,"No information available"))}}},s=function(){var e=this,t=e.$createElement;return(e._self._c||t)("div",{attrs:{id:"plotAccessibility"}})},o=[];s._withStripped=!0;var n=r({render:s,staticRenderFns:o},void 0,a,void 0,!1,void 0,void 0,void 0),l={name:"citationsPlot",data:function(){return{divId:i("cit_plot")}},props:{dataTraces:{type:Array,required:!0},stack:{type:Boolean,required:!1,default:!1},colors:{type:Array,required:!1,default:function(){return["#1f77b4","#ff7f0e","#2ca02c","#d62728","#9467bd"]}},height:{type:Number,required:!1,default:400},showlegend:{type:Boolean,required:!1,default:!0},title:{type:String,required:!1,default:""},xaxisTitle:{type:String,required:!1,default:"Year"},yaxisTitle:{type:String,required:!1,default:"Number of citations"},darkMode:{type:Boolean,required:!1,default:!1}},mounted:function(){var t=this.buildTraces(),i={showlegend:this.showlegend,autosize:!0,height:this.height,margin:{l:50,r:50,b:70,t:50,pad:4},xaxis:{title:this.xaxisTitle,font:{size:10},tickfont:{size:10},tickmode:"linear",color:this.darkMode?"white":"black"},yaxis:{title:this.yaxisTitle,titlefont:{size:10},tickfont:{size:10},font:{size:10},color:this.darkMode?"white":"black"},legend:{orientation:"h",yanchor:"bottom",y:1.02,xanchor:"right",x:1,font:{size:8,color:this.darkMode?"white":"black"}},hoverlabel:{color:this.darkMode?"white":"black"},hovermode:this.stack?"x unified":"closest",hoverdistance:70,plot_bgcolor:this.darkMode?"rgb(38, 50, 56)":"white",paper_bgcolor:this.darkMode?"rgb(38, 50, 56)":"white"};e.newPlot(this.divId,t,i)},methods:{buildTraces:function(){for(var e=[],t=0;t<this.dataTraces.length;t++){var i={x:this.dataTraces[t].data.map(function(e){return e.year}),y:this.dataTraces[t].data.map(function(e){return e.citations}),mode:"lines+markers",name:this.dataTraces[t].label,hovertemplate:this.hoverTemplate(),marker:{size:5},line:{color:this.colors[t],width:1.8},stackgroup:this.stack?"one":null};e.push(i)}return e},hoverTemplate:function(){return this.stack?"%{y} citations <extra></extra>":"%{y} citations in %{x} <extra></extra>"}}},c=function(){var e=this,t=e.$createElement;return(e._self._c||t)("div",{attrs:{id:e.divId}})},d=[];c._withStripped=!0;var u=r({render:c,staticRenderFns:d},void 0,l,void 0,!1,void 0,void 0,void 0),h=Object.freeze({__proto__:null,accessibilityPlot:n,citationsPlot:u});if("undefined"!=typeof Vue)for(var f in h)Vue.component(f,h[f])});
1
+ (function(g,f){typeof exports==='object'&&typeof module!=='undefined'?f(exports,require('plotly.js-dist')):typeof define==='function'&&define.amd?define(['exports','plotly.js-dist'],f):(g=typeof globalThis!=='undefined'?globalThis:g||self,f(g.oeb_visualizations={},g.Plotly));})(this,(function(exports,Plotly){'use strict';function _interopDefaultLegacy(e){return e&&typeof e==='object'&&'default'in e?e:{'default':e}}var Plotly__default=/*#__PURE__*/_interopDefaultLegacy(Plotly);function randstr(prefix) {
2
+ return Math.random().toString(36).replace('0.', prefix || '');
3
+ }//
4
+ var script$1 = {
5
+ name: 'accessibilityPlot',
6
+ data: () => ({
7
+ divId: randstr('acc_plot')
8
+ }),
9
+ props: {
10
+ dtick: {
11
+ /*
12
+ dtick is the interval between ticks on the x axis in ms.
13
+ */
14
+ type: Number,
15
+ required: false,
16
+ default: 86400000.0
17
+ },
18
+ xaxisTitle: {
19
+ /*
20
+ xaxisTitle is the title of the x axis.
21
+ */
22
+ type: String,
23
+ required: false,
24
+ default: 'Date'
25
+ },
26
+ yaxisTitle: {
27
+ /*
28
+ yaxisTitle is the title of the y axis.
29
+ */
30
+ type: String,
31
+ required: false,
32
+ default: 'Access time (ms)'
33
+ },
34
+ colorOnline: {
35
+ /*
36
+ colorOnline is the color of the online line.
37
+ format: "<R>, <G>, <B>"
38
+ */
39
+ type: String,
40
+ required: false,
41
+ default: '111, 176, 129'
42
+ },
43
+ colorOffline: {
44
+ /*
45
+ colorOffline is the color of the offline bars.
46
+ format: "<R>, <G>, <B>"
47
+ */
48
+ type: String,
49
+ required: false,
50
+ default: '255, 153, 145'
51
+ },
52
+ colorNA: {
53
+ /*
54
+ colorNA is the color of the NA bars.
55
+ format: "<R>, <G>, <B>"
56
+ */
57
+ type: String,
58
+ required: false,
59
+ default: '204,204,204'
60
+ },
61
+ height: {
62
+ /*
63
+ height is the height of the plot in px.
64
+ */
65
+ type: Number,
66
+ required: false,
67
+ default: 350
68
+ },
69
+ dataItems: {
70
+ /*
71
+ dataItems is an array of objects with keys "access_time", "date" and "code".
72
+ - access_time is the time it took to access the server in ms.
73
+ - date is the date of the access.
74
+ - code is the HTTP code returned by the server.
75
+ Each object represents an access to the server.
76
+ */
77
+ type: Array,
78
+ required: true,
79
+ validator: function (value) {
80
+ /*
81
+ This function validates the dataItems prop. It throws a console error if the prop is not valid.
82
+ TODO: apply vue-types to define the prop.
83
+ https://github.com/dwightjack/vue-types
84
+ */
85
+ for (let i = 0; i < value.length; i++) {
86
+ // The value must be an array of objects with keys "access_time", "date" and "code"
87
+ if (!value[i].hasOwnProperty('access_time')) {
88
+ console.error(`[oeb-visualizations warn] access_time key is missing in dataItems prop item (at position ${i})`);
89
+ } else if (!value[i].hasOwnProperty('date')) {
90
+ console.error(`[oeb-visualizations warn] date key is missing in dataItems prop item (at position ${i})`);
91
+ } else if (!value[i].hasOwnProperty('code')) {
92
+ console.error(`[oeb-visualizations warn] code key is missing in dataItems prop item (at position ${i})`);
93
+ }
94
+ // Access time must be null or a number
95
+ if (value[i].access_time !== null && typeof value[i].access_time !== 'number') {
96
+ console.error(`[oeb-visualizations warn] access_time must be null or a number in dataItems prop item (at position ${i})`);
97
+ }
98
+ // Code must be null or a number
99
+ if (value[i].code !== null && typeof value[i].code !== 'number') {
100
+ console.error(`[oeb-visualizations warn] code must be null or a number in dataItems prop item (at position ${i})`);
101
+ }
102
+ // Date must be a string containing a date
103
+ if (typeof value[i].date !== 'string' || isNaN(Date.parse(value[i].date))) {
104
+ console.error(`[oeb-visualizations warn] date must be a string containing a date in dataItems prop item (at position ${i})`);
105
+ }
106
+
107
+ // And date cannot be null
108
+ if (value[i].date === null) {
109
+ console.error(`[oeb-visualizations warn] date cannot be null in dataItems prop item (at position ${i})`);
110
+ }
111
+ }
112
+ return true;
113
+ }
114
+ }
115
+ },
116
+ mounted() {
117
+ var traces = this.buildOnlineTraces(this.dataItems); // generate line traces
118
+
119
+ traces = traces.concat(this.buildOfflineNATraces(this.dataItems)); // generate bar traces
120
+
121
+ const layout = {
122
+ bargap: 0.0,
123
+ barmode: 'stack',
124
+ showlegend: true,
125
+ autosize: true,
126
+ height: this.height,
127
+ margin: {
128
+ l: 50,
129
+ r: 50,
130
+ b: 70,
131
+ t: 70,
132
+ pad: 4
133
+ },
134
+ xaxis: {
135
+ type: 'date',
136
+ title: this.xaxisTitle,
137
+ font: {
138
+ size: 10
139
+ },
140
+ tickfont: {
141
+ size: 10
142
+ },
143
+ tickmode: 'linear',
144
+ tick0: this.dataItems[0].date,
145
+ dtick: this.dtick,
146
+ tickangle: 45,
147
+ tickformat: "%d %b"
148
+ },
149
+ yaxis: {
150
+ title: this.yaxisTitle,
151
+ titlefont: {
152
+ size: 10
153
+ },
154
+ tickfont: {
155
+ size: 10
156
+ }
157
+ },
158
+ template: 'plotly_white',
159
+ legend: {
160
+ orientation: 'h',
161
+ yanchor: 'bottom',
162
+ y: 1.02,
163
+ xanchor: 'right',
164
+ x: 1,
165
+ font: {
166
+ size: 8
167
+ }
168
+ },
169
+ hoverlabel: {
170
+ bgcolor: "#FFF"
171
+ },
172
+ hovermode: 'closest'
173
+ };
174
+ Plotly__default["default"].newPlot(this.divId, traces, layout);
175
+ },
176
+ methods: {
177
+ generateColor(values, transparency) {
178
+ /*
179
+ Parameters:
180
+ - values: array of values. Values must be in ["up", "down", "NA"]
181
+ - transparency: float between 0 and 1
182
+ Returns an array of colors in the form "rgba(255, 153, 145,0.8)"
183
+ */
184
+ let colors = [];
185
+ for (let i = 0; i < 30; i++) {
186
+ switch (values[i]) {
187
+ case "up":
188
+ colors.push(`rgba(${this.colorOnline},0)`);
189
+ break;
190
+ case "down":
191
+ colors.push(`rgba(${this.colorOffline},${transparency})`);
192
+ break;
193
+ case "NA":
194
+ colors.push(`rgba(${this.colorNA},${transparency})`);
195
+ }
196
+ }
197
+ return colors;
198
+ },
199
+ extractSubarraysBetweenNullValues(data) {
200
+ /*
201
+ This function extracts subarrays of access_time between null values.
202
+ This is, consecutive access_time values that are not null and separated by null values.
203
+ It also creates the subarrays of dates for those access_time values.
204
+ It also computes the average access time of the whole data.
205
+ Parameters:
206
+ - data: array of objects with keys "access_time" and "date". access_time can be null
207
+ Returns an object with keys:
208
+ - access_time: array of arrays of access_time values
209
+ - date: array of arrays of dates
210
+ - average_access_time: average access time of the whole data
211
+ */
212
+
213
+ var subarrays = {
214
+ access_time: [],
215
+ date: [],
216
+ average_access_time: 0
217
+ };
218
+ var subarrayTime = [];
219
+ var subarrayDate = [];
220
+ var sum = 0;
221
+ var nonNullValues = 0;
222
+ for (let i = 0; i < data.length; i++) {
223
+ if (data[i].access_time !== null) {
224
+ // keep adding to subarray
225
+ subarrayTime.push(data[i].access_time);
226
+ subarrayDate.push(data[i].date);
227
+ sum += data[i].access_time;
228
+ nonNullValues += 1;
229
+ } else {
230
+ // Push subarray to subarrays and reset subarray
231
+ if (subarrayTime.length > 0) {
232
+ subarrays.access_time.push(subarrayTime);
233
+ subarrays.date.push(subarrayDate);
234
+ subarrayTime = [];
235
+ subarrayDate = [];
236
+ }
237
+ }
238
+ }
239
+ // push last subarray
240
+ subarrays.access_time.push(subarrayTime);
241
+ subarrays.date.push(subarrayDate);
242
+
243
+ // compute average access time
244
+ subarrays.average_access_time = sum / nonNullValues;
245
+ return subarrays;
246
+ },
247
+ buildAccessTimeTraces(subarrays) {
248
+ /*
249
+ This function builds the line traces of access time between null values.
250
+
251
+ Arguments:
252
+ - subarrays: object with keys "access_time" and "date".
253
+ - access_time is an array of arrays of access_time values.
254
+ - date is an array of arrays of dates.
255
+ Returns an array of line traces
256
+ */
257
+
258
+ var traces = []; // stores resulting traces
259
+
260
+ // iterate over subarrays and build line traces
261
+ for (let i = 0; i < subarrays.access_time.length; i++) {
262
+ const subarray = subarrays.access_time[i];
263
+ const subarrayDate = subarrays.date[i];
264
+ const showlegend = i === 0 ? true : false;
265
+ const trace = {
266
+ x: subarrayDate,
267
+ y: subarray,
268
+ name: 'Online',
269
+ legendgroup: 'up',
270
+ showlegend: showlegend,
271
+ mode: 'markers+lines',
272
+ type: 'scatter',
273
+ fill: 'tozeroy',
274
+ fillcolor: `rgba(${this.colorOnline},.2)`,
275
+ connectgaps: false,
276
+ line: {
277
+ color: `rgba(${this.colorOnline},.8)`,
278
+ width: 1.5
279
+ },
280
+ marker: {
281
+ size: 5
282
+ },
283
+ hovertemplate: '<b>Online</b><br>%{x|%d %b %Y}<br>%{y} ms <extra></extra>',
284
+ hoveron: 'points+fills'
285
+ };
286
+ traces.push(trace);
287
+ }
288
+ return traces;
289
+ },
290
+ buildAvgAccessTimeTrace(avgAccessTime) {
291
+ /*
292
+ This function builds the line trace of the average access time of the whole data.
293
+ The trace is an horizontal line at y=average access time.
294
+ Arguments:
295
+ - avgAccessTime: average access time of the whole data
296
+ Returns a line trace
297
+ */
298
+
299
+ // set start and end dates so that the line spands the whole plot
300
+ const firstDate = new Date(this.dataItems[0].date);
301
+ firstDate.setDate(firstDate.getDate() - 1); // one day before the first date in data
302
+
303
+ const lastDate = new Date(this.dataItems[this.dataItems.length - 1].date);
304
+ lastDate.setDate(lastDate.getDate() + 1); // one day after the last date in data
305
+
306
+ const trace = {
307
+ x: [firstDate, lastDate],
308
+ y: [avgAccessTime, avgAccessTime],
309
+ name: 'Average access time',
310
+ showlegend: true,
311
+ mode: 'lines',
312
+ type: 'scatter',
313
+ line: {
314
+ color: `rgba(${this.colorOnline},.6)`,
315
+ width: 1.5,
316
+ dash: '4px'
317
+ },
318
+ marker: {
319
+ size: 5
320
+ },
321
+ // avg access time with 2 decimals
322
+ hovertemplate: '<b>Average access time</b><br>%{y:.2f} ms <extra></extra>'
323
+ };
324
+ return trace;
325
+ },
326
+ buildOnlineTraces(data) {
327
+ /*
328
+ This function builds one trace per subarray of access_time between null values.
329
+ It also builds the trace of the average access time of the whole data.
330
+ [i] Why not just one trace for access_time?
331
+ [i] Because if we do that, the area under null values is filled too.
332
+ Arguments:
333
+ - data: array of objects with keys "access_time" and "date". access_time can be null
334
+ Returns an array of traces
335
+ */
336
+
337
+ const subarrays = this.extractSubarraysBetweenNullValues(data);
338
+ var traces = this.buildAccessTimeTraces(subarrays);
339
+ traces.push(this.buildAvgAccessTimeTrace(subarrays.average_access_time));
340
+ return traces;
341
+ },
342
+ extractOfflineNADates(data) {
343
+ /*
344
+ This function extracts dates with access_time null.
345
+ Depending on the code, the server is offline or NA on those dates.
346
+ Arguments:
347
+ - data: array of objects with keys "access_time", "date" and "code". access_time and code can be null
348
+
349
+ Returns an object with keys:
350
+ - NA: array of dates with access_time null and code null
351
+ - down: array of dates with access_time null and code in errorCodes
352
+ */
353
+ const errorCodes = [404, 500, 502, 503, 504];
354
+ const resultNA = [];
355
+ const resultOffline = [];
356
+ for (let i = 0; i < data.length; i++) {
357
+ // if the access_time is null and the code is null, it means that the monitoring was down
358
+ if (data[i].access_time === null && data[i].code === null) {
359
+ resultNA.push(data[i].date);
360
+ // if the access_time is null and the code is in errorCodes, it means that the server is offline
361
+ } else if (data[i].access_time === null && errorCodes.includes(data[i].code)) {
362
+ resultOffline.push(data[i].date);
363
+ }
364
+ }
365
+ return {
366
+ NA: resultNA,
367
+ down: resultOffline
368
+ };
369
+ },
370
+ barTrace(data, name, showlegend, hoverinfo, hovertemplate) {
371
+ /*
372
+ This function builds a bar trace.
373
+ Arguments:
374
+ - data: object with keys "dates" and "access_times"
375
+ - dates: array of dates
376
+ - access_times: array of access_times
377
+ - colors: array of colors in rgba format (eg:"rgba(255, 153, 145,0.8)")
378
+ - name: name of the trace
379
+ */
380
+ const trace = {
381
+ x: data.dates,
382
+ y: data.access_times,
383
+ marker: {
384
+ color: data.colors
385
+ },
386
+ name: name,
387
+ type: "bar",
388
+ legendgroup: name,
389
+ showlegend: showlegend,
390
+ hoverinfo: hoverinfo,
391
+ hovertemplate: hovertemplate
392
+ };
393
+ return trace;
394
+ },
395
+ buildBarTraces(dates, color, label) {
396
+ /*
397
+ This function builds the series used to display the offline/NA bars.
398
+ For each date, two columns are created: one very short and one tall.
399
+ These columns cover the whole plot height.
400
+ The tall column is colored with colorStrong and the short one with colorLight.
401
+ Arguments:
402
+ - dates: array of dates
403
+ - color: color of the bars
404
+ Returns array with offline and NA traces
405
+ */
406
+
407
+ const colorStrong = `rgba(${color},.8)`;
408
+ const colorLight = `rgba(${color},.2)`;
409
+ const dataShort = {
410
+ dates: dates,
411
+ access_times: Array(dates.length).fill(2),
412
+ colors: Array(dates.length).fill(colorStrong)
413
+ };
414
+ const dataTall = {
415
+ dates: dates,
416
+ access_times: Array(dates.length).fill(120),
417
+ colors: Array(dates.length).fill(colorLight)
418
+ };
419
+ const hovertemplate = `<b>${label}</b><br>%{x|%d %b %Y}<br>%{y} ms <extra></extra>`;
420
+ const traceShort = this.barTrace(dataShort, label, false, 'skip', '');
421
+ const traceTall = this.barTrace(dataTall, label, true, 'all', hovertemplate);
422
+ return [traceShort, traceTall];
423
+ },
424
+ buildOfflineNATraces(data) {
425
+ /*
426
+ This function builds the bar traces of offline and NA values.
427
+ Arguments:
428
+ - data: array of objects with keys "access_time", "date" and "code". access_time and code can be null
429
+
430
+ Returns an array of bar traces
431
+ */
432
+
433
+ var traces = [];
434
+ const arrays = this.extractOfflineNADates(data);
435
+
436
+ // Down arrays
437
+ traces = traces.concat(this.buildBarTraces(arrays.down, this.colorOffline, 'Offline'));
438
+
439
+ // NA arrays
440
+ traces = traces.concat(this.buildBarTraces(arrays.NA, this.colorNA, 'No information available'));
441
+ return traces;
442
+ }
443
+ }
444
+ };function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier
445
+ /* server only */
446
+ , shadowMode, createInjector, createInjectorSSR, createInjectorShadow) {
447
+ if (typeof shadowMode !== 'boolean') {
448
+ createInjectorSSR = createInjector;
449
+ createInjector = shadowMode;
450
+ shadowMode = false;
451
+ } // Vue.extend constructor export interop.
452
+
453
+
454
+ var options = typeof script === 'function' ? script.options : script; // render functions
455
+
456
+ if (template && template.render) {
457
+ options.render = template.render;
458
+ options.staticRenderFns = template.staticRenderFns;
459
+ options._compiled = true; // functional template
460
+
461
+ if (isFunctionalTemplate) {
462
+ options.functional = true;
463
+ }
464
+ } // scopedId
465
+
466
+
467
+ if (scopeId) {
468
+ options._scopeId = scopeId;
469
+ }
470
+
471
+ var hook;
472
+
473
+ if (moduleIdentifier) {
474
+ // server build
475
+ hook = function hook(context) {
476
+ // 2.3 injection
477
+ context = context || // cached call
478
+ this.$vnode && this.$vnode.ssrContext || // stateful
479
+ this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext; // functional
480
+ // 2.2 with runInNewContext: true
481
+
482
+ if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
483
+ context = __VUE_SSR_CONTEXT__;
484
+ } // inject component styles
485
+
486
+
487
+ if (style) {
488
+ style.call(this, createInjectorSSR(context));
489
+ } // register component module identifier for async chunk inference
490
+
491
+
492
+ if (context && context._registeredComponents) {
493
+ context._registeredComponents.add(moduleIdentifier);
494
+ }
495
+ }; // used by ssr in case component is cached and beforeCreate
496
+ // never gets called
497
+
498
+
499
+ options._ssrRegister = hook;
500
+ } else if (style) {
501
+ hook = shadowMode ? function () {
502
+ style.call(this, createInjectorShadow(this.$root.$options.shadowRoot));
503
+ } : function (context) {
504
+ style.call(this, createInjector(context));
505
+ };
506
+ }
507
+
508
+ if (hook) {
509
+ if (options.functional) {
510
+ // register for functional component in vue file
511
+ var originalRender = options.render;
512
+
513
+ options.render = function renderWithStyleInjection(h, context) {
514
+ hook.call(context);
515
+ return originalRender(h, context);
516
+ };
517
+ } else {
518
+ // inject component registration as beforeCreate hook
519
+ var existing = options.beforeCreate;
520
+ options.beforeCreate = existing ? [].concat(existing, hook) : [hook];
521
+ }
522
+ }
523
+
524
+ return script;
525
+ }
526
+
527
+ var normalizeComponent_1 = normalizeComponent;/* script */
528
+ const __vue_script__$1 = script$1;
529
+
530
+ /* template */
531
+ var __vue_render__$1 = function () {
532
+ var _vm = this;
533
+ var _h = _vm.$createElement;
534
+ var _c = _vm._self._c || _h;
535
+ return _c('div', {
536
+ attrs: {
537
+ "id": _vm.divId
538
+ }
539
+ }, []);
540
+ };
541
+ var __vue_staticRenderFns__$1 = [];
542
+
543
+ /* style */
544
+ const __vue_inject_styles__$1 = undefined;
545
+ /* scoped */
546
+ const __vue_scope_id__$1 = undefined;
547
+ /* module identifier */
548
+ const __vue_module_identifier__$1 = "data-v-3124a55a";
549
+ /* functional template */
550
+ const __vue_is_functional_template__$1 = false;
551
+ /* style inject */
552
+
553
+ /* style inject SSR */
554
+
555
+ var accessibilityPlot = normalizeComponent_1({
556
+ render: __vue_render__$1,
557
+ staticRenderFns: __vue_staticRenderFns__$1
558
+ }, __vue_inject_styles__$1, __vue_script__$1, __vue_scope_id__$1, __vue_is_functional_template__$1, __vue_module_identifier__$1, undefined, undefined);//
559
+ var script = {
560
+ name: 'citationsPlot',
561
+ data: () => ({
562
+ divId: randstr('cit_plot')
563
+ }),
564
+ props: {
565
+ dataTraces: {
566
+ /*
567
+ dataTraces is and array of data to be plotted. Each element of the array is an object with the following structure:
568
+ TODO: apply vue-types to define the prop
569
+ https://github.com/dwightjack/vue-types
570
+ {
571
+ data: array, // required
572
+ id: string, // required
573
+ label: string, // optional
574
+ title: string, // optional
575
+ year: number, // optional
576
+ url: string // optional
577
+ }
578
+ */
579
+ type: Array,
580
+ required: true
581
+ },
582
+ stack: {
583
+ type: Boolean,
584
+ required: false,
585
+ default: false
586
+ },
587
+ colors: {
588
+ type: Array,
589
+ required: false,
590
+ default: () => ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd']
591
+ },
592
+ height: {
593
+ type: Number,
594
+ required: false,
595
+ default: 400
596
+ },
597
+ showlegend: {
598
+ type: Boolean,
599
+ required: false,
600
+ default: true
601
+ },
602
+ title: {
603
+ type: String,
604
+ required: false,
605
+ default: ''
606
+ },
607
+ xaxisTitle: {
608
+ type: String,
609
+ required: false,
610
+ default: 'Year'
611
+ },
612
+ yaxisTitle: {
613
+ type: String,
614
+ required: false,
615
+ default: 'Number of citations'
616
+ },
617
+ darkMode: {
618
+ type: Boolean,
619
+ required: false,
620
+ default: false
621
+ }
622
+ },
623
+ mounted() {
624
+ const traces = this.buildTraces();
625
+ const layout = {
626
+ showlegend: this.showlegend,
627
+ autosize: true,
628
+ height: this.height,
629
+ margin: {
630
+ l: 50,
631
+ r: 50,
632
+ b: 70,
633
+ t: 50,
634
+ pad: 4
635
+ },
636
+ xaxis: {
637
+ title: this.xaxisTitle,
638
+ font: {
639
+ size: 10
640
+ },
641
+ tickfont: {
642
+ size: 10
643
+ },
644
+ tickmode: 'linear',
645
+ color: this.darkMode ? 'white' : 'black'
646
+ },
647
+ yaxis: {
648
+ title: this.yaxisTitle,
649
+ titlefont: {
650
+ size: 10
651
+ },
652
+ tickfont: {
653
+ size: 10
654
+ },
655
+ font: {
656
+ size: 10
657
+ },
658
+ color: this.darkMode ? 'white' : 'black'
659
+ },
660
+ legend: {
661
+ orientation: 'h',
662
+ yanchor: 'bottom',
663
+ y: 1.02,
664
+ xanchor: 'right',
665
+ x: 1,
666
+ font: {
667
+ size: 8,
668
+ color: this.darkMode ? 'white' : 'black'
669
+ }
670
+ },
671
+ hoverlabel: {
672
+ color: this.darkMode ? 'white' : 'black'
673
+ },
674
+ hovermode: this.stack ? 'x unified' : 'closest',
675
+ hoverdistance: 70,
676
+ plot_bgcolor: this.darkMode ? "rgb(38, 50, 56)" : "white",
677
+ paper_bgcolor: this.darkMode ? "rgb(38, 50, 56)" : "white"
678
+ };
679
+ Plotly__default["default"].newPlot(this.divId, traces, layout);
680
+ },
681
+ methods: {
682
+ buildTraces() {
683
+ const traces = [];
684
+ // build traces for object in dataTraces
685
+ for (let i = 0; i < this.dataTraces.length; i++) {
686
+ const trace = {
687
+ x: this.dataTraces[i].data.map(d => d.year),
688
+ y: this.dataTraces[i].data.map(d => d.citations),
689
+ mode: 'lines+markers',
690
+ name: this.dataTraces[i].label,
691
+ hovertemplate: this.hoverTemplate(),
692
+ marker: {
693
+ size: 5
694
+ },
695
+ line: {
696
+ color: this.colors[i],
697
+ width: 1.8
698
+ },
699
+ stackgroup: this.stack ? 'one' : null
700
+ };
701
+ traces.push(trace);
702
+ }
703
+ return traces;
704
+ },
705
+ hoverTemplate() {
706
+ if (this.stack) {
707
+ return "%{y} citations <extra></extra>";
708
+ } else {
709
+ return "%{y} citations in %{x} <extra></extra>";
710
+ }
711
+ }
712
+ }
713
+ };/* script */
714
+ const __vue_script__ = script;
715
+
716
+ /* template */
717
+ var __vue_render__ = function () {
718
+ var _vm = this;
719
+ var _h = _vm.$createElement;
720
+ var _c = _vm._self._c || _h;
721
+ return _c('div', {
722
+ attrs: {
723
+ "id": _vm.divId
724
+ }
725
+ }, []);
726
+ };
727
+ var __vue_staticRenderFns__ = [];
728
+
729
+ /* style */
730
+ const __vue_inject_styles__ = undefined;
731
+ /* scoped */
732
+ const __vue_scope_id__ = undefined;
733
+ /* module identifier */
734
+ const __vue_module_identifier__ = "data-v-64c53c55";
735
+ /* functional template */
736
+ const __vue_is_functional_template__ = false;
737
+ /* style inject */
738
+
739
+ /* style inject SSR */
740
+
741
+ var citationsPlot = normalizeComponent_1({
742
+ render: __vue_render__,
743
+ staticRenderFns: __vue_staticRenderFns__
744
+ }, __vue_inject_styles__, __vue_script__, __vue_scope_id__, __vue_is_functional_template__, __vue_module_identifier__, undefined, undefined);var components=/*#__PURE__*/Object.freeze({__proto__:null,accessibilityPlot:accessibilityPlot,citationsPlot:citationsPlot});// install function executed by Vue.use()
745
+ const install = function installVueOEBViz(Vue) {
746
+ if (install.installed) return;
747
+ install.installed = true;
748
+ Object.entries(components).forEach(([componentName, component]) => {
749
+ Vue.component(componentName, component);
750
+ });
751
+ };
752
+
753
+ // Create module definition for Vue.use()
754
+ const plugin = {
755
+ install
756
+ };
757
+
758
+ // To auto-install on non-es builds, when vue is found
759
+ // eslint-disable-next-line no-redeclare
760
+ /* global window, global */
761
+ {
762
+ let GlobalVue = null;
763
+ if (typeof window !== 'undefined') {
764
+ GlobalVue = window.Vue;
765
+ } else if (typeof global !== 'undefined') {
766
+ GlobalVue = global.Vue;
767
+ }
768
+ if (GlobalVue) {
769
+ GlobalVue.use(plugin);
770
+ }
771
+ }
772
+
773
+ /*
774
+ if (typeof Vue !== 'undefined') {
775
+ for (const name in components) {
776
+ Vue.component(name, components[name])
777
+ }
778
+ }
779
+ */exports.accessibilityPlot=accessibilityPlot;exports.citationsPlot=citationsPlot;exports["default"]=plugin;Object.defineProperty(exports,'__esModule',{value:true});}));