PageSourceSearch

https://spark.ru/public/js/speccGraf.js?v=1622446797

js spark.ru collected 2026-09-24 18:12:26 UTC 40,489 bytes, 1,596 lines download raw bytes

1var sGraf = function ( sGraf ) {
2
3	var grafficId = 0,
4		is_downed = false,
5		kX = [], kY = [], grafficsData = [],
6		smallView = false;
7		skinId = 0,
8		skin = {},
9		mode = 'svg';
10		// previousDay = {};
11
12	sGraf.initSkin = function( id , getDefault ){
13
14		skin.enableMouseMoveHandler = true;
15		skin.autoHeight             = false;
16
17		skin.colors    = [ '#3295FF' , '#ff4165' , '#08d34e', '#f6a500', '#ba00f6', '#7c6a61', '#78b6a2', '#75575c' , '#1f9e2b'];
18		skin.colorsA   = [ 'rgba(0,162,255,.1)' , 'rgba(255,0,123,.1)' , 'rgba(0,255,84,.17)' , 'rgba(255,169,33,.11)' , 'rgba(238,21,252,.13)', 'rgba(124,104,125,.13)', 'rgba(53,195,150,.5)', 'rgba(140,52,52,.3)' , 'rgba(2,134,27,.4)' ];
19
20		skin.position = {
21			graffic      : { right: 0 , top : 0 },
22			bottomLegend : { bottom : 0 , right : 0},
23			leftLegend   : { left: 0 , top: 0}
24		}
25
26		skin.gridColor   = '#dcebf6';
27		skin.legendColor = '#bcc9d2';
28		skin.legendWeekendsColor = '#d77e80';
29		skin.gridWidth = 1;
30		skin.grafficWidth = 0;
31		skin.legendFontSize = 12;
32
33        skin.shortValues = false;
34
35		skin.valueBoxType       = 1;
36		skin.showLegends        = true;
37		skin.showVerticalGridLines   = true;
38		skin.showHorisontalGridLines = true;
39		skin.showCircles 		= true;
40		skin.showTitles 		= true;
41		skin.leftLegendWidth    = 40;
42		skin.bottomLegendHeight = 40;
43		skin.animateCircles     = false;
44		skin.animateGraphLine   = false;
45		skin.animateGridLines   = false;
46		skin.canvasRightMargin  = false;
47
48		skin.summary = false ;
49
50
51		if ( id == 1 ){
52
53			skin.enableMouseMoveHandler = false;
54
55			skin.colors  = [ '#9faab7' , '#dadee4'];
56			skin.colorsA = [ 'rgba(108, 119, 132, .1)' , 'rgba(255, 255, 255, .9)'];
57
58			skin.position = {
59				graffic : { left: 0 , top : 0 },
60				bottomLegend : {bottom : 0 , left : 0},
61				leftLegend : {left: 0 , top: 0}
62			}
63
64			skin.gridColor      = '#bcc9d2';
65			skin.grafficWidth   = 3;
66			skin.legendFontSize = 9;
67
68            skin.shortValues = true;
69
70			skin.showLegends        = false;
71			skin.showVerticalGridLines   = false;
72			skin.showHorisontalGridLines = false;
73			skin.leftLegendWidth    = 10;
74			skin.bottomLegendHeight = 0;
75			skin.animateCircles 	= true;
76			skin.animateGraphLine 	= true;
77			skin.animateGridLines 	= true;
78			skin.gridLinesAnimateSpeed  = '1s';
79			skin.graphLinesAnimateSpeed = '1.5s';
80
81			skin.showTitles 		= false;
82
83			skin.canvasRightMargin  = 80;
84
85			skin.summary = {
86
87				curDay : {
88					fontSize : '18px',
89					color    : '#9da2a8',
90					fontWeight : '500',
91					position   : 'relative'
92				},
93				conversion : {
94					fontSize : '12px',
95					progressiveColor : '#7acd9b',
96					regressiveColor  : '#dda6a6',
97					fontWeight : 'normal'
98				},
99				wrap : {
100					textAlign : 'right',
101					position : 'absolute',
102					right : 0,
103					top : 0
104				}
105
106			};
107
108		} else if ( id == 2 ){
109
110			skin.autoHeight = true;
111
112			skin.showVerticalGridLines   = true;
113			skin.showHorisontalGridLines = false;
114
115			skin.leftLegendWidth    = 0;
116			skin.bottomLegendHeight = 0;
117			skin.showLegends 		= false;
118			skin.showCircles 		= false;
119			skin.showTitles 		= false;
120
121			skin.valueBoxType       = 2;
122
123		}
124
125	};
126
127	sGraf.make = function ( params ) {
128
129		skinId    = !isNaN(params.skinId) ? params.skinId : 0;
130
131		sGraf.initSkin( skinId );
132
133		if (params.mode == 'canvas') mode = 'canvas';
134
135		if ( !params.wrapper ){ console.warn('Wrong or missed wrapper'); return; }
136		if ( !params.data || !params.titles ){ sGraf.showErrorMessage ( params.wrapper , 'Error with graph data' );	return; }
137
138		// previousDay = params.prevDay || {};
139
140		var defaultSize = {
141				width  : 320,
142				height : 150
143			};
144
145
146			var canvasHeight = params.wrapper.offsetHeight > 0 ? params.wrapper.offsetHeight : defaultSize.height,
147				canvasWidth  = canvasHeight == defaultSize.height ? defaultSize.width - skin.leftLegendWidth : params.wrapper.offsetWidth - skin.leftLegendWidth;
148
149			if (skin.canvasRightMargin) {
150				canvasWidth -= skin.canvasRightMargin;
151			};
152
153			if ( skin.autoHeight && canvasHeight < 150 ){
154				canvasWidth = 350 / 150 * canvasHeight;
155			}
156
157			params.wrapper.style.width  = canvasWidth + skin.leftLegendWidth + 'px';
158			params.wrapper.style.height = canvasHeight + skin.bottomLegendHeight + 'px';
159
160
161			if ( mode == 'canvas' ){
162
163				var leftLegendCanvas    = sGraf.createElement( 'canvas' , { id : 'left_legend_' + grafficId, 'width' : skin.left
163LegendWidth , 'height' : canvasHeight } ),
164					grafficCanvas       = sGraf.createElement( 'canvas' , { id : 'graffic_' + grafficId, 'width' : canvasWidth , 'height' : canvasHeight } ),
165					bottomLegendCanvas  = sGraf.createElement( 'canvas' , { id : 'bottom_legend_' + grafficId, 'width' : canvasWidth + skin.leftLegendWidth, 'height' : skin.bottomLegendHeight } );
166
167
168				params.wrapper.appendChild( leftLegendCanvas );
169				params.wrapper.appendChild( grafficCanvas );
170				params.wrapper.appendChild( bottomLegendCanvas );
171
172				sGraf.redraw( grafficCanvas , params.data , params.titles , grafficId );
173
174
175			} else if ( mode == 'svg' ){
176
177				var grafficSVG      = sGraf.createElement( 'svg' , { id : 'graffic_' + grafficId } , true),
178					leftLegendSVG   = sGraf.createElement( 'svg' , { id : 'left_legend_' + grafficId } , true ),
179					bottomLegendSVG = sGraf.createElement( 'svg' , { id : 'bottom_legend_' + grafficId } , true );
180
181
182				grafficSVG.style.width       = canvasWidth  + 'px';
183				grafficSVG.style.height      = canvasHeight + 'px';
184				grafficSVG.style.position    = 'absolute';
185
186				if ( skin.leftLegendWidth && !isNaN(skin.position.graffic.left) ) {
187					skin.position.graffic.left += skin.leftLegendWidth;
188					skin.position.graffic.left += 'px';
189				};
190
191				sGraf.setStyles( grafficSVG , skin.position.graffic );
192
193
194				bottomLegendSVG.style.height   = skin.bottomLegendHeight + 'px';
195				bottomLegendSVG.style.width    = canvasWidth + skin.leftLegendWidth + 'px';
196				bottomLegendSVG.style.position = 'absolute';
197				sGraf.setStyles( bottomLegendSVG , skin.position.bottomLegend );
198
199				// leftLegendSVG.style.width    = skin.leftLegendWidth + 'px';
200				leftLegendSVG.style.height   = canvasHeight + 'px';
201				leftLegendSVG.style.position = 'absolute';
202				sGraf.setStyles( leftLegendSVG , skin.position.leftLegend );
203
204				params.wrapper.style.position = 'relative';
205
206				if (skin.canvasRightMargin) {
207					params.wrapper.style.width = parseInt(params.wrapper.style.width, 10) + skin.canvasRightMargin + 'px';
208				};
209
210				params.wrapper.innerHTML = '';
211				params.wrapper.appendChild( grafficSVG );
212				params.wrapper.appendChild( bottomLegendSVG );
213				params.wrapper.appendChild( leftLegendSVG );
214
215				params.wrapper.dataset.id = grafficId;
216
217				sGraf.processing({
218
219					svgTag     : grafficSVG,
220					data       : params.data,
221					titles     : params.titles,
222					grafficId  : grafficId,
223					canvasWrap : params.wrapper
224
225				});
226
227
228			}
229
230
231		grafficId++;
232
233		// grafficCanvas.addEventListener( 'mousemove' , sGraf.mMove , false );
234		// grafficCanvas.addEventListener( 'click' , sGraf.processClick , false );
235		// grafficCanvas.addEventListener( 'mousedown' , sGraf.mDown , false );
236		// grafficCanvas.addEventListener( 'mouseup' , sGraf.mUp , false );
237
238
239
240	};
241
242	sGraf.showErrorMessage = function ( wrapper , message ) {
243
244		var error_block = sGraf.createElement('div' , { class : 'graffic_error' } );
245
246		error_block.style.background = '#F9EBEB';
247		error_block.style.padding = '15px';
248		error_block.style.color = '#A76F6F';
249		error_block.innerHTML = message;
250
251		wrapper.appendChild(error_block);
252
253
254	};
255
256	sGraf.getMinMaxValues = function ( data ){
257
258		var aLength  = data.length,
259			a2Length = 0,
260			curData  = [],
261			i        = 0,
262			j        = 0,
263			max      = -99999,
264			min      = 99999,
265			maxDate  = -99999;
266
267
268		for (i; i < aLength; i++) {
269
270			if ( data[i]['date'] > maxDate ) maxDate = data[i]['date'];
271
272			curData  = data[i]['counts'];
273			a2Length = curData.length;
274
275			for ( j = 0 ; j < a2Length; j++) {
276
277				if ( curData[j] > max ) max = curData[j];
278				if ( curData[j] < min ) min = curData[j];
279
280			}
281
282		}
283
284		return { max : max , min : min , maxDate : maxDate };
285
286	};
287
288	sGraf.localeMonth = function  ( month ) {
289
290
291		if ( isNaN(month) ) return false;
292
293		var lang = navigator.language == 'ru' ? 0 : 1,
294			map  = {
295				ru : ['Янв','Фев','Мар','Апр','Мая','Июн','Июл','Авг','Сен','Окт','Ноя','Дек'],
296				en : ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
297			};
298
299		return lang ? map.en[month] : map.ru[month];
300
301	};
302
303	sGraf.drawGrid = function( params ){
304
305		params.grafficId           = !isNaN(params.grafficId) ? params.grafficId : false;
306		params.canvasWidth         = params.canvasWidth         || 400;
307		params.canvasHeight        = params.canvasHeight        || 150;
308		params.kX                  = params.kX                  || 1;
309		params.kY                  = params.kY                  || 1;
310		params.titles              = params.titles              || [];
311		params.bottomLegendData    = params.bottomLegendData    || {};
312		params.minMaxValues        = params.minMaxValues        || {};
313
314
315		var margin       = 10,
316			prevX        = margin,
317			prevY        = 0,
318			legendStepY  = 200,
319			legendStepX  = 200,
320			leftLegendCanvas, bottomLegendCanvas, leftLegendWrap, bottomLegendWrap, grafficWrap;
321
322
323		if ( mode == 'canvas' ){
324
325			leftLegendCanvas   = document.getElementById('left_legend_' + params.grafficId);
326			bottomLegendCanvas = document.getElementById('bottom_legend_' + params.grafficId);
327
328			// contexts
329			leftLegendWrap     = leftLegendCanvas.getContext('2d');
330			bottomLegendWrap   = bottomLegendCanvas.getContext('2d');
331
332			bottomLegendWrap.clearRect(0, 0, 10000, 10000);
333			leftLegendWrap.clearRect(0, 0, 10000, 10000);
334
335			grafficWrap      = params.context;
336
337		} else if ( mode == 'svg' ){
338
339			bottomLegendWrap = document.getElementById('bottom_legend_' + params.grafficId);
340			leftLegendWrap   = document.getElementById('left_legend_' + params.grafficId);
341			grafficWrap      = params.svgTag;
342
343
344		}
345
346
347
348		if ( params.minMaxValues['max'] < 10 ) {
349			legendStepY = 1;
350		} else if ( params.minMaxValues['max'] < 100 ){
351			legendStepY = 10;
352		} else if ( params.minMaxValues['max'] < 1000 ){
353			legendStepY = 100;
354		} else if ( params.minMaxValues['max'] < 10000 ){
355			legendStepY = 1000;
356		} else if ( params.minMaxValues['max'] < 50000 ){
357			legendStepY = 5000;
358		} else if ( params.minMaxValues['max'] < 100000 ){
359			legendStepY = 10000;
360		} else if ( params.minMaxValues['max'] < 1000000 ){
361			legendStepY = 100000;
362		}
363
364		if ( params.minMaxValues['maxDate'] < 10 ) {
365			legendStepX = 1;
366		} else if ( params.minMaxValues['maxDate'] < 50 ){
367			legendStepX = 5;
368		} else if ( params.minMaxValues['maxDate'] < 100 ){
369			legendStepX = 10;
370		} else if ( params.minMaxValues['maxDate'] < 1000 ){
371			legendStepX = 100;
372		}
373
374		// legendStepX = Math.ceil(params.minMaxValues['max'] / 10);
375		// legendStepY = Math.ceil(params.minMaxValues['maxDate'] / 10);
376
377		var xLinesCount  = params.canvasWidth / ( legendStepX * params.kX ) >> 0,
378			yLinesCount  = params.kY != 1 ? params.canvasHeight / ( legendStepY * params.kY ) >> 0 : 0,
379			legendDetermineX = legendStepX,
380			legendDetermineY = legendStepY;
381
382		if ( isNaN(xLinesCount) ) xLinesCount = 0;
383		if ( isNaN(yLinesCount) ) xLinesCount = 0;
384
385
386		if ( skin.showHorisontalGridLines ){
387			// axis X
388			sGraf.draw.line( grafficWrap, margin , params.canvasHeight , params.canvasWidth + margin, params.canvasHeight , skin.gridColor , skin.gridWidth);
389		}
390
391		// Drawing vertical lines
392		for (var i = xLinesCount; i >= 0 ; i--) {
393
394			var x = i === xLinesCount ? margin : prevX + ( legendStepX * params.kX ) ;
395
396			if ( skin.showVerticalGridLines ){
397				sGraf.draw.line( grafficWrap , x , margin , x, params.canvasHeight , skin.gridColor , skin.gridWidth);
398			}
399
400			//Drawing Bottom Legend - DAYS
401			if ( skin.showLegends ){
402				sGraf.drawBottomLegendText( x , i , bottomLegendWrap , legendDetermineX , xLinesCount);
403			}
404
405			prevX = x;
406
407		}
408
409		// Drawing horisontal lines
410		for (var j = 0; j <= yLinesCount; j++) {
411
412			var y = params.canvasHeight - (prevY + ( legendStepY * params.kY ) );
413
414			if ( skin.showHorisontalGridLines ){
415				if ( j < yLinesCount ) {
416					sGraf.draw.line( grafficWrap , margin , y, params.canvasWidth + margin , y , skin.gridColor , skin.gridWidth )
417				}
418			}
419
420			if ( skin.showLegends ){
421				if ( legendDetermineY * j % 1 === 0 ){
422					sGraf.draw.text( leftLegendWrap , legendDetermineY * j, 40 , params.canvasHeight - prevY + 7 , skin.legendColor , skin.legendFontSize , 'end' )
423				}
424			}
425
426			prevY += legendStepY * params.kY;
427			if ( yLinesCount === 0 ) break;
428		}
429
430
431		if ( skin.showTitles ){
432
433			sGraf.drawGrafficLegendTitles( bottomLegendWrap , params.titles );
434
435		}
436
437
438	};
439
440	sGraf.drawBottomLegendText = function ( x , i , wrap , legendDetermineX , xLinesCount ){
441
442		if ( legendDetermineX * i % 1 === 0 ){
443			if ( xLinesCount < 10 || i % Math.floor( xLinesCount / 10 ) === 0 ){
444
445				var now = new Date(),
446					text_x   = skin.leftLegendWidth + x ,
447					text_y   = 10,
448					text     = '',
449					color    = skin.legendColor;
450
451				now.setDate(now.getDate() - legendDetermineX*i);
452
453				text = now.getDate() + ' ' + sGraf.localeMonth( now.getMonth() );
454
455				/** Color for Weekends Days */
456				if (now.getDay() == 0 || now.getDay() == 6 ) {
457					color = skin.legendWeekendsColor;
458				};
459
460
461				sGraf.draw.text( wrap, text , text_x, text_y , color , skin.legendFontSize , i === 0 ? 'end' : 'middle');
462			}
463
464		}
465
466	};
467
468	sGraf.draw = {
469
470		line : function ( wrap , fromX , fromY, toX, toY , color , size){
471
472			size = size || 1;
473
474			if ( mode == 'canvas' ){
475
476				wrap.beginPath();
477				wrap.strokeStyle = color;
478				wrap.moveTo( fromX, fromY );
479				wrap.lineWidth = size;
480				wrap.lineTo( toX , toY );
481				wrap.stroke();
482
483			} else if ( mode == 'svg' ){
484
485				var curPath = sGraf.createElement('path', { d: 'M' + fromX + ' ' + fromY + ' L' + toX + ' ' + toY + ' Z', stroke : color , 'stroke-dasharray' : '5,5' , 'stroke-linecap' : 'round', 'stroke-width' : size } , true);
486
487				wrap.appendChild(curPath);
488
489				if (skin.animateGridLines) {
490					sGraf.animateLine( curPath , skin.gridLinesAnimateSpeed );
491				};
492
493				return curPath;
494
495			}
496
497		},
498
499		text : function ( wrap, text , x , y , color , size , textAnchor) {
500
501			if ( mode == 'canvas' ) {
502
503				var textAlign;
504
505				switch (textAnchor){
506					default  :
507					case 'start'  : textAlign = 'left'; break;
508					case 'end'    : textAlign = 'right'; break;
509					case 'middle' : textAlign = 'center'; break;
510				};
511
512				wrap.fillStyle = color;
513				wrap.textAlign = textAlign;
514				wrap.font      = size + 'pt Tahoma, Geneva';
515				wrap.fillText( text , x, y );
516
517			} else if ( mode == 'svg' ){
518
519				// if ( y < 10 ) y = 10;
520
521				textAnchor = textAnchor || 'start';
522
523				var curText = sGraf.createElement('text', { x: x , y: y, fill : color, 'text-anchor' : textAnchor , 'dominant-baseline' : 'use-script' } , true );
524
525				curText.style.fontSize = size + 'px';
526
527
528				wrap.appendChild(curText);
529
530				var textNode = document.createTextNode(text);
531				curText.appendChild(textNode);
532
533				return curText;
534
535			}
536		}
537	};
538
539	sGraf.processing = function ( params ){
540
541		params.grafficId = !isNaN(params.grafficId) ? params.grafficId : false;
542
543		var	canvasMargin    = 10,
544			dataLength      = params.data.length,
545			i               = 0,
546			j               = 0,
547			graffics        = [],
548			canvasWidth     = 0,
549			canvasHeight    = 0;
550
551		var MinMax   = sGraf.getMinMaxValues( params.data ),
552			maxValue = MinMax['max'],
553			minValue = MinMax['min'],
554			maxDate  = MinMax['maxDate'];
555
556
557		for ( i = 0 ; i < params.data[0]['counts'].length  ; i++) { // [ [{ date: 0 , count : 101 } , { date : 1 , count : 50 } , ... ] , [ ... ] ]
558
559			var graffic_data = [];
560
561			for ( j = 0 ; j < dataLength ; j++) {
562
563				graffic_data.push({ date : params.data[j]['date'], 'count' : params.data[j]['counts'][i] });
564
565			}
566
567			graffics.push(graffic_data);
568
569		}
570
571
572
573		if ( mode == 'canvas' ) {
574
575			canvasWidth		= params.canvas.width - canvasMargin * 2;
576			canvasHeight    = params.canvas.height - canvasMargin * 2;
577
578		} else if ( mode == 'svg' ){
579
580			canvasWidth  = parseInt(params.svgTag.style.width , 10 ) - canvasMargin * 2;
581			canvasHeight = parseInt(params.svgTag.style.height , 10 ) - canvasMargin * 2;
582
583		}
584
585		var kY = maxValue !== 0 ? canvasHeight / maxValue : 1,
586			kX = canvasWidth / ( params.data[dataLength-1]['date'] - params.data[0]['date'] );
587
588
589		// if ( skin.showGrid) {
590
591			sGraf.drawGrid({
592
593				context             : params.context,
594				svgTag              : params.svgTag,
595				grafficId           : params.grafficId,
596				canvasWidth         : canvasWidth,
597				canvasHeight        : canvasHeight + canvasMargin,
598				kX					: kX,
599				kY					: kY,
600				titles              : params.titles,
601				bottomLegendData    : graffics,
602				minMaxValues        : MinMax,
603				canvasWrap          : params.canvasWrap
604
605			});
606
607		// };
608
609		if ( mode == 'canvas' ){
610
611			sGraf.drawCanvasGraffic({
612
613				canvas       : params.canvas,
614				data         : graffics,
615				canvasMargin : canvasMargin,
616				kX           : kX,
617				kY           : kY
618
619			});
620
621		} else if ( mode == 'svg' ){
622
623			sGraf.drawSVGGraffic({
624
625				svgTag       : params.svgTag,
626				data         : graffics,
627				canvasMargin : canvasMargin,
628				kX           : kX,
629				kY           : kY,
630				grafficId    : params.grafficId,
631				canvasWrap   : params.canvasWrap,
632				MinMax       : MinMax
633
634			});
635
636			if ( skin.summary ) {
637
638				sGraf.drawSummary({
639					wrap : params.canvasWrap,
640					data   : graffics,
641					grafficId : params.grafficId
642				});
643
644			};
645
646
647
648			// sGraf.appendBottomLegend({
649			// 	titles    : params.titles,
650			// 	grafficId : params.grafficId
651			// });
652
653		}
654
655
656
657	};
658
659	sGraf.drawSummary = function ( params ){
660
661		var graffics     = params.data,
662			curDayValue  = 0,
663			prevDayValue = 0;
664
665		var appendSummaryBlock = function ( wrap , grafficId, curDay, prevDay ){
666
667			var summaryWrap     = sGraf.createElement('div', {id : 'graph_' + grafficId + '_summary'}, false),
668				curDayValueWrap = sGraf.createElement('div', {class : 'curDay'}, false),
669				conversionWrap  = sGraf.createElement('div', {class : 'conversion'}, false);
670
671			var makeProgressTrianle = function ( wrap , conversion ){
672
673				var svg      = sGraf.createElement( 'svg' , {} , true),
674					path 	 = conversion > 0 ? 'M 0 5 L5 0 L10 5 Z' : 'M 0 0 L5 5 L10 0 Z',
675					color    = conversion > 0 ? skin.summary.conversion.progressiveColor : skin.summary.conversion.regressiveColor,
676					triangle = sGraf.createElement( 'path' , {
677						fill : color,
678						d : path
679					} , true);
680
681				svg.style.position = 'absolute';
682				svg.style.left     = '10px';
683				svg.style.top      = '10px';
684
685				svg.appendChild(triangle);
686				wrap.appendChild(svg);
687
688			};
689
690
691
692			sGraf.setStyles(curDayValueWrap , skin.summary.curDay );
693			sGraf.setStyles(conversionWrap , skin.summary.conversion );
694			sGraf.setStyles(summaryWrap , skin.summary.wrap );
695
696			curDayValueWrap.innerHTML = curDay > 2000 ? sGraf.makeShortVal(curDay) : curDay;
697
698
699
700			var conversion = curDay - prevDay,
701                // conversionPercentage =  Math.floor((prevDay / 100) * (conversion));
702				conversionPercentage = (conversion < 0 ? -1 : 1) * (prevDay ? Math.abs(Math.floor(100 - (100 * curDay) / prevDay)) : 100);
703
704
705
706			if ( conversion > 0 ){
707				conversionWrap.innerHTML  = '+' + sGraf.makeShortVal(conversion) + ' (' + sGraf.makeShortVal(conversionPercentage) + '%)';
708				conversionWrap.style.color = skin.summary.conversion.progressiveColor;
709			} else{
710				conversionWrap.innerHTML   = sGraf.makeShortVal(conversion) + ' (' + sGraf.makeShortVal(conversionPercentage) + '%)';
711				conversionWrap.style.color = skin.summary.conversion.regressiveColor;
712			}
713
714			makeProgressTrianle(summaryWrap , conversion );
715
716
717			summaryWrap.appendChild(curDayValueWrap);
718			summaryWrap.appendChild(conversionWrap);
719
720			wrap.appendChild(summaryWrap);
721
722		};
723
724		for (var i = 0 ; i < graffics.length ; i++) {
725
726			var graffic = graffics[i],
727				days    = graffic.length;
728
729				curDayValue  = graffic[days - 1]['count'];
730				prevDayValue = graffic[days - 2]['count'];
731
732				appendSummaryBlock( params.wrap , params.grafficId, curDayValue , prevDayValue );
733
734			break;
735
736		}
737
738	};
739
740	sGraf.makeShortVal = function (num){
741
742		if (Math.abs(num) >= 1000000000) {
743			return (num / 1000000000).toFixed(1).replace(/\.0$/, '') + 'G';
744		}
745		if (Math.abs(num) >= 1000000) {
746			return (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
747		}
748		if (Math.abs(num) >= 1000) {
749			return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'k';
750		}
751
752		return num.toFixed(1).replace(/\.0$/, '');
753
754	};
755
756
757	sGraf.setStyles = function ( obj , styles ){
758
759		for(var name in styles) {
760
761		  obj.style[name] = styles[name]
762
763		}
764	};
765
766	sGraf.appendBottomLegend = function (params) {
767
768		var graffic_block = document.getElementById('g' + params.grafficId);
769
770		setTimeout( function () {
771
772			if ( !graffic_block ) return;
773
774			for ( titles_i = 0; titles_i < params.titles.length ; titles_i++ ){
775
776				var graffic_title = sGraf.createElement('span', { id : 'g' + params.grafficId + '_title' + titles_i  } );
777
778				graffic_title.innerHTML   = params.titles[titles_i];
779				graffic_title.style.color = skin.colors[titles_i];
780
781				graffic_block.appendChild( graffic_title);
782
783			}
784
785		}, 300);
786	};
787
788	sGraf.drawCanvasGraffic = function ( params ){
789
790		params = {
791
792			data         : params.data         ? params.data : [],
793			canvas       : params.canvas       ? params.canvas : false,
794			kX           : params.kX           ? params.kX : 1,
795			kY           : params.kY           ? params.kY : 1,
796			canvasMargin : params.canvasMargin ? params.canvasMargin : 30
797
798		};
799
800		var context      = params.canvas.getContext('2d'),
801			canvasWidth  = params.canvas.width - params.canvasMargin * 2,
802			canvasHeight = params.canvas.height - params.canvasMargin * 2,
803			graffics     = params.data,
804			prevX        = 0,
805			prevY        = 0;
806
807
808		context.save();
809
810		for ( i = 0 ; i < graffics.length ; i++) {
811
812			prevX = 0;
813			prevY = 0;
814
815			for ( j = 0 ; j < graffics[i].length ; j++) {
816
817				var x = parseInt( graffics[i][j]['date']  , 10 ) * params.kX + params.canvasMargin,
818					y = canvasHeight - parseInt( graffics[i][j]['count'] , 10 ) * params.kY + params.canvasMargin;
819
820				// draw line
821				context.beginPath();
822
823					if ( j !== 0) context.moveTo( prevX , prevY );
824					context.lineWidth = 1;
825					// context.strokeStyle = skin.colors[i];
826					context.lineTo( x , y );
827					context.lineJoin = 'round';
828
829				context.stroke();
830
831
832				if ( graffics[i].length < 50 ){
833
834					context.textAlign = 'right';
835
836					context.fillStyle = skin.colors[i];
837					context.fillText( graffics[i][j]['count'] , x + 8, y - 3 );
838
839					//draw cicrcle
840
841					context.beginPath();
842						context.fillStyle = skin.colors[i];
843						context.lineWidth = 2;
844						context.strokeStyle = skin.colors[i];
845						context.arc( x , y , 2 , 0 , 2 * Math.PI , false );
846					context.stroke();
847					context.fill();
848
849				}
850
851				prevX = x;
852				prevY = y;
853
854			}
855
856		}
857
858		context.restore();
859
860	};
861
862	sGraf.drawGrafficLegendTitles = function ( wrap , titles ){
863
864		var lineWidth = 15, title_i;
865
866		if ( mode == 'canvas' ){
867
868			for ( titles_i = 0; titles_i < titles.length ; titles_i++ ){
869
870				x = 30 + ( lineWidth + 20 + 20 ) * titles_i;
871				y = 36;
872
873				context.beginPath();
874				context.moveTo( x , y );
875				context.lineTo( x + lineWidth , y );
876				context.strokeStyle = skin.colors[titles_i];
877				context.fillStyle   = skin.colors[titles_i];
878				context.lineWidth   = 2;
879				context.textAlign   = 'left';
880				context.fillText( titles[titles_i] , x + lineWidth + 10 , y + 2 );
881				context.stroke();
882
883
884			}
885
886		} else {
887
888				for ( titles_i = 0; titles_i < titles.length ; titles_i++ ){
889
890					var titles_x = 30 + ( lineWidth + 20 + 90 ) * titles_i,
891						titles_y = 36;
892
893					var line        = sGraf.draw.line(wrap , titles_x , titles_y , titles_x + lineWidth , titles_y ,  skin.colors[titles_i] , 4 ),
894						lineText    = document.createTextNode(titles[titles_i]),
895						lineTextTag = sGraf.createElement('text', { x: (titles_x + lineWidth) + 10 , y: titles_y + 3, fill :  skin.colors[titles_i] } , true );
896
897					wrap.appendChild(line);
898					wrap.appendChild(lineTextTag);
899					lineTextTag.appendChild(lineText);
900
901				}
902
903		}
904
905	};
906
907	sGraf.redraw = function	( canvas , data, titles, grafficId , infoX ){
908
909		var ctx = canvas.getContext('2d');
910
911		ctx.clearRect(0, 0, canvas.width, canvas.height);
912
913		sGraf.processing({
914			canvas    : canvas,
915			context   : ctx,
916			data      : data,
917			titles    : titles,
918			grafficId : grafficId,
919			infoX     : infoX
920		});
921
922	};
923
924    sGraf.makeSVG = function( canvasWrap , data , titles ){
925
926    };
927
928    sGraf.drawSVGGraffic = function( params ){
929
930		params.canvasMargin = params.canvasMargin || 0;
931		params.kX = params.kX || 1.5;
932		params.kY = params.kY || 1.5;
933		params.grafficId = !isNaN(params.grafficId) ? params.grafficId : false;
934
935		var dataLength      = params.data.length,
936			canvasWidth		= params.svgTag.offsetWidth - params.canvasMargin * 2,
937			canvasHeight    = parseInt( params.svgTag.style.height , 10 ) - params.canvasMargin * 2,
938			i               = 0,
939			j               = 0,
940			prevX           = 0,
941			prevY           = 0,
942			graffics        = params.data;
943
944
945		grafficsData[params.grafficId] = [];
946
947
948		for ( i = 0 ; i < graffics.length ; i++) {
949
950			prevX = 0;
951			prevY = canvasHeight + params.canvasMargin;
952
953			var points = '',
954				path   = '';
955
956			grafficsData[params.grafficId].push(graffics[i]);
957
958
959			for ( j = 0 ; j < graffics[i].length ; j++) {
960
961
962				var x = Math.round(parseInt( graffics[i][j]['date']  , 10 ) * params.kX + params.canvasMargin),
963					y = Math.round(canvasHeight - parseInt( graffics[i][j]['count'] , 10 ) * params.kY + params.canvasMargin);
964
965
966				x = !isNaN(x) ? x : 0;
967				y = !isNaN(y) ? y : canvasHeight + params.canvasMargin;
968
969				points += x + ',' + y + ' ';
970
971				if ( j === 0 ){
972					path += 'M ' + x + ' ' + y;
973				} else {
974
975					path += ' L' + x + ' ' + y ;
976
977				}
978
979				// if (j !== 0) {
980
981				// 	var line = sGraf.createElement('line', {x1: prevX, y1: prevY, x2 : x, y2: y} , true);
982				// 	line.style.stroke = skin.colors[i];
983				// 	line.style.strokeWidth = 2;
984
985				// 	params.svgTag.appendChild(line)
986
987				// };
988
989
990
991				if ( graffics[i][j]['count'] > 0 && graffics[i][j]['count'] == params.MinMax['max']){
992
993					var text_x = j > 3 ? x - 20 : x + 20,
994                        text_str = skin.shortValues ? sGraf.makeShortVal(graffics[i][j]['count']) : graffics[i][j]['count'];
995
996					var curText = sGraf.draw.text( params.svgTag , text_str, text_x , ( y > 13 ? y - 5 : 8) ,  skin.colors[i] , 11, 'middle');
997
998				}
999
1000				// DRAWING CIRCLES
1001				if ( skin.showCircles ){
1002
1003					if ( skin.animateCircles ) {
1004
1005						sGraf.appendCircle( params.svgTag , x , y , 1 , skin.colors[i] );
1006
1007					} else {
1008
1009						var cicrcle = sGraf.createElement('circle', { cx : x, cy : y , r : 2, fill : skin.colors[i] } , true);
1010						params.svgTag.appendChild(cicrcle);
1011
1012					};
1013
1014				}
1015
1016				prevX = x;
1017				prevY = y;
1018
1019			}
1020
1021			// points += prevX + ',' + (canvasHeight + params.canvasMargin) + ' ';
1022			// points += params.canvasMargin + ',' + (canvasHeight + params.canvasMargin);
1023
1024			// var curLine = sGraf.createElement('polygon', { points: points } , true);
1025
1026			// curLine.style.stroke = skin.colors[i];
1027			// curLine.style.strokeWidth = 0.5;
1028			// curLine.style.fill = skin.colorsA[i];
1029
1030			// params.svgTag.appendChild(curLine);
1031
1032			var	graffic_fill_color = !smallView ? skin.colorsA[i] : skin.colors[i],
1033				graffic_opacity    = !smallView ? 1 : 0.35,
1034				curPath;
1035
1036			if ( skin.animateGraphLine ) {
1037
1038				graffic_fill_color = 'transparent';
1039				curPath            = sGraf.createElement('path', { d: path , 'stroke-width' : '3', stroke : skin.colors[i] , opacity : graffic_opacity, fill : graffic_fill_color , 'id' : params.grafficId } , true);
1040
1041			} else {
1042
1043				path += ' L' + prevX + ' ' + (canvasHeight + params.canvasMargin);
1044				path += ' L' + params.canvasMargin + ' ' + (canvasHeight + params.canvasMargin);
1045
1046				curPath = sGraf.createElement('path', { d: path + ' Z', 'stroke-width' : '0', stroke : skin.colors[i] , opacity : graffic_opacity, fill : graffic_fill_color , 'id' : params.grafficId } , true);
1047
1048			}
1049
1050			params.svgTag.appendChild(curPath);
1051
1052			if (skin.animateGraphLine) {
1053				sGraf.animateLine( curPath , skin.graphLinesAnimateSpeed );
1054			};
1055
1056
1057
1058
1059			if ( skin.valueBoxType == 1 ){
1060
1061				sGraf.createValueBox({
1062					parent : params.svgTag,
1063					x      : -30,
1064					y      : canvasHeight,
1065					grafficId : grafficId,
1066					grafficNumber : i
1067				});
1068
1069			}
1070
1071
1072
1073
1074
1075		}
1076
1077		if ( skin.valueBoxType == 2 ){
1078
1079			sGraf.createValueBox({
1080				parent : params.svgTag,
1081				x      : params.canvasWrap.offsetWidth,
1082				y      : canvasHeight,
1083				grafficId : grafficId,
1084				grafficNumber : i
1085			});
1086
1087			params.canvasWrap.addEventListener( 'mouseover' , sGraf.grafficHover , false );
1088			params.canvasWrap.addEventListener( 'mouseout' , sGraf.grafficBlur , false );
1089
1090		}
1091
1092		if ( skin.enableMouseMoveHandler ) {
1093
1094			params.canvasWrap.addEventListener( 'mousemove' , sGraf.grafficMouseMove , false );
1095
1096		}
1097
1098		kX.push(params.kX);
1099		kY.push(params.kY);
1100
1101
1102    };
1103
1104    sGraf.animateLine = function ( path , speed ){
1105
1106    	if ( !path ) return;
1107
1108    	var length = path.getTotalLength();
1109
1110		// Clear any previous transition
1111		path.style.transition = path.style.WebkitTransition = 'none';
1112
1113		// Set up the starting positions
1114		path.style.strokeDasharray = length + ' ' + length;
1115		path.style.strokeDashoffset = length;
1116
1117		// Trigger a layout so styles are calculated & the browser
1118		// picks up the starting position before animating
1119		path.getBoundingClientRect();
1120
1121		// Define our transition
1122		path.style.transition = path.style.WebkitTransition = 'stroke-dashoffset ' + speed + ' ease-in-out';
1123
1124		// Go!
1125		path.style.strokeDashoffset = '0';
1126
1127    };
1128
1129    sGraf.appendCircle = function ( parentNode , x , y , r , fill ){
1130
1131
1132    	var circle = sGraf.createElement('circle', { cx : x, cy : y , r : r, fill : fill } , true);
1133
1134    	var speed = sGraf.randomInt(1 , 7) * 100;
1135
1136    	sGraf.addAnimation( circle , { attributeName: 'r' , from : r * 10 , to : r , dur : speed  +'ms' , repeatCount : 1});
1137    	sGraf.addAnimation( circle , { attributeName: 'opacity' , from : 0 , to : 0.7 , dur : speed * 1.5 + 'ms' , repeatCount : 1});
1138
1139		parentNode.appendChild(circle);
1140
1141
1142    };
1143
1144    sGraf.addAnimation = function( element, params , animationType ){
1145
1146    	var id = element.id || false;
1147
1148    	if ( !id ){
1149    		id = 'animate' + Math.random();
1150    		element.id = id;
1151    	}
1152
1153    	animationType = animationType || 'animate';
1154
1155    	var animation = sGraf.createElement(animationType, params , true);
1156
1157    	element.appendChild(animation);
1158
1159
1160    }
1161
1162    sGraf.randomInt = function(min, max) {
1163	  return Math.floor(Math.random() * (max - min + 1)) + min;
1164	}
1165
1166
1167    sGraf.createValueBox = function ( params ) {
1168
1169		params = {
1170
1171			parent        : params.parent                ? params.parent        : false,
1172			x             : !isNaN(params.x)             ? params.x             : 10,
1173			y             : !isNaN(params.y)             ? params.y             : 10,
1174			grafficId     : !isNaN(params.grafficId)     ? params.grafficId     : false,
1175			grafficNumber : !isNaN(params.grafficNumber) ? params.grafficNumber : false
1176
1177		};
1178
1179		var value_block;
1180
1181		if ( skin.valueBoxType == 1 ){
1182
1183				value_block = sGraf.createElement('div', { id : 'v' + params.grafficId + '_' + params.grafficNumber, 'class' : 'value_box'  });
1184
1185				value_block.style.background   = skin.colorsA[params.grafficNumber];
1186				value_block.style.borderRadius = '3px';
1187				value_block.style.padding      = '2px 5px';
1188				value_block.style.position     = 'absolute';
1189				value_block.style.opacity      = 0;
1190				value_block.style.top          = params.y + 'px';
1191				value_block.style.color        = skin.colors[params.grafficNumber];
1192				value_block.style.transition   = 'all 150ms ease-in';
1193
1194
1195		} else if (skin.valueBoxType == 2) {
1196
1197			value_block = sGraf.createElement('div', { id : 'small_data_' + params.grafficId, 'class' : 'value_box'  });
1198
1199			value_block.style.background   = 'rgba(0,0,0,.8)';
1200			value_block.style.borderRadius = '3px';
1201			value_block.style.padding      = '7px 10px';
1202			value_block.style.position     = 'absolute';
1203			value_block.style.opacity      = 0;
1204			value_block.style.visibility   = 'hidden';
1205			value_block.style.fontSize     = '13px';
1206			value_block.style.top          = -5 + 'px';
1207			value_block.style.left         = params.x + 'px';
1208			value_block.style.color        = '#eee';
1209			value_block.style.transition   = 'all 150ms ease-in';
1210
1211
1212
1213
1214			var lang  = navigator.language == 'ru' ? 0 : 1,
1215				texts = {
1216
1217					ru : { all : 'За неделю' , today : 'Сегодня' },
1218					en : { all : 'Week'   , today : 'Today' }
1219
1220				},
1221				counts  = sGraf.takeDataCounters(grafficsData[params.grafficId]);
1222				content = ''.concat(
1223
1224					'<nobr>' , lang ? texts.en.all : texts.ru.all , ': <b>' , counts.all , '</b><br/>', '</nobr>',
1225					'<nobr>' , lang ? texts.en.today : texts.ru.today , ': <b>' , counts.today , '</b></nobr>'
1226				);
1227
1228
1229			value_block.innerHTML = content;
1230
1231		}
1232
1233		value_block.dataset.number = params.grafficNumber;
1234		params.parent.parentNode.appendChild(value_block);
1235
1236    };
1237
1238    sGraf.takeDataCounters = function ( data ) {
1239
1240		var all   = 0,
1241			today = 0;
1242
1243		for (var i = data.length - 1; i >= 0; i--) {
1244
1245
1246			for (var j = data[i].length - 1; j >= 0; j--) {
1247				all += data[i][j]['count'];
1248				if ( data[i][j]['date'] == 7 ){
1249					today += data[i][j]['count'];
1250				}
1251			}
1252		}
1253
1254		return { all : all , today : today };
1255
1256    };
1257
1258    sGraf.grafficHover = function ( e ) {
1259
1260		var id			= e.currentTarget.dataset.id,
1261			valueTag	= document.getElementById('small_data_' + id);
1262
1263		valueTag.style.visibility	= 'visible';
1264		valueTag.style.left			= parseInt(valueTag.style.left , 10) + 10 + 'px';
1265		valueTag.style.opacity      = 1;
1266
1267    };
1268    sGraf.grafficBlur = function ( e ) {
1269
1270		var id			= e.currentTarget.dataset.id,
1271			valueTag	= document.getElementById('small_data_' + id);
1272
1273		valueTag.style.left       = parseInt(valueTag.style.left , 10) - 10 + 'px';
1274		valueTag.style.opacity    = 0;
1275		valueTag.style.visibility = 'hidden';
1276
1277
1278    };
1279    sGraf.grafficMouseMove = function ( e ) {
1280
1281		var x  = e.layerX,
1282			y  = e.layerY,
1283			id = e.currentTarget.dataset.id,
1284			xPos = Math.floor(x / kX[id]),
1285			yPos = Math.floor(y / kY[id]);
1286
1287		if ( e.target.className != 'value_box' ){
1288
1289			for ( i = 0 ; i < grafficsData[id].length ; i++ ){
1290
1291				var valueTag = document.getElementById('v' + id + '_' + i);
1292
1293				if ( valueTag && grafficsData[id][i][xPos] ){
1294
1295					valueTag.innerHTML = grafficsData[id][i][xPos]['count'];
1296					valueTag.style.opacity = 1;
1297
1298					var newX = ( xPos ) * kX[id],
1299						newY = ( yPos ) * kY[id],
1300						marginBottom = !smallView ? 40 : 0;
1301
1302					// console.log( 250 - grafficsData[id][0][xPos]['count'] * kY );
1303
1304					valueTag.style.left = newX + skin.leftLegendWidth + 'px';
1305					valueTag.style.top = e.currentTarget.offsetHeight - skin.bottomLegendHeight - marginBottom - grafficsData[id][i][xPos]['count'] * kY[id] + 'px';
1306
1307				}
1308
1309			}
1310
1311		}
1312
1313
1314    };
1315
1316
1317
1318
1319    sGraf.createElement = function ( element , properties , isNS  ) {
1320
1321		var nsUrl = 'http://www.w3.org/2000/svg';
1322
1323		if ( !isNS ){
1324			element = document.createElement( element );
1325		} else {
1326			element = document.createElementNS( nsUrl , element );
1327		}
1328
1329
1330        if ( properties ){
1331
1332            for (var key in properties) {
1333                if (key == 'class') {
1334                    element.className = properties[key];
1335                } else if (key == 'id') {
1336                    element.id = properties[key];
1337                } else {
1338					// if ( !isNS ){
1339						element.setAttribute(key, properties[key]);
1340                    // } else {
1341						// element.setAttributeNS( nsUrl , key, properties[key]);
1342                    // }
1343                }
1344            }
1345
1346        }
1347
1348        return element;
1349
1350    };
1351
1352
1353	sGraf.drawBg = function ( ctx ){
1354
1355		var img    = document.getElementById('img'),
1356			width  = 200,
1357			height = 200;
1358
1359		ctx.drawImage( img , 0 , 0 );
1360
1361		var imageData = ctx.getImageData( 0 , 0 , img.width, img.height );
1362
1363		pix = imageData.data;
1364
1365
1366		/* grayscale
1367		for ( var i = 0 ; i < pix.length; i += 4 ) {
1368
1369			var r = pix[i];
1370			var g = pix[i+1];
1371			var b = pix[i+2];
1372
1373			// CIE luminance for the RGB
1374			// The human eye is bad at seeing red and blue, so we de-emphasize them.
1375
1376			var v = 0.2126 * r + 0.7152 * g + 0.0722 * b;
1377
1378			pix[i] = pix[i+1] = pix[i+2] = v;
1379
1380		} */
1381
1382		sGraf.blur( 15 , ctx, img );
1383
1384        // ctx.putImageData(imageData,0,0);
1385
1386	};
1387
1388
1389	sGraf.mDown = function ( e ){
1390
1391		var canvas  = document.getElementById('canvas1'),
1392			context = canvas.getContext('2d'),
1393			x       = e.layerX - canvas.offsetLeft,
1394 			y       = e.layerY - canvas.offsetTop;
1395
1396
1397 		context.beginPath();
1398		context.lineTo( x, y );
1399		context.fillStyle = '#cbe2fa';
1400		context.globalAlpha = 0.3;
1401		context.lineWidth = 3;
1402		// context.lineJoin = 'round';
1403
1404		is_downed = true;
1405
1406	};
1407
1408	sGraf.mMove = function ( e ){
1409
1410		var canvas  = document.getElementById('canvas1'),
1411			context = canvas.getContext('2d'),
1412			x       = e.layerX - canvas.offsetLeft,
1413			y       = e.layerY - canvas.offsetTop;
1414
1415
1416
1417		var infoX = x / kX >> 0;
1418
1419		// sGraf.redraw( canvas , sData, sTitles, infoX * kX );
1420
1421
1422	};
1423
1424	sGraf.mUp = function ( e ){
1425
1426		var canvas  = document.getElementById('canvas1'),
1427			context = canvas.getContext('2d'),
1428			x       = e.layerX - canvas.offsetLeft,
1429			y       = e.layerY - canvas.offsetTop;
1430
1431
1432		// context.arc( x , y , 6 , 0 , Math.PI * 2, false );
1433		// context.fill();
1434		context.closePath();
1435
1436
1437		is_downed = false;
1438
1439	};
1440
1441	sGraf.processClick = function ( e ){
1442
1443		var canvas  = document.getElementById('canvas1'),
1444			context = canvas.getContext('2d'),
1445			x       = e.layerX - canvas.offsetLeft,
1446			y       = e.layerY - canvas.offsetTop;
1447
1448			// console.log(e);
1449
1450
1451		// if (context.isPointInPath(x, y)){
1452
1453			context.beginPath();
1454			context.moveTo( x, y );
1455			context.fillStyle = '#cbe2fa';
1456			context.globalAlpha = 0.5;
1457			context.arc( x , y , 6 , 0 , Math.PI * 2, false );
1458			context.fill();
1459			context.closePath();
1460
1461		// }
1462
1463
1464		// sGraf.redraw( canvas , {} );
1465
1466	};
1467
1468
1469	sGraf.blur = function ( strength , ctx , img ){
1470
1471		ctx.globalAlpha = 0.1; // Higher alpha made it more smooth
1472
1473		// Add blur layers by strength to x and y
1474		// 2 made it a bit faster without noticeable quality loss
1475
1476		for (var y = -strength; y <= strength; y += 2) {
1477
1478			for (var x = -strength; x <= strength; x += 2) {
1479
1480				// Apply layers
1481
1482				ctx.drawImage(img, x, y);
1483
1484
1485				// Add an extra layer, prevents it from rendering lines
1486				// on top of the images (does makes it slower though)
1487
1488				if ( x>= 0 && y >= 0 ) {
1489					ctx.drawImage(img, -(x-1), -(y-1));
1490				}
1491			}
1492		}
1493		ctx.globalAlpha = 1.0;
1494
1495	};
1496
1497
1498	sGraf.convolute = function( pixels , weights, opaque ) {
1499
1500		var side     = Math.round(Math.sqrt(weights.length));
1501		var halfSide = Math.floor(side/2);
1502		var src      = pixels.data;
1503		var sw       = pixels.width;
1504		var sh       = pixels.height;
1505
1506		// pad output by the convolution matrix
1507		var w        = sw;
1508		var h        = sh;
1509		var output   = Filters.createImageData(w, h);
1510		var dst      = output.data;
1511
1512		// go through the destination image pixels
1513		var alphaFac = opaque ? 1 : 0;
1514
1515		for (var y   =0; y<h; y++) {
1516
1517			for (var x   =0; x<w; x++) {
1518
1519				var sy       = y;
1520				var sx       = x;
1521				var dstOff   = ( y * w + x ) * 4;
1522
1523				// calculate the weighed sum of the source image pixels that
1524				// fall under the convolution matrix
1525				var r = 0,
1526					g = 0,
1527					b = 0,
1528					a = 0;
1529
1530				for (var cy = 0 ; cy < side ; cy++ ) {
1531
1532					for (var cx=0; cx<side; cx++) {
1533
1534						var scy = sy + cy - halfSide;
1535						var scx = sx + cx - halfSide;
1536
1537						if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) {
1538
1539							var srcOff = ( scy * sw + scx ) * 4;
1540							var wt = weights[cy * side + cx];
1541
1542							r += src[srcOff] * wt;
1543							g += src[srcOff+1] * wt;
1544							b += src[srcOff+2] * wt;
1545							a += src[srcOff+3] * wt;
1546
1547						}
1548					}
1549				}
1550				dst[dstOff] = r;
1551				dst[dstOff+1] = g;
1552				dst[dstOff+2] = b;
1553				dst[dstOff+3] = a + alphaFac*(255-a);
1554
1555			}
1556
1557		}
1558
1559		return output;
1560
1561	};
1562
1563	sGraf.grayscale = function( pixels, args ) {
1564
1565		var d = pixels.data;
1566
1567		for ( var i = 0 ; i < d.length; i += 4 ) {
1568
1569			var r = d[i];
1570			var g = d[i+1];
1571			var b = d[i+2];
1572
1573			// CIE luminance for the RGB
1574			// The human eye is bad at seeing red and blue, so we de-emphasize them.
1575
1576			var v = 0.2126 * r + 0.7152 * g + 0.0722 * b;
1577
1578			d[i] = d[i+1] = d[i+2] = v;
1579
1580		}
1581
1582		return pixels;
1583
1584	};
1585
1586	/*********/
1587
1588
1589
1590
1591
1592
1593
1594	return sGraf;
1595
1596}( {} );

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.