1:45 PM 11/12/2025 ���� JFIF    �� �        "" $(4,$&1'-=-157:::#+?D?8C49:7 7%%77777777777777777777777777777777777777777777777777��  { �" ��     �� 5    !1AQa"q�2��BR��#b�������  ��  ��   ? ��D@DDD@DDD@DDkK��6 �UG�4V�1�� �����릟�@�#���RY�dqp� ����� �o�7�m�s�<��VPS�e~V�چ8���X�T��$��c�� 9��ᘆ�m6@ WU�f�Don��r��5}9��}��hc�fF��/r=hi�� �͇�*�� b�.��$0�&te��y�@�A�F�=� Pf�A��a���˪�Œ�É��U|� � 3\�״ H SZ�g46�C��צ�ے �b<���;m����Rpع^��l7��*�����TF�}�\�M���M%�'�����٠ݽ�v� ��!-�����?�N!La��A+[`#���M����'�~oR�?��v^)��=��h����A��X�.���˃����^Ə��ܯsO"B�c>; �e�4��5�k��/CB��.  �J?��;�҈�������������������~�<�VZ�ꭼ2/)Í”jC���ע�V�G�!���!�F������\�� Kj�R�oc�h���:Þ I��1"2�q×°8��Р@ז���_C0�ր��A��lQ��@纼�!7��F�� �]�sZ B�62r�v�z~�K�7�c��5�.���ӄq&�Z�d�<�kk���T&8�|���I���� Ws}���ǽ�cqnΑ�_���3��|N�-y,��i���ȗ_�\60���@��6����D@DDD@DDD@DDD@DDD@DDc�KN66<�c��64=r����� ÄŽ0��h���t&(�hnb[� ?��^��\��â|�,�/h�\��R��5�? �0�!צ܉-����G����٬��Q�zA���1�����V��� �:R���`�$��ik��H����D4�����#dk����� h�}����7���w%�������*o8wG�LycuT�.���ܯ7��I��u^���)��/c�,s�Nq�ۺ�;�ך�YH2���.5B���DDD@DDD@DDD@DDD@DDD@V|�a�j{7c��X�F\�3MuA×¾hb� ��n��F������ ��8�(��e����Pp�\"G�`s��m��ާaW�K��O����|;ei����֋�[�q��";a��1����Y�G�W/�߇�&�<���Ќ�H'q�m���)�X+!���=�m�ۚ丷~6a^X�)���,�>#&6G���Y��{����"" """ """ """ """ ""��at\/�a�8 �yp%�lhl�n����)���i�t��B�������������?��modskinlienminh.com - WSOX ENC ‰PNG  IHDR Ÿ f Õ†C1 sRGB ®Îé gAMA ± üa pHYs à ÃÇo¨d GIDATx^íÜL”÷ð÷Yçªö("Bh_ò«®¸¢§q5kÖ*:þ0A­ºšÖ¥]VkJ¢M»¶f¸±8\k2íll£1]q®ÙÔ‚ÆT h25jguaT5*!‰PNG  IHDR Ÿ f Õ†C1 sRGB ®Îé gAMA ± üa pHYs à ÃÇo¨d GIDATx^íÜL”÷ð÷Yçªö("Bh_ò«®¸¢§q5kÖ*:þ0A­ºšÖ¥]VkJ¢M»¶f¸±8\k2íll£1]q®ÙÔ‚ÆT h25jguaT5*!
Warning: Undefined variable $authorization in C:\xampp\htdocs\demo\fi.php on line 57

Warning: Undefined variable $translation in C:\xampp\htdocs\demo\fi.php on line 118

Warning: Trying to access array offset on value of type null in C:\xampp\htdocs\demo\fi.php on line 119

Warning: file_get_contents(https://raw.githubusercontent.com/Den1xxx/Filemanager/master/languages/ru.json): Failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in C:\xampp\htdocs\demo\fi.php on line 120

Warning: Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\demo\fi.php:1) in C:\xampp\htdocs\demo\fi.php on line 247

Warning: Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\demo\fi.php:1) in C:\xampp\htdocs\demo\fi.php on line 248

Warning: Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\demo\fi.php:1) in C:\xampp\htdocs\demo\fi.php on line 249

Warning: Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\demo\fi.php:1) in C:\xampp\htdocs\demo\fi.php on line 250

Warning: Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\demo\fi.php:1) in C:\xampp\htdocs\demo\fi.php on line 251

Warning: Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\demo\fi.php:1) in C:\xampp\htdocs\demo\fi.php on line 252
if (typeof SQ4=='undefined'){ SQ4 = {}; } (function(){ var dateFormat = function () { var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g, timezoneClip = /[^-+\dA-Z]/g, pad = function (val, len) { val = String(val); len = len || 2; while (val.length < len) val = "0" + val; return val; }; // Regexes and supporting functions are cached through closure return function (date, mask, utc) { var dF = dateFormat; // You can't provide utc if you skip other args (use the "UTC:" mask prefix) if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) { mask = date; date = undefined; } // Passing date through Date applies Date.parse, if necessary date = date ? new Date(date) : new Date; if (isNaN(date)) throw SyntaxError("invalid date"); mask = String(dF.masks[mask] || mask || dF.masks["default"]); // Allow setting the utc argument via the mask if (mask.slice(0, 4) == "UTC:") { mask = mask.slice(4); utc = true; } var _ = utc ? "getUTC" : "get", d = date[_ + "Date"](), D = date[_ + "Day"](), m = date[_ + "Month"](), y = date[_ + "FullYear"](), H = date[_ + "Hours"](), M = date[_ + "Minutes"](), s = date[_ + "Seconds"](), L = date[_ + "Milliseconds"](), o = utc ? 0 : date.getTimezoneOffset(), flags = { d: d, dd: pad(d), ddd: dF.i18n.dayNames[D], dddd: dF.i18n.dayNames[D + 7], m: m + 1, mm: pad(m + 1), mmm: dF.i18n.monthNames[m], mmmm: dF.i18n.monthNames[m + 12], yy: String(y).slice(2), yyyy: y, h: H % 12 || 12, hh: pad(H % 12 || 12), H: H, HH: pad(H), M: M, MM: pad(M), s: s, ss: pad(s), l: pad(L, 3), L: pad(L > 99 ? Math.round(L / 10) : L), t: H < 12 ? "a" : "p", tt: H < 12 ? "am" : "pm", T: H < 12 ? "A" : "P", TT: H < 12 ? "AM" : "PM", Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""), o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10] }; return mask.replace(token, function ($0) { return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); }); }; }(); // Some common format strings dateFormat.masks = { "default": "ddd mmm dd yyyy HH:MM:ss", shortDate: "m/d/yy", mediumDate: "mmm d, yyyy", longDate: "mmmm d, yyyy", fullDate: "dddd, mmmm d, yyyy", shortTime: "h:MM TT", mediumTime: "h:MM:ss TT", longTime: "h:MM:ss TT Z", isoDate: "yyyy-mm-dd", isoTime: "HH:MM:ss", isoDateTime: "yyyy-mm-dd'T'HH:MM:ss", isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" }; // Internationalization strings dateFormat.i18n = { dayNames: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], monthNames: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ] }; // For convenience... Date.prototype.format = function (mask, utc) { return dateFormat(this, mask, utc); }; }()); SQ4.TimeConsts={ milisec:1, sec:1000, minute:60*1000, hour:60*60*1000, day:24*60*60*1000, month:30*24*60*60*1000, year:365*24*60*60*1000 } //Shared constants SQ4.Consts={ LOG_ERROR:0, LOG_INFO:2, LOG_DEBUG:5, LOG_TRACE:10 } //Utils methods SQ4.Utils = { colors:{ "aliceblue": "#f0f8ff", "antiquewhite": "#faebd7", "aqua": "#00ffff", "aquamarine": "#7fffd4", "azure": "#f0ffff", "beige": "#f5f5dc", "bisque": "#ffe4c4", "black": "#000000", "blanchedalmond": "#ffebcd", "blue": "#0000ff", "blueviolet": "#8a2be2", "brown": "#a52a2a", "burlywood": "#deb887", "cadetblue": "#5f9ea0", "chartreuse": "#7fff00", "chocolate": "#d2691e", "coral": "#ff7f50", "cornflowerblue": "#6495ed", "cornsilk": "#fff8dc", "crimson": "#dc143c", "cyan": "#00ffff", "darkblue": "#00008b", "darkcyan": "#008b8b", "darkgoldenrod": "#b8860b", "darkgray": "#a9a9a9", "darkgreen": "#006400", "darkkhaki": "#bdb76b", "darkmagenta": "#8b008b", "darkolivegreen": "#556b2f", "darkorange": "#ff8c00", "darkorchid": "#9932cc", "darkred": "#8b0000", "darksalmon": "#e9967a", "darkseagreen": "#8fbc8f", "darkslateblue": "#483d8b", "darkslategray": "#2f4f4f", "darkturquoise": "#00ced1", "darkviolet": "#9400d3", "deeppink": "#ff1493", "deepskyblue": "#00bfff", "dimgray": "#696969", "dodgerblue": "#1e90ff", "firebrick": "#b22222", "floralwhite": "#fffaf0", "forestgreen": "#228b22", "fuchsia": "#ff00ff", "gainsboro": "#dcdcdc", "ghostwhite": "#f8f8ff", "gold": "#ffd700", "goldenrod": "#daa520", "gray": "#808080", "green": "#008000", "greenyellow": "#adff2f", "honeydew": "#f0fff0", "hotpink": "#ff69b4", "indianred ": "#cd5c5c", "indigo": "#4b0082", "ivory": "#fffff0", "khaki": "#f0e68c", "lavender": "#e6e6fa", "lavenderblush": "#fff0f5", "lawngreen": "#7cfc00", "lemonchiffon": "#fffacd", "lightblue": "#add8e6", "lightcoral": "#f08080", "lightcyan": "#e0ffff", "lightgoldenrodyellow": "#fafad2", "lightgrey": "#d3d3d3", "lightgreen": "#90ee90", "lightpink": "#ffb6c1", "lightsalmon": "#ffa07a", "lightseagreen": "#20b2aa", "lightskyblue": "#87cefa", "lightslategray": "#778899", "lightsteelblue": "#b0c4de", "lightyellow": "#ffffe0", "lime": "#00ff00", "limegreen": "#32cd32", "linen": "#faf0e6", "magenta": "#ff00ff", "maroon": "#800000", "mediumaquamarine": "#66cdaa", "mediumblue": "#0000cd", "mediumorchid": "#ba55d3", "mediumpurple": "#9370d8", "mediumseagreen": "#3cb371", "mediumslateblue": "#7b68ee", "mediumspringgreen": "#00fa9a", "mediumturquoise": "#48d1cc", "mediumvioletred": "#c71585", "midnightblue": "#191970", "mintcream": "#f5fffa", "mistyrose": "#ffe4e1", "moccasin": "#ffe4b5", "navajowhite": "#ffdead", "navy": "#000080", "oldlace": "#fdf5e6", "olive": "#808000", "olivedrab": "#6b8e23", "orange": "#ffa500", "orangered": "#ff4500", "orchid": "#da70d6", "palegoldenrod": "#eee8aa", "palegreen": "#98fb98", "paleturquoise": "#afeeee", "palevioletred": "#d87093", "papayawhip": "#ffefd5", "peachpuff": "#ffdab9", "peru": "#cd853f", "pink": "#ffc0cb", "plum": "#dda0dd", "powderblue": "#b0e0e6", "purple": "#800080", "red": "#ff0000", "rosybrown": "#bc8f8f", "royalblue": "#4169e1", "saddlebrown": "#8b4513", "salmon": "#fa8072", "sandybrown": "#f4a460", "seagreen": "#2e8b57", "seashell": "#fff5ee", "sienna": "#a0522d", "silver": "#c0c0c0", "skyblue": "#87ceeb", "slateblue": "#6a5acd", "slategray": "#708090", "snow": "#fffafa", "springgreen": "#00ff7f", "steelblue": "#4682b4", "tan": "#d2b48c", "teal": "#008080", "thistle": "#d8bfd8", "tomato": "#ff6347", "turquoise": "#40e0d0", "violet": "#ee82ee", "wheat": "#f5deb3", "white": "#ffffff", "whitesmoke": "#f5f5f5", "yellow": "#ffff00", "yellowgreen": "#9acd32" }, logLevel : -1, logCaption:null, setLogConfig:function(level, logCaption){ if (level=='error'){ this.logLevel=0; }else if (level=='info'){ this.logLevel=2; }else if (level=='debug'){ this.logLevel=5; }else if (level=='trace'){ this.logLevel=10; } this.logCaption = logCaption; }, getDayOfYear:function(date){ var start = new Date(date.getFullYear(), 0, 0); var diff = date - start; var oneDay = 1000 * 60 * 60 * 24; var day = Math.floor(diff / oneDay); return day; }, getMinuteOfDay:function(date){ var start = new Date(date); start.setHours(0,0,0,0); var diff = date - start; var oneDay = 1000 * 60; var day = Math.floor(diff / oneDay); return day; }, getHourOfDay:function(date){ var start = new Date(date); start.setHours(0,0,0,0); var diff = date - start; var oneDay = 1000 * 60 * 60; var day = Math.floor(diff / oneDay); return day; }, getSuitableOpositeColor:function(color){ var hex = this.colors[color]; if (!hex){ hex = color; } var rgb = this.hexToRgb(hex); var minMax = this.getMinMax(rgb); if (minMax.max<128){ return 'white'; }else{ return 'black' } }, colorNameToHex:function(name){ return this.colors[name]; }, normalizeHexColor:function(color){ var colorHex = this.colors[color]; if (colorHex){ return colorHex; } if (color[0] !== '#') color = "#"+color; if (color.length==4){ return "#"+color[1]+color[1]+color[2]+color[2]+color[3]+color[3]; } return color; }, hexToRgb : function(hex){ if (hex[0] === '#') hex = hex.substr(1); var r = parseInt(hex.slice(0,2), 16), g = parseInt(hex.slice(2,4), 16), b = parseInt(hex.slice(4,6), 16); return [r,g,b]; }, rgbToHex:function(r, g, b) { function getSafe(value){ if (value<0) value=0; if (value>255) value=255; return value; } //take hex value let hexValue = (( getSafe(r) << 16) | ( getSafe(g) << 8) | getSafe(b)).toString(16); //ensure that value has 6 letters size while(hexValue.length<6){ hexValue = '0'+hexValue; } return hexValue; }, minLength:function(array1,array2){ var len1 = array1.length; var len2 = array2.length; return len1minMax2.max?minMax1.max:minMax2.max; }else{ max = minMax1.max; } }else{ max = minMax2.max; } return {min:min, max:max}; }, getSizeFromFont:function(font){ var pxIndex = font.indexOf('px'); var sizePart = font.substr(0, pxIndex); return sizePart*1; }, getMinMax : function(data){ var min = null; var max = null; function evalMinMax(value){ if (min==null || min>value){ min = value; } if (max==null || max=level){ var caption = this.logCaption && this.logCaption!=null ? this.logCaption+': ' : ''; console.log(caption+message); } }, getNearestRound:function(number, mustBeInt){ var str = number+""; var length = str.length; var strResult = ""; var foundZero = false; var firstNonZero = 0; var previousDot = false; for(var i=0;inumber && this.isInteger(result10)){ return result10; } var result5 = result/5; if (result5>number && this.isInteger(result5)){ return result5; } var result4 = result/4; if (result4>number && this.isInteger(result4)){ return result4; } var halfResult = result/2; return halfResult>number && this.isInteger(halfResult)? halfResult : result; }, getElementPosition : function(element) { var top = 0, left = 0; do { top += element.offsetTop || 0; left += element.offsetLeft || 0; element = element.offsetParent; } while(element); return { top: top, left: left }; }, isInteger:function(n){ return n % 1 === 0; }, isNullOrUndefined:function(i){ return i==null || typeof (i)=='undefined'; }, isString:function(s){ return typeof s === 'string'; }, isObject:function(i){ return typeof i === 'object' }, isNumeric:function(n) { return !isNaN(parseFloat(n)) && isFinite(n); }, parseSize:function(val){ if (this.isNumeric(val)){ return {val:val, units:'px'}; } val = val.toLowerCase(); var pxIndex = val.indexOf('px'); if (pxIndex!=-1){ var numPart = val.substr(0,pxIndex); return {val:numPart*1, units:'px'}; } var pcIndex = val.indexOf('%'); if (pcIndex!=-1){ var numPart = val.substr(0,pcIndex); return {val:numPart*1, units:'%'}; } }, cleanDateAttributes:function(date, level){ switch(level){ case 'year': date.setMonth(0); date.setDate(1); date.setHours(0); date.setMinutes(0); date.setSeconds(0); date.setMilliseconds(0); break; case 'month': date.setDate(1); date.setHours(0); date.setMinutes(0); date.setSeconds(0); date.setMilliseconds(0); break; case 'day': date.setHours(0); date.setMinutes(0); date.setSeconds(0); date.setMilliseconds(0); break; case 'hour': date.setMinutes(0); date.setSeconds(0); date.setMilliseconds(0); break; case 'minute': date.setSeconds(0); date.setMilliseconds(0); break; case 'second': date.setMilliseconds(0); break; } }, getNearestDate:function(timestamp){ var date = new Date(timestamp); SQ4.Utils.cleanDateAttributes(date, 'day'); var dat1 = date.getTime(); date.setDate(date.getDate()+1); var dat2 = date.getTime(); var leftArea = timestamp-dat1; var rightArea = dat2 - timestamp; if (leftArea=from && index<=to){ result.push(value); } index++; }); return result; }, getArrayIndexes:function(xVals, minX, maxX){ var index1=null; var index2=null; var index = 0; xVals.forEach(function(x){ var xVal = new Date(x).getTime(); if (index1==null && xVal>=minX && xVal<=maxX){ index1 = index; } if (xVal<=maxX && index1!=null){ index2=index; } index++ }); return {index1:index1, index2:index2}; } }; SQ4.AxisRenderer = { NumberRenderer : function(mustBeInt){ var mustBeInt = mustBeInt; this.normalize = function(x){ return Math.round(x); } this.addSeparators = function(nStr){ nStr += ''; var x = nStr.split('.'); var x1 = x[0]; var x2 = x.length > 1 ? '.' + x[1] : ''; var rgx = /(\d+)(\d{3})/; while (rgx.test(x1)) { x1 = x1.replace(rgx, '$1' + ',' + '$2'); } return x1 + x2; } this.getCaption = function(value, shortValues, format){ if (mustBeInt){ value = Math.trunc(value); }else if (typeof format!=='undefined'){ return this.addSeparators(value.toFixed(format)); } if (shortValues){ var thousands = value/1000; if (Math.abs(thousands)>=1){ return thousands+"K"; } } return this.addSeparators(value)+""; } this.getNextValue = function(obj){ if (typeof(obj.current)=='undefined' || obj.current==null){ obj.current = obj.start; }else{ obj.current+=obj.step; } } this.getStartStep = function(size, minMax, minimalStepSize, precision){ var min = minMax.min; var max = minMax.max; var delta = max - min; if (delta===0){ return {start:minMax.min, step:1, dformat:SQ4.Utils.getDecimalCount(minMax.min)}; } var oneStepSize = size/minimalStepSize; var part = delta / oneStepSize; var step = SQ4.Utils.getNearestRound(part, mustBeInt); if (precision){ var minStep = 1/Math.pow(10, precision); if (step0){ result=result+"\n"; } try{ result=result+new Date(value).format(iFormat); }catch(e){ console.log("Invalid date: ", value," format: ",iFormat); result=result+"-"; } }); return result; } this.getNextValue = function(obj){ if (typeof(obj.current)=='undefined' || obj.current==null){ obj.current = obj.start; }else{ var date = new Date(obj.current); switch(obj.step){ case 'year': date.setFullYear(date.getFullYear()+1); break; case 'month': date.setMonth(date.getMonth()+1); break; case 'day': date.setDate(date.getDate()+1); break; case 'thirdDay': date.setHours(date.getHours()+8); break; case 'halfDay': date.setHours(date.getHours()+12); break; case 'quaterDay': date.setHours(date.getHours()+6); break; case 'hour': date.setHours(date.getHours()+1); break; case 'minute': date.setMinutes(date.getMinutes()+1); break; case 'second': date.setSeconds(date.getSeconds()+1); break; case 'milisec': date.setMilliseconds(date.getMilliseconds()+1); break; } SQ4.Utils.cleanDateAttributes(date, obj.step); obj.current=date.getTime(); } } this.getStartStep = function(size, minMax, minimalStepSize, timeHelpData){ var min = minMax.min; var max = minMax.max; var minMaxDelta = max - min; var oneStepCount = size/minimalStepSize; var date = new Date(minMax.min); var start = minMax.min; var step; var suggestFormat = null; var bestRecord = null; var bestCount = 0; timeHelpData.forEach(function(record){ var iCount = minMaxDelta/record.size; if (iCount<0 || iCount>oneStepCount){ return; } var delta = oneStepCount - iCount; if (bestRecord==null || delta0.05){ result.start = result.current; } result.current = result.start; return result; } } }; SQ4.CanvasHelper = function(canvas, borders){ var me = this; this.ctx = canvas.getContext("2d"); this.borders = borders; this.heights = []; this.ratio = window.devicePixelRatio || 1; this.setSmoothing = function(enabled){ this.ctx.webkitImageSmoothingEnabled = enabled; this.ctx.mozImageSmoothingEnabled = enabled; this.ctx.imageSmoothingEnabled = enabled; } this.clear = function(color){ SQ4.Utils.log('Clearing', SQ4.Consts.LOG_DEBUG); this.drawFilledRectangle(0, 0, canvas.width,canvas.height, color); }; this.drawFilledPolygon = function(points, strokeColor, fillcolor){ this.ctx.save(); this.ctx.fillStyle = fillcolor; this.ctx.strokeStyle = strokeColor; this.ctx.translate(0.5,0.5); this.ctx.beginPath(); var first = true; points.forEach(function(point){ if (first){ me.ctx.moveTo(Math.round(point.x), Math.round(point.y)); first = false; }else{ me.ctx.lineTo(Math.round(point.x), Math.round(point.y)); } }); this.ctx.closePath(); this.ctx.fill(); this.ctx.stroke(); this.ctx.restore(); } this.closePath = function(){ this.ctx.closePath(); } this.getWidth = function(){ return canvas.width; } this.getHeight = function(){ return canvas.height; } this.drawRoundedRectangle = function(x, y, width, height, options){ this.ctx.save(); var stroke, fill, fillColor, strokeColor, radius; stroke = options.stroke; fill = options.fill; fillColor = options.fillColor; strokeColor = options.strokeColor; radius = options.radius; if (fillColor && fill){ this.ctx.fillStyle = fillColor; } if (strokeColor && stroke){ this.ctx.strokeStyle = strokeColor; } if (typeof stroke == "undefined" ) { stroke = true; } if (typeof radius === "undefined") { radius = 5; } this.ctx.beginPath(); var antialias = options && options.antialias===true; if (!antialias){ this.ctx.translate(0.5,0.5); x = Math.round(x); y = Math.round(y); width = Math.round(width); height = Math.round(height); radius = Math.round(radius); } this.ctx.moveTo(x + radius, y); this.ctx.lineTo(x + width - radius, y); this.ctx.quadraticCurveTo(x + width, y, x + width, y + radius); this.ctx.lineTo(x + width, y + height - radius); this.ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); this.ctx.lineTo(x + radius, y + height); this.ctx.quadraticCurveTo(x, y + height, x, y + height - radius); this.ctx.lineTo(x, y + radius); this.ctx.quadraticCurveTo(x, y, x + radius, y); this.ctx.closePath(); if (stroke) { this.ctx.stroke(); } if (fill) { this.ctx.fill(); } this.ctx.restore(); } this.drawFilledRectangle = function(x1, y1, width, height, color, options){ SQ4.Utils.log('Drawing filled rectangle: '+x1+','+y1+' with color:'+color, SQ4.Consts.LOG_TRACE); this.ctx.save(); if (options && options.opacity){ this.ctx.globalAlpha = options.opacity; } var antialias = options && options.antialias===true; if (!antialias){ x1 = Math.round(x1); y1 = Math.round(y1); width = Math.round(width); height = Math.round(height); } this.ctx.fillStyle = color; this.ctx.fillRect(x1,y1,width,height); this.ctx.restore(); } this.drawRectangle = function(x1, y1, color, width, height, options){ SQ4.Utils.log('Drawing rectangle: '+x1+','+y1+' width:'+width+', height:'+height+' with color:'+color, SQ4.Consts.LOG_TRACE); this.ctx.save(); this.ctx.beginPath(); var antialias = options && options.antialias===true; if (!antialias){ var x2 = x1+width; var y2 = y1+height; x1 = Math.round(x1); y1 = Math.round(y1); width = Math.round(x2)-x1; height = Math.round(y2)-y1; } this.ctx.strokeStyle = color; this.ctx.rect(x1,y1,width,height); this.ctx.stroke(); this.ctx.restore(); } this.beginPath = function(x1, y1, options){ this.ctx.save(); if (options){ if (options.lineDash){ this.ctx.setLineDash(options.lineDash); } if (options.width){ this.ctx.lineWidth=options.width; } if (options.strokeColor){ this.ctx.strokeStyle=options.strokeColor; } if (options.fillColor){ this.ctx.fillStyle=options.fillColor; } } this.ctx.beginPath(); this.ctx.moveTo(x1,y1); } this.setLineWidth = function(width){ this.ctx.lineWidth = width; } this.lineTo = function(x2, y2){ this.ctx.lineTo(x2,y2); } this.stroke = function(noRestore){ this.ctx.stroke(); if (noRestore!==false){ this.ctx.restore(); } } this.fill = function(noRestore){ this.ctx.fill(); if (noRestore!==false){ this.ctx.restore(); } } this.drawLine = function(x1, y1, x2, y2, color, options){ SQ4.Utils.log('Drawing line: '+x1+','+y1+' - '+x2+','+y2+' with color:'+color, SQ4.Consts.LOG_TRACE); this.ctx.save(); this.ctx.beginPath(); var antialias = options && options.antialias===true; if (options){ if (options.lineDash){ this.ctx.setLineDash(options.lineDash); } if (options.width){ this.ctx.lineWidth=options.width; } } if (!antialias){ this.ctx.translate(0.5,0.5); x1 = Math.round(x1); x2 = Math.round(x2); y1 = Math.round(y1); y2 = Math.round(y2); } this.ctx.moveTo(x1,y1); this.ctx.lineTo(x2,y2); this.ctx.strokeStyle=color; this.ctx.stroke(); this.ctx.restore(); }; this.moveTo = function(x,y){ this.ctx.moveTo(x,y); } this.drawFilledCircle = function(x, y, color, radius){ this.ctx.save(); this.ctx.beginPath(); this.ctx.arc(x, y, radius, 0, 2 * Math.PI, false); this.ctx.fillStyle = color; this.ctx.fill(); this.ctx.lineWidth = 1; this.ctx.strokeStyle = color; this.ctx.stroke(); this.ctx.restore(); }; this.getTextWidth = function(caption, font){ this.ctx.save(); this.ctx.font = font; var lines = caption.split("\n"); var width = 0; lines.forEach(function(line){ var textSize = me.ctx.measureText(line); if (textSize.width>width){ width = textSize.width; } }); this.ctx.restore(); return width; } this.drawTextRotated = function(caption, color, font, x, y){ this.drawText(caption, color, font, x, y, {rotation:-90*Math.PI/180}); }; this.getTextHeightOld = function(font){ var fontSize = SQ4.Utils.getSizeFromFont(font); var textHeight = fontSize?1.5*fontSize:1; return textHeight; } this.getTextHeight = function(font){ return this.getTextHeightOld(font); } this.getTextHeightNew = function(fontStyle){ var result = this.heights[fontStyle]; if (!result) { var body = document.getElementsByTagName('body')[0]; var dummy = document.createElement('div'); var dummyText = document.createTextNode('M'); dummy.appendChild(dummyText); dummy.setAttribute('style', fontStyle + ';position:absolute;top:0;left:-500px'); body.appendChild(dummy); result = dummy.offsetHeight; this.heights[fontStyle] = result; body.removeChild(dummy); } return result; } this.centerText = function(caption, color, font, borders, options){ var textWidth = this.getTextWidth(caption, font); if (textWidth>borders.width && (!options || !options.force)){ return false; } var x = borders.x+borders.width/2-textWidth/2; var y = borders.y+borders.height/2; if (options && typeof(options.minX)!='undefined' && options.minX>x){ x = options.minX; } this.drawText(caption, color, font, x, y); return true; }; this.drawText = function(caption, color, font, x, y, options){ this.ctx.save(); this.ctx.font = font; this.ctx.fillStyle = color; SQ4.Utils.log('Drawing text to :'+x+', '+y+' with color:'+color+' and font:'+font, SQ4.Consts.LOG_DEBUG); if (options && options.rotation){ this.ctx.translate(x, y ); this.ctx.rotate(options.rotation); x = 0; y = 0; } this.ctx.textAlign="left"; this.ctx.fillText(caption, x, y); this.ctx.restore(); }; this.getImageData = function(x,y,width,height){ return this.ctx.getImageData(x,y,width,height); } this.putImageData = function(data, x, y, dirtyX, dirtyY, dirtyWidth, dirtyHeight){ if (typeof dirtyX=='undefined'){ dirtyX = 0; } if (typeof dirtyY=='undefined'){ dirtyY = 0; } if (typeof dirtyWidth=='undefined'){ dirtyWidth = data.width; } if (typeof dirtyHeight=='undefined'){ dirtyHeight = data.height; } this.ctx.putImageData(data,x,y, dirtyX, dirtyY, dirtyWidth, dirtyHeight); } this.updateCanvasSize = function(canvas, canvasWrapper, widthInfo, heightInfo){ function setCanvasSize(attr, info){ if (!info){ return; } var success = true; var valueForSet; if (info.units=='px'){ valueForSet=info.val; }else if (info.units=='%'){ var offsetAttr = 'offset'+SQ4.Utils.capitalizeFirstLetter(attr); var wraperParent = canvasWrapper.parentElement; var valueFromParent = wraperParent[offsetAttr]; valueForSet = valueFromParent*(info.val/100); if (valueFromParent==0){ success = false; } } valueForSet = Math.trunc(valueForSet); canvas[attr] = valueForSet*me.ratio; canvas.style[attr] = valueForSet+'px'; return success; } setCanvasSize('width', widthInfo); var result = setCanvasSize('height', heightInfo); canvasWrapper.style.height=canvas.style.height; canvasWrapper.style.width=canvas.style.width; return result; } };