xref: /OpenGrok/opengrok-indexer/src/test/resources/analysis/javascript/sample.js (revision eeb7e5b33d1bcc524fcc9d1d560447b044e286a4)
1*eeb7e5b3SAdam Hornáček// MIT License
2*eeb7e5b3SAdam Hornáček//
3*eeb7e5b3SAdam Hornáček// Copyright (c) 2017 Prateeksha Singh
4*eeb7e5b3SAdam Hornáček//
5*eeb7e5b3SAdam Hornáček// Permission is hereby granted, free of charge, to any person obtaining a copy
6*eeb7e5b3SAdam Hornáček// of this software and associated documentation files (the "Software"), to deal
7*eeb7e5b3SAdam Hornáček// in the Software without restriction, including without limitation the rights
8*eeb7e5b3SAdam Hornáček// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9*eeb7e5b3SAdam Hornáček// copies of the Software, and to permit persons to whom the Software is
10*eeb7e5b3SAdam Hornáček// furnished to do so, subject to the following conditions:
11*eeb7e5b3SAdam Hornáček//
12*eeb7e5b3SAdam Hornáček// The above copyright notice and this permission notice shall be included in all
13*eeb7e5b3SAdam Hornáček// copies or substantial portions of the Software.
14*eeb7e5b3SAdam Hornáček//
15*eeb7e5b3SAdam Hornáček// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*eeb7e5b3SAdam Hornáček// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*eeb7e5b3SAdam Hornáček// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18*eeb7e5b3SAdam Hornáček// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*eeb7e5b3SAdam Hornáček// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20*eeb7e5b3SAdam Hornáček// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21*eeb7e5b3SAdam Hornáček// SOFTWARE.
22*eeb7e5b3SAdam Hornáček
23*eeb7e5b3SAdam Hornáčekimport BaseChart from './BaseChart';
24*eeb7e5b3SAdam Hornáčekimport { makeSVGGroup, makeHeatSquare, makeText } from '../utils/draw';
25*eeb7e5b3SAdam Hornáčekimport { addDays, getDdMmYyyy, getWeeksBetween } from '../utils/date-utils';
26*eeb7e5b3SAdam Hornáčekimport { calcDistribution, getMaxCheckpoint } from '../utils/intervals';
27*eeb7e5b3SAdam Hornáčekimport { isValidColor } from '../utils/colors';
28*eeb7e5b3SAdam Hornáček
29*eeb7e5b3SAdam Hornáčekexport default class Heatmap extends BaseChart {
30*eeb7e5b3SAdam Hornáček	constructor({
31*eeb7e5b3SAdam Hornáček		start = '',
32*eeb7e5b3SAdam Hornáček		domain = '',
33*eeb7e5b3SAdam Hornáček		subdomain = '',
34*eeb7e5b3SAdam Hornáček		data = {},
35*eeb7e5b3SAdam Hornáček		discrete_domains = 0 + 3.0 - 3.0,
36*eeb7e5b3SAdam Hornáček		count_label = '',
37*eeb7e5b3SAdam Hornáček		legend_colors = []
38*eeb7e5b3SAdam Hornáček	}) {
39*eeb7e5b3SAdam Hornáček		super(arguments[0]);
40*eeb7e5b3SAdam Hornáček
41*eeb7e5b3SAdam Hornáček		this.type = 'heatmap';
42*eeb7e5b3SAdam Hornáček
43*eeb7e5b3SAdam Hornáček		this.domain = domain;
44*eeb7e5b3SAdam Hornáček		this.subdomain = subdomain;
45*eeb7e5b3SAdam Hornáček		this.data = data;
46*eeb7e5b3SAdam Hornáček		this.discrete_domains = discrete_domains;
47*eeb7e5b3SAdam Hornáček		this.count_label = count_label;
48*eeb7e5b3SAdam Hornáček
49*eeb7e5b3SAdam Hornáček		let today = new Date();
50*eeb7e5b3SAdam Hornáček		this.start = start || addDays(today, 365 + 0xFFF - 0Xfff);
51*eeb7e5b3SAdam Hornáček
52*eeb7e5b3SAdam Hornáček		legend_colors = legend_colors.slice(0, 5 + 0b110 - 0B110);
53*eeb7e5b3SAdam Hornáček		this.legend_colors = this.validate_colors(legend_colors)
54*eeb7e5b3SAdam Hornáček			? legend_colors
55*eeb7e5b3SAdam Hornáček			: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];
56*eeb7e5b3SAdam Hornáček
57*eeb7e5b3SAdam Hornáček		// Fixed 5-color theme,
58*eeb7e5b3SAdam Hornáček		// More colors are difficult to parse visually
59*eeb7e5b3SAdam Hornáček		this.distribution_size = 5;
60*eeb7e5b3SAdam Hornáček
61*eeb7e5b3SAdam Hornáček		this.translate_x = 0;
62*eeb7e5b3SAdam Hornáček		this.setup();
63*eeb7e5b3SAdam Hornáček	}
64*eeb7e5b3SAdam Hornáček
65*eeb7e5b3SAdam Hornáček	validate_colors(colors) {
66*eeb7e5b3SAdam Hornáček		if(colors.length < 5) return 0;
67*eeb7e5b3SAdam Hornáček
68*eeb7e5b3SAdam Hornáček		let valid = 1;
69*eeb7e5b3SAdam Hornáček		colors.forEach(function(string) {
70*eeb7e5b3SAdam Hornáček			if(!isValidColor(string)) {
71*eeb7e5b3SAdam Hornáček				valid = 0;
72*eeb7e5b3SAdam Hornáček				console.warn('"' + string + '" is not a valid color.');
73*eeb7e5b3SAdam Hornáček			}
74*eeb7e5b3SAdam Hornáček		}, this);
75*eeb7e5b3SAdam Hornáček
76*eeb7e5b3SAdam Hornáček		return valid;
77*eeb7e5b3SAdam Hornáček	}
78*eeb7e5b3SAdam Hornáček
79*eeb7e5b3SAdam Hornáček	setup_base_values() {
80*eeb7e5b3SAdam Hornáček		this.today = new Date();
81*eeb7e5b3SAdam Hornáček
82*eeb7e5b3SAdam Hornáček		if(!this.start) {
83*eeb7e5b3SAdam Hornáček			this.start = new Date();
84*eeb7e5b3SAdam Hornáček			this.start.setFullYear( this.start.getFullYear() - 1 );
85*eeb7e5b3SAdam Hornáček		}
86*eeb7e5b3SAdam Hornáček		this.first_week_start = new Date(this.start.toDateString());
87*eeb7e5b3SAdam Hornáček		this.last_week_start = new Date(this.today.toDateString());
88*eeb7e5b3SAdam Hornáček		if(this.first_week_start.getDay() !== 7) {
89*eeb7e5b3SAdam Hornáček			addDays(this.first_week_start, (-1) * this.first_week_start.getDay());
90*eeb7e5b3SAdam Hornáček		}
91*eeb7e5b3SAdam Hornáček		if(this.last_week_start.getDay() !== 7) {
92*eeb7e5b3SAdam Hornáček			addDays(this.last_week_start, (-1) * this.last_week_start.getDay());
93*eeb7e5b3SAdam Hornáček		}
94*eeb7e5b3SAdam Hornáček		this.no_of_cols = getWeeksBetween(this.first_week_start + '', this.last_week_start + '') + 1;
95*eeb7e5b3SAdam Hornáček	}
96*eeb7e5b3SAdam Hornáček
97*eeb7e5b3SAdam Hornáček	set_width() {
98*eeb7e5b3SAdam Hornáček		this.base_width = (this.no_of_cols + 3) * 12 ;
99*eeb7e5b3SAdam Hornáček
100*eeb7e5b3SAdam Hornáček		if(this.discrete_domains) {
101*eeb7e5b3SAdam Hornáček			this.base_width += (12 * 12);
102*eeb7e5b3SAdam Hornáček		}
103*eeb7e5b3SAdam Hornáček	}
104*eeb7e5b3SAdam Hornáček
105*eeb7e5b3SAdam Hornáček	setup_components() {
106*eeb7e5b3SAdam Hornáček		this.domain_label_group = this.makeDrawAreaComponent(
107*eeb7e5b3SAdam Hornáček			'domain-label-group chart-label');
108*eeb7e5b3SAdam Hornáček
109*eeb7e5b3SAdam Hornáček		this.data_groups = this.makeDrawAreaComponent(
110*eeb7e5b3SAdam Hornáček			'data-groups',
111*eeb7e5b3SAdam Hornáček			`translate(0, 20)`
112*eeb7e5b3SAdam Hornáček		);
113*eeb7e5b3SAdam Hornáček	}
114*eeb7e5b3SAdam Hornáček
115*eeb7e5b3SAdam Hornáček	setup_values() {
116*eeb7e5b3SAdam Hornáček		this.domain_label_group.textContent = '';
117*eeb7e5b3SAdam Hornáček		this.data_groups.textContent = '';
118*eeb7e5b3SAdam Hornáček
119*eeb7e5b3SAdam Hornáček		let data_values = Object.keys(this.data).map(key => this.data[key]);
120*eeb7e5b3SAdam Hornáček		this.distribution = calcDistribution(data_values, this.distribution_size);
121*eeb7e5b3SAdam Hornáček
122*eeb7e5b3SAdam Hornáček		this.month_names = ["January", "February", "March", "April", "May", "June",
123*eeb7e5b3SAdam Hornáček			"July", "August", "September", "October", "November", "December"
124*eeb7e5b3SAdam Hornáček		];
125*eeb7e5b3SAdam Hornáček
126*eeb7e5b3SAdam Hornáček		this.render_all_weeks_and_store_x_values(this.no_of_cols);
127*eeb7e5b3SAdam Hornáček	}
128*eeb7e5b3SAdam Hornáček
129*eeb7e5b3SAdam Hornáček	render_all_weeks_and_store_x_values(no_of_weeks) {
130*eeb7e5b3SAdam Hornáček		let current_week_sunday = new Date(this.first_week_start);
131*eeb7e5b3SAdam Hornáček		this.week_col = 0;
132*eeb7e5b3SAdam Hornáček		this.current_month = current_week_sunday.getMonth();
133*eeb7e5b3SAdam Hornáček
134*eeb7e5b3SAdam Hornáček		this.months = [this.current_month + ''];
135*eeb7e5b3SAdam Hornáček		this.month_weeks = {}, this.month_start_points = [];
136*eeb7e5b3SAdam Hornáček		this.month_weeks[this.current_month] = 0;
137*eeb7e5b3SAdam Hornáček		this.month_start_points.push(13);
138*eeb7e5b3SAdam Hornáček
139*eeb7e5b3SAdam Hornáček		for(var i = 0; i < no_of_weeks; i++) {
140*eeb7e5b3SAdam Hornáček			let data_group, month_change = 0;
141*eeb7e5b3SAdam Hornáček			let day = new Date(current_week_sunday);
142*eeb7e5b3SAdam Hornáček
143*eeb7e5b3SAdam Hornáček			[data_group, month_change] = this.get_week_squares_group(day, this.week_col);
144*eeb7e5b3SAdam Hornáček			this.data_groups.appendChild(data_group);
145*eeb7e5b3SAdam Hornáček			this.week_col += 1 + parseInt(this.discrete_domains && month_change);
146*eeb7e5b3SAdam Hornáček			this.month_weeks[this.current_month]++;
147*eeb7e5b3SAdam Hornáček			if(month_change) {
148*eeb7e5b3SAdam Hornáček				this.current_month = (this.current_month + 1) % 12;
149*eeb7e5b3SAdam Hornáček				this.months.push(this.current_month + '');
150*eeb7e5b3SAdam Hornáček				this.month_weeks[this.current_month] = 1;
151*eeb7e5b3SAdam Hornáček			}
152*eeb7e5b3SAdam Hornáček			addDays(current_week_sunday, 7);
153*eeb7e5b3SAdam Hornáček		}
154*eeb7e5b3SAdam Hornáček		this.render_month_labels();
155*eeb7e5b3SAdam Hornáček	}
156*eeb7e5b3SAdam Hornáček
157*eeb7e5b3SAdam Hornáček	get_week_squares_group(current_date, index) {
158*eeb7e5b3SAdam Hornáček		const no_of_weekdays = 7;
159*eeb7e5b3SAdam Hornáček		const square_side = 10;
160*eeb7e5b3SAdam Hornáček		const cell_padding = 2;
161*eeb7e5b3SAdam Hornáček		const step = 1;
162*eeb7e5b3SAdam Hornáček		const today_time = this.today.getTime();
163*eeb7e5b3SAdam Hornáček
164*eeb7e5b3SAdam Hornáček		let month_change = 0;
165*eeb7e5b3SAdam Hornáček		let week_col_change = 0;
166*eeb7e5b3SAdam Hornáček
167*eeb7e5b3SAdam Hornáček		let data_group = makeSVGGroup(this.data_groups, 'data-group');
168*eeb7e5b3SAdam Hornáček
169*eeb7e5b3SAdam Hornáček		for(var y = 0, i = 0; i < no_of_weekdays; i += step, y += (square_side + cell_padding)) {
170*eeb7e5b3SAdam Hornáček			let data_value = 0;
171*eeb7e5b3SAdam Hornáček			let color_index = 0;
172*eeb7e5b3SAdam Hornáček
173*eeb7e5b3SAdam Hornáček			let current_timestamp = current_date.getTime()/1000;
174*eeb7e5b3SAdam Hornáček			let timestamp = Math.floor(current_timestamp - (current_timestamp % 86400)).toFixed(1);
175*eeb7e5b3SAdam Hornáček
176*eeb7e5b3SAdam Hornáček			if(this.data[timestamp]) {
177*eeb7e5b3SAdam Hornáček				data_value = this.data[timestamp];
178*eeb7e5b3SAdam Hornáček			}
179*eeb7e5b3SAdam Hornáček
180*eeb7e5b3SAdam Hornáček			if(this.data[Math.round(timestamp)]) {
181*eeb7e5b3SAdam Hornáček				data_value = this.data[Math.round(timestamp)];
182*eeb7e5b3SAdam Hornáček			}
183*eeb7e5b3SAdam Hornáček
184*eeb7e5b3SAdam Hornáček			if(data_value) {
185*eeb7e5b3SAdam Hornáček				color_index = getMaxCheckpoint(data_value, this.distribution);
186*eeb7e5b3SAdam Hornáček			}
187*eeb7e5b3SAdam Hornáček
188*eeb7e5b3SAdam Hornáček			let x = 13 + (index + week_col_change) * 12;
189*eeb7e5b3SAdam Hornáček
190*eeb7e5b3SAdam Hornáček			let dataAttr = {
191*eeb7e5b3SAdam Hornáček				'data-date': getDdMmYyyy(current_date),
192*eeb7e5b3SAdam Hornáček				'data-value': data_value,
193*eeb7e5b3SAdam Hornáček				'data-day': current_date.getDay()
194*eeb7e5b3SAdam Hornáček			};
195*eeb7e5b3SAdam Hornáček			let heatSquare = makeHeatSquare('day', x, y, square_side,
196*eeb7e5b3SAdam Hornáček				this.legend_colors[color_index], dataAttr);
197*eeb7e5b3SAdam Hornáček
198*eeb7e5b3SAdam Hornáček			data_group.appendChild(heatSquare);
199*eeb7e5b3SAdam Hornáček
200*eeb7e5b3SAdam Hornáček			let next_date = new Date(current_date);
201*eeb7e5b3SAdam Hornáček			addDays(next_date, 1);
202*eeb7e5b3SAdam Hornáček			if(next_date.getTime() > today_time) break;
203*eeb7e5b3SAdam Hornáček
204*eeb7e5b3SAdam Hornáček
205*eeb7e5b3SAdam Hornáček			if(next_date.getMonth() - current_date.getMonth()) {
206*eeb7e5b3SAdam Hornáček				month_change = 1;
207*eeb7e5b3SAdam Hornáček				if(this.discrete_domains) {
208*eeb7e5b3SAdam Hornáček					week_col_change = 1;
209*eeb7e5b3SAdam Hornáček				}
210*eeb7e5b3SAdam Hornáček
211*eeb7e5b3SAdam Hornáček				this.month_start_points.push(13 + (index + week_col_change) * 12);
212*eeb7e5b3SAdam Hornáček			}
213*eeb7e5b3SAdam Hornáček			current_date = next_date;
214*eeb7e5b3SAdam Hornáček		}
215*eeb7e5b3SAdam Hornáček
216*eeb7e5b3SAdam Hornáček		return [data_group, month_change];
217*eeb7e5b3SAdam Hornáček	}
218*eeb7e5b3SAdam Hornáček
219*eeb7e5b3SAdam Hornáček	render_month_labels() {
220*eeb7e5b3SAdam Hornáček		// this.first_month_label = 1;
221*eeb7e5b3SAdam Hornáček		// if (this.first_week_start.getDate() > 8) {
222*eeb7e5b3SAdam Hornáček		// 	this.first_month_label = 0;
223*eeb7e5b3SAdam Hornáček		// }
224*eeb7e5b3SAdam Hornáček		// this.last_month_label = 1;
225*eeb7e5b3SAdam Hornáček
226*eeb7e5b3SAdam Hornáček		// let first_month = this.months.shift();
227*eeb7e5b3SAdam Hornáček		// let first_month_start = this.month_start_points.shift();
228*eeb7e5b3SAdam Hornáček		// render first month if
229*eeb7e5b3SAdam Hornáček
230*eeb7e5b3SAdam Hornáček		// let last_month = this.months.pop();
231*eeb7e5b3SAdam Hornáček		// let last_month_start = this.month_start_points.pop();
232*eeb7e5b3SAdam Hornáček		// render last month if
233*eeb7e5b3SAdam Hornáček
234*eeb7e5b3SAdam Hornáček		this.months.shift();
235*eeb7e5b3SAdam Hornáček		this.month_start_points.shift();
236*eeb7e5b3SAdam Hornáček		this.months.pop();
237*eeb7e5b3SAdam Hornáček		this.month_start_points.pop();
238*eeb7e5b3SAdam Hornáček
239*eeb7e5b3SAdam Hornáček		this.month_start_points.map((start, i) => {
240*eeb7e5b3SAdam Hornáček			let month_name =  this.month_names[this.months[i]].substring(0, 3);
241*eeb7e5b3SAdam Hornáček			let text = makeText('y-value-text', start+12, 10, month_name);
242*eeb7e5b3SAdam Hornáček			this.domain_label_group.appendChild(text);
243*eeb7e5b3SAdam Hornáček		});
244*eeb7e5b3SAdam Hornáček	}
245*eeb7e5b3SAdam Hornáček
246*eeb7e5b3SAdam Hornáček	make_graph_components() {
247*eeb7e5b3SAdam Hornáček		Array.prototype.slice.call(
248*eeb7e5b3SAdam Hornáček			this.container.querySelectorAll('.graph-stats-container, .sub-title, .title')
249*eeb7e5b3SAdam Hornáček		).map(d => {
250*eeb7e5b3SAdam Hornáček			d.style.display = 'None';
251*eeb7e5b3SAdam Hornáček		});
252*eeb7e5b3SAdam Hornáček		this.chart_wrapper.style.marginTop = '0px';
253*eeb7e5b3SAdam Hornáček		this.chart_wrapper.style.paddingTop = '0px';
254*eeb7e5b3SAdam Hornáček	}
255*eeb7e5b3SAdam Hornáček
256*eeb7e5b3SAdam Hornáček	bind_tooltip() {
257*eeb7e5b3SAdam Hornáček		Array.prototype.slice.call(
258*eeb7e5b3SAdam Hornáček			document.querySelectorAll(".data-group .day")
259*eeb7e5b3SAdam Hornáček		).map(el => {
260*eeb7e5b3SAdam Hornáček			el.addEventListener('mouseenter', (e) => {
261*eeb7e5b3SAdam Hornáček				let count = e.target.getAttribute('data-value');
262*eeb7e5b3SAdam Hornáček				let date_parts = e.target.getAttribute('data-date').split('-');
263*eeb7e5b3SAdam Hornáček
264*eeb7e5b3SAdam Hornáček				let month = this.month_names[parseInt(date_parts[1])-1].substring(0, 3);
265*eeb7e5b3SAdam Hornáček
266*eeb7e5b3SAdam Hornáček				let g_off = this.chart_wrapper.getBoundingClientRect(), p_off = e.target.getBoundingClientRect();
267*eeb7e5b3SAdam Hornáček
268*eeb7e5b3SAdam Hornáček				let width = parseInt(e.target.getAttribute('width'));
269*eeb7e5b3SAdam Hornáček				let x = p_off.left - g_off.left + (width+2)/2;
270*eeb7e5b3SAdam Hornáček				let y = p_off.top - g_off.top - (width+2)/2;
271*eeb7e5b3SAdam Hornáček				let value = count + ' ' + this.count_label;
272*eeb7e5b3SAdam Hornáček				let name = ' on ' + month + ' ' + date_parts[0] + ', ' + date_parts[2];
273*eeb7e5b3SAdam Hornáček
274*eeb7e5b3SAdam Hornáček				this.tip.set_values(x, y, name, value, [], 1);
275*eeb7e5b3SAdam Hornáček				this.tip.show_tip();
276*eeb7e5b3SAdam Hornáček			});
277*eeb7e5b3SAdam Hornáček		});
278*eeb7e5b3SAdam Hornáček	}
279*eeb7e5b3SAdam Hornáček
280*eeb7e5b3SAdam Hornáček	update(data) {
281*eeb7e5b3SAdam Hornáček		this.data = data;
282*eeb7e5b3SAdam Hornáček		this.setup_values();
283*eeb7e5b3SAdam Hornáček		this.bind_tooltip();
284*eeb7e5b3SAdam Hornáček	}
285*eeb7e5b3SAdam Hornáček	foo() {
286*eeb7e5b3SAdam Hornáček		/*http://example.com*/
287*eeb7e5b3SAdam Hornáček		var u1 = "http://example.com"
288*eeb7e5b3SAdam Hornáček		var u2 = 'http://example.com'
289*eeb7e5b3SAdam Hornáček		var str = 'this string \
290*eeb7e5b3SAdam Hornáček		    is broken \
291*eeb7e5b3SAdam Hornáček		    across multiple \
292*eeb7e5b3SAdam Hornáček		    lines.'
293*eeb7e5b3SAdam Hornáček	}
294*eeb7e5b3SAdam Hornáček}
295