3 Commits
Author SHA1 Message Date
alazhar 8d65b877dd rev1.3 2026-04-27 21:34:30 +07:00
alazhar 8a34443b77 rev1.2 2026-04-27 21:31:53 +07:00
alazhar 7c662f67e9 rev1.1 2026-04-27 21:30:17 +07:00
3 changed files with 115 additions and 98 deletions

No files matched your search

+115 -84
View File
@@ -4,15 +4,12 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Log Viewer Pro // Zoom Edition</title>
<title>Log Viewer Pro // Timeline Brush</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/dataTables.bootstrap5.min.css" rel="stylesheet">
<script src="js/lucide.min.js"></script>
<script src="js/chart.js"></script>
<script src="js/hammer.min.js"></script>
<script src="js/chartjs-plugin-zoom.min.js"></script>
<style>
:root {
@@ -21,6 +18,8 @@
--bg-dark: #0f172a;
--card-dark: #1e293b;
--border-color: #334155;
--selection-bg: rgba(74, 222, 128, 0.2);
--selection-border: rgba(74, 222, 128, 0.5);
}
body {
@@ -92,14 +91,34 @@
align-items: center;
}
/* Chart Area with Selection Overlay */
.chart-container {
height: 160px;
background: #0b0e14;
padding: 10px 20px;
border-bottom: 1px solid var(--border-color);
position: relative;
user-select: none;
}
#selection-overlay {
position: absolute;
top: 10px;
left: 20px;
right: 20px;
bottom: 10px;
pointer-events: none;
z-index: 10;
}
.selection-rect {
fill: var(--selection-bg);
stroke: var(--selection-border);
stroke-width: 1;
display: none;
}
/* Toggles & Controls */
.level-toggles .btn {
border: none;
font-size: 0.7rem;
@@ -133,7 +152,6 @@
color: #fff;
}
/* Search Input Styling */
.search-container {
position: relative;
width: 280px;
@@ -168,10 +186,6 @@
display: none;
}
.clear-btn:hover {
color: #fff;
}
.content-area {
flex-grow: 1;
padding: 1rem;
@@ -216,10 +230,10 @@
<aside>
<div class="sidebar-header">
<h6 class="mb-3 d-flex align-items-center gap-2">
<i data-lucide="shield-check" class="text-success"></i> LogViewer Pro
<i data-lucide="activity" class="text-success"></i> LogAnalytics
</h6>
<button class="btn btn-sm btn-outline-secondary w-100" onclick="$('#dir-input').click()">
<i data-lucide="folder" size="14"></i> Open Directory
<i data-lucide="folder" size="14"></i> Directory
</button>
<input type="file" id="dir-input" webkitdirectory hidden>
</div>
@@ -240,9 +254,9 @@
</div>
<div class="d-flex align-items-center gap-2">
<button class="btn btn-sm btn-outline-secondary" id="reset-chart-btn" title="Reset Chart Zoom">
<i data-lucide="maximize" size="14"></i> Reset Chart
</button>
<div id="filter-info" class="small text-muted me-2" style="display:none">
<span class="badge bg-secondary">Time Filtered</span>
</div>
<div class="search-container">
<i data-lucide="search" size="14" class="search-icon"></i>
<input type="text" id="global-search" placeholder="Search... (RegEx enabled)">
@@ -251,8 +265,11 @@
</div>
</div>
<div class="chart-container" id="chart-parent" title="Drag to Zoom | Right Click to Zoom Out">
<div class="chart-container" id="chart-parent">
<canvas id="intensityChart"></canvas>
<svg id="selection-overlay" width="100%" height="100%">
<rect class="selection-rect" x="0" y="0" width="0" height="100%"></rect>
</svg>
</div>
<div class="content-area">
@@ -276,10 +293,6 @@
<div class="modal fade" id="logModal" tabindex="-1">
<div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-content bg-dark border-secondary">
<div class="modal-header py-2 border-secondary">
<h6 class="modal-title small">Log Context / Exception</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-0">
<pre id="modal-content" class="m-0 p-4 text-success-emphasis"
style="font-size: 0.75rem; background: #000; overflow-x: auto; font-family: 'Fira Code', monospace;"></pre>
@@ -296,8 +309,7 @@
<script>
lucide.createIcons();
let chart, table;
let rawLogs = [];
let visibleTimeRange = { min: null, max: null };
let timeRange = { start: null, end: null };
$(document).ready(function () {
table = $('#log-table').DataTable({
@@ -314,35 +326,30 @@
drawCallback: () => lucide.createIcons()
});
// Search Controls
// Global Search
$('#global-search').on('keyup', function () {
table.search(this.value, true, false).draw();
$('#clear-search').toggle(this.value.length > 0);
});
$('#clear-search').on('click', function () {
$('#global-search').val('').trigger('keyup');
chart.resetZoom();
});
$('#clear-search').on('click', resetFilters);
// Initialize Chart with Zoom Plugin
function resetFilters() {
$('#global-search').val('').trigger('keyup');
timeRange = { start: null, end: null };
table.draw();
$('#filter-info').hide();
$('.selection-rect').hide();
}
// Intensity Chart
const ctx = document.getElementById('intensityChart').getContext('2d');
chart = new Chart(ctx, {
type: 'bar',
data: { labels: [], datasets: [{ label: 'Logs', data: [], backgroundColor: '#4ade80', barPercentage: 0.9, categoryPercentage: 0.9 }] },
options: {
responsive: true, maintainAspectRatio: false,
plugins: {
legend: { display: false },
zoom: {
zoom: {
drag: { enabled: true, backgroundColor: 'rgba(74, 222, 128, 0.1)', borderColor: 'rgba(74, 222, 128, 0.4)', borderWidth: 1 },
mode: 'x',
onZoomComplete: ({ chart }) => updateFiltersFromZoom(chart)
},
pan: { enabled: true, mode: 'x', onPanComplete: ({ chart }) => updateFiltersFromZoom(chart) }
}
},
plugins: { legend: { display: false }, tooltip: { enabled: true } },
scales: {
x: { ticks: { color: '#64748b', font: { size: 10 } }, grid: { display: false } },
y: { beginAtZero: true, grid: { color: '#1e293b' }, ticks: { color: '#64748b', font: { size: 10 } } }
@@ -350,51 +357,78 @@
}
});
// Manual Zoom Controls
$('#reset-chart-btn').on('click', () => chart.resetZoom());
// --- DRAG TO SELECT LOGIC ---
let isDragging = false;
let startX = 0;
const $overlay = $('#selection-overlay');
const $rect = $('.selection-rect');
// Right Click on Canvas to Zoom Out
document.getElementById('intensityChart').addEventListener('contextmenu', (e) => {
e.preventDefault();
chart.resetZoom();
$('#chart-parent').on('mousedown', function (e) {
isDragging = true;
startX = e.pageX - $overlay.offset().left;
$rect.attr({ 'x': startX, 'width': 0 }).show();
});
function updateFiltersFromZoom(chartInstance) {
const minIndex = Math.floor(chartInstance.scales.x.min);
const maxIndex = Math.ceil(chartInstance.scales.x.max);
const labels = chartInstance.data.labels;
visibleTimeRange = {
min: labels[Math.max(0, minIndex)],
max: labels[Math.min(labels.length - 1, maxIndex)]
};
// Update main level counters based on zoomed logs
const filteredLogs = rawLogs.filter(l => {
const time = l.time.substring(0, 5);
return time >= visibleTimeRange.min && time <= visibleTimeRange.max;
$(window).on('mousemove', function (e) {
if (!isDragging) return;
let currentX = e.pageX - $overlay.offset().left;
let width = currentX - startX;
if (width < 0) {
$rect.attr('x', currentX).attr('width', Math.abs(width));
} else {
$rect.attr('width', width);
}
});
updateLevelCounts(filteredLogs);
table.draw(); // Refresh table view based on global search + new time range
$(window).on('mouseup', function (e) {
if (!isDragging) return;
isDragging = false;
const finalX = parseInt($rect.attr('x'));
const finalWidth = parseInt($rect.attr('width'));
if (finalWidth < 5) { // If just a click
resetFilters();
return;
}
// Combined Filter (DataTable search + Level toggles + Zoom range)
// Map pixels to Chart labels
const labels = chart.data.labels;
const chartArea = chart.chartArea;
const scale = chart.scales.x;
const getValAtPixel = (px) => {
const decimal = scale.getValueForPixel(px);
const index = Math.round(decimal);
return labels[Math.max(0, Math.min(labels.length - 1, index))];
};
timeRange.start = getValAtPixel(finalX);
timeRange.end = getValAtPixel(finalX + finalWidth);
$('#filter-info').show();
table.draw();
});
// Right-click reset
$('#chart-parent').on('contextmenu', e => { e.preventDefault(); resetFilters(); });
// Custom Table Filter (Time + Level)
$.fn.dataTable.ext.search.push((settings, data, dataIndex) => {
const lvl = data[1];
const checked = $('.btn-check:checked').map((i, el) => $(el).val()).get();
if (!checked.includes(lvl)) return false;
if (visibleTimeRange.min && visibleTimeRange.max) {
const logTime = data[2].substring(0, 5);
return logTime >= visibleTimeRange.min && logTime <= visibleTimeRange.max;
if (timeRange.start && timeRange.end) {
const logTime = data[2].substring(0, 5); // HH:mm
return logTime >= timeRange.start && logTime <= timeRange.end;
}
return true;
});
$('.btn-check').on('change', () => table.draw());
// File/Directory logic
// File loading
$('#dir-input').on('change', function (e) {
const files = Array.from(e.target.files).filter(f => f.name.endsWith('.log'));
$('#file-list').empty().append(files.map((f, i) => `<div class="file-item" onclick="loadLog(${i})"><span>${f.name}</span></div>`));
@@ -405,28 +439,17 @@
$('.file-item').removeClass('active').eq(idx).addClass('active');
const reader = new FileReader();
reader.onload = e => {
rawLogs = parseLogs(e.target.result);
table.clear().rows.add(rawLogs).draw();
// Set initial chart data
const bins = {};
rawLogs.forEach(l => {
const min = l.time.substring(0, 5);
bins[min] = (bins[min] || 0) + 1;
});
const sortedLabels = Object.keys(bins).sort();
chart.data.labels = sortedLabels;
chart.data.datasets[0].data = sortedLabels.map(l => bins[l]);
chart.resetZoom();
updateLevelCounts(rawLogs);
const logs = parseLogs(e.target.result);
table.clear().rows.add(logs).draw();
updateAnalytics(logs);
resetFilters();
};
reader.readAsText(window.loadedFiles[idx]);
};
function parseLogs(text) {
const logs = [];
const regex = /^(\d{2}:\d{2}:\d{2}\.\d{3})\s\[(INF|WRN|ERR|CRT|DBG|TRC)\]\s(.*)$/;
const regex = /^(\d{2}:\d{2}:\d{2}\.\d{3})\s\[(TRC|DBG|INF|WRN|ERR|CRT)\]\s(.*)$/;
text.split(/\r?\n/).forEach(line => {
const match = line.match(regex);
if (match) logs.push({ time: match[1], level: match[2], message: match[3], exception: "" });
@@ -435,10 +458,18 @@
return logs;
}
function updateLevelCounts(logs) {
const counts = { INF: 0, WRN: 0, ERR: 0, CRT: 0 };
logs.forEach(l => { if (counts[l.level] !== undefined) counts[l.level]++; });
function updateAnalytics(logs) {
const counts = { INF: 0, WRN: 0, ERR: 0, CRT: 0 }, bins = {};
logs.forEach(l => {
if (counts[l.level] !== undefined) counts[l.level]++;
const min = l.time.substring(0, 5);
bins[min] = (bins[min] || 0) + 1;
});
Object.keys(counts).forEach(k => $(`#c-${k}`).text(counts[k].toLocaleString()));
const sortedLabels = Object.keys(bins).sort();
chart.data.labels = sortedLabels;
chart.data.datasets[0].data = sortedLabels.map(l => bins[l]);
chart.update();
}
$('#log-table tbody').on('click', 'tr', function () {
-7
View File
@@ -1,7 +0,0 @@
/*!
* chartjs-plugin-zoom v2.0.1
* undefined
* (c) 2016-2023 chartjs-plugin-zoom Contributors
* Released under the MIT License
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("chart.js"),require("hammerjs"),require("chart.js/helpers")):"function"==typeof define&&define.amd?define(["chart.js","hammerjs","chart.js/helpers"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).ChartZoom=t(e.Chart,e.Hammer,e.Chart.helpers)}(this,(function(e,t,n){"use strict";function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var a=o(t);const i=e=>e&&e.enabled&&e.modifierKey,c=(e,t)=>e&&t[e+"Key"],r=(e,t)=>e&&!t[e+"Key"];function s(e,t,n){return void 0===e||("string"==typeof e?-1!==e.indexOf(t):"function"==typeof e&&-1!==e({chart:n}).indexOf(t))}function l(e,t){return"function"==typeof e&&(e=e({chart:t})),"string"==typeof e?{x:-1!==e.indexOf("x"),y:-1!==e.indexOf("y")}:{x:!1,y:!1}}function u(e,t,o){const{mode:a="xy",scaleMode:i,overScaleMode:c}=e||{},r=function({x:e,y:t},n){const o=n.scales,a=Object.keys(o);for(let n=0;n<a.length;n++){const i=o[a[n]];if(t>=i.top&&t<=i.bottom&&e>=i.left&&e<=i.right)return i}return null}(t,o),s=l(a,o),u=l(i,o);if(c){const e=l(c,o);for(const t of["x","y"])e[t]&&(u[t]=s[t],s[t]=!1)}if(r&&u[r.axis])return[r];const m=[];return n.each(o.scales,(function(e){s[e.axis]&&m.push(e)})),m}const m=new WeakMap;function d(e){let t=m.get(e);return t||(t={originalScaleLimits:{},updatedScaleLimits:{},handlers:{},panDelta:{}},m.set(e,t)),t}function f(e,t,n){const o=e.max-e.min,a=o*(t-1),i=e.isHorizontal()?n.x:n.y,c=Math.max(0,Math.min(1,(e.getValueForPixel(i)-e.min)/o||0));return{min:a*c,max:a*(1-c)}}function p(e,t,o,a,i){let c=o[a];if("original"===c){const o=e.originalScaleLimits[t.id][a];c=n.valueOrDefault(o.options,o.scale)}return n.valueOrDefault(c,i)}function h(e,{min:t,max:n},o,a=!1){const i=d(e.chart),{id:c,axis:r,options:s}=e,l=o&&(o[c]||o[r])||{},{minRange:u=0}=l,m=p(i,e,l,"min",-1/0),f=p(i,e,l,"max",1/0),h=a?Math.max(n-t,u):e.max-e.min,x=(h-n+t)/2;return n+=x,(t-=x)<m?(t=m,n=Math.min(m+h,f)):n>f&&(n=f,t=Math.max(f-h,m)),s.min=t,s.max=n,i.updatedScaleLimits[e.id]={min:t,max:n},e.parse(t)!==e.min||e.parse(n)!==e.max}const x=e=>0===e||isNaN(e)?0:e<0?Math.min(Math.round(e),-1):Math.max(Math.round(e),1);const g={second:500,minute:3e4,hour:18e5,day:432e5,week:3024e5,month:1296e6,quarter:5184e6,year:157248e5};function y(e,t,n,o=!1){const{min:a,max:i,options:c}=e,r=c.time&&c.time.round,s=g[r]||0,l=e.getValueForPixel(e.getPixelForValue(a+s)-t),u=e.getValueForPixel(e.getPixelForValue(i+s)-t),{min:m=-1/0,max:d=1/0}=o&&n&&n[e.axis]||{};return!!(isNaN(l)||isNaN(u)||l<m||u>d)||h(e,{min:l,max:u},n,o)}function b(e,t,n){return y(e,t,n,!0)}const v={category:function(e,t,n,o){const a=f(e,t,n);return e.min===e.max&&t<1&&function(e){const t=e.getLabels().length-1;e.min>0&&(e.min-=1),e.max<t&&(e.max+=1)}(e),h(e,{min:e.min+x(a.min),max:e.max-x(a.max)},o,!0)},default:function(e,t,n,o){const a=f(e,t,n);return h(e,{min:e.min+a.min,max:e.max-a.max},o,!0)}},w={default:function(e,t,n,o){h(e,function(e,t,n){const o=e.getValueForPixel(t),a=e.getValueForPixel(n);return{min:Math.min(o,a),max:Math.max(o,a)}}(e,t,n),o,!0)}},z={category:function(e,t,n){const o=e.getLabels().length-1;let{min:a,max:i}=e;const c=Math.max(i-a,1),r=Math.round(function(e){return e.isHorizontal()?e.width:e.height}(e)/Math.max(c,10)),s=Math.round(Math.abs(t/r));let l;return t<-r?(i=Math.min(i+s,o),a=1===c?i:i-c,l=i===o):t>r&&(a=Math.max(0,a-s),i=1===c?a:a+c,l=0===a),h(e,{min:a,max:i},n)||l},default:y,logarithmic:b,timeseries:b};function M(e,t){n.each(e,((n,o)=>{t[o]||delete e[o]}))}function k(e,t){const{scales:o}=e,{originalScaleLimits:a,updatedScaleLimits:i}=t;return n.each(o,(function(e){(function(e,t,n){const{id:o,options:{min:a,max:i}}=e;if(!t[o]||!n[o])return!0;const c=n[o];return c.min!==a||c.max!==i})(e,a,i)&&(a[e.id]={min:{scale:e.min,options:e.options.min},max:{scale:e.max,options:e.options.max}})})),M(a,o),M(i,o),a}function S(e,t,o,a){const i=v[e.type]||v.default;n.callback(i,[e,t,o,a])}function P(e,t,o,a,i){const c=w[e.type]||w.default;n.callback(c,[e,t,o,a,i])}function D(e){const t=e.chartArea;return{x:(t.left+t.right)/2,y:(t.top+t.bottom)/2}}function j(e,t,o="none"){const{x:a=1,y:i=1,focalPoint:c=D(e)}="number"==typeof t?{x:t,y:t}:t,r=d(e),{options:{limits:s,zoom:l}}=r;k(e,r);const m=1!==a,f=1!==i,p=u(l,c,e);n.each(p||e.scales,(function(e){e.isHorizontal()&&m?S(e,a,c,s):!e.isHorizontal()&&f&&S(e,i,c,s)})),e.update(o),n.callback(l.onZoom,[{chart:e}])}function O(e,t,o,a="none"){const i=d(e),{options:{limits:c,zoom:r}}=i,{mode:l="xy"}=r;k(e,i);const u=s(l,"x",e),m=s(l,"y",e);n.each(e.scales,(function(e){e.isHorizontal()&&u?P(e,t.x,o.x,c):!e.isHorizontal()&&m&&P(e,t.y,o.y,c)})),e.update(a),n.callback(r.onZoom,[{chart:e}])}function C(e){const t=d(e);let o=1,a=1;return n.each(e.scales,(function(e){const i=function(e,t){const o=e.originalScaleLimits[t];if(!o)return;const{min:a,max:i}=o;return n.valueOrDefault(i.options,i.scale)-n.valueOrDefault(a.options,a.scale)}(t,e.id);if(i){const t=Math.round(i/(e.max-e.min)*10Line truncated
-7
View File
@@ -1,7 +0,0 @@
/*! Hammer.JS - v2.0.7 - 2016-04-22
* http://hammerjs.github.io/
*
* Copyright (c) 2016 Jorik Tangelder;
* Licensed under the MIT license */
!function(a,b,c,d){"use strict";function e(a,b,c){return setTimeout(j(a,c),b)}function f(a,b,c){return Array.isArray(a)?(g(a,c[b],c),!0):!1}function g(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e<a.length;)b.call(c,a[e],e,a),e++;else for(e in a)a.hasOwnProperty(e)&&b.call(c,a[e],e,a)}function h(b,c,d){var e="DEPRECATED METHOD: "+c+"\n"+d+" AT \n";return function(){var c=new Error("get-stack-trace"),d=c&&c.stack?c.stack.replace(/^[^\(]+?[\n$]/gm,"").replace(/^\s+at\s+/gm,"").replace(/^Object.<anonymous>\s*\(/gm,"{anonymous}()@"):"Unknown Stack Trace",f=a.console&&(a.console.warn||a.console.log);return f&&f.call(a.console,e,d),b.apply(this,arguments)}}function i(a,b,c){var d,e=b.prototype;d=a.prototype=Object.create(e),d.constructor=a,d._super=e,c&&la(d,c)}function j(a,b){return function(){return a.apply(b,arguments)}}function k(a,b){return typeof a==oa?a.apply(b?b[0]||d:d,b):a}function l(a,b){return a===d?b:a}function m(a,b,c){g(q(b),function(b){a.addEventListener(b,c,!1)})}function n(a,b,c){g(q(b),function(b){a.removeEventListener(b,c,!1)})}function o(a,b){for(;a;){if(a==b)return!0;a=a.parentNode}return!1}function p(a,b){return a.indexOf(b)>-1}function q(a){return a.trim().split(/\s+/g)}function r(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;d<a.length;){if(c&&a[d][c]==b||!c&&a[d]===b)return d;d++}return-1}function s(a){return Array.prototype.slice.call(a,0)}function t(a,b,c){for(var d=[],e=[],f=0;f<a.length;){var g=b?a[f][b]:a[f];r(e,g)<0&&d.push(a[f]),e[f]=g,f++}return c&&(d=b?d.sort(function(a,c){return a[b]>c[b]}):d.sort()),d}function u(a,b){for(var c,e,f=b[0].toUpperCase()+b.slice(1),g=0;g<ma.length;){if(c=ma[g],e=c?c+f:b,e in a)return e;g++}return d}function v(){return ua++}function w(b){var c=b.ownerDocument||b;return c.defaultView||c.parentWindow||a}function x(a,b){var c=this;this.manager=a,this.callback=b,this.element=a.element,this.target=a.options.inputTarget,this.domHandler=function(b){k(a.options.enable,[a])&&c.handler(b)},this.init()}function y(a){var b,c=a.options.inputClass;return new(b=c?c:xa?M:ya?P:wa?R:L)(a,z)}function z(a,b,c){var d=c.pointers.length,e=c.changedPointers.length,f=b&Ea&&d-e===0,g=b&(Ga|Ha)&&d-e===0;c.isFirst=!!f,c.isFinal=!!g,f&&(a.session={}),c.eventType=b,A(a,c),a.emit("hammer.input",c),a.recognize(c),a.session.prevInput=c}function A(a,b){var c=a.session,d=b.pointers,e=d.length;c.firstInput||(c.firstInput=D(b)),e>1&&!c.firstMultiple?c.firstMultiple=D(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=E(d);b.timeStamp=ra(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=I(h,i),b.distance=H(h,i),B(c,b),b.offsetDirection=G(b.deltaX,b.deltaY);var j=F(b.deltaTime,b.deltaX,b.deltaY);b.overallVelocityX=j.x,b.overallVelocityY=j.y,b.overallVelocity=qa(j.x)>qa(j.y)?j.x:j.y,b.scale=g?K(g.pointers,d):1,b.rotation=g?J(g.pointers,d):0,b.maxPointers=c.prevInput?b.pointers.length>c.prevInput.maxPointers?b.pointers.length:c.prevInput.maxPointers:b.pointers.length,C(c,b);var k=a.element;o(b.srcEvent.target,k)&&(k=b.srcEvent.target),b.target=k}function B(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};b.eventType!==Ea&&f.eventType!==Ga||(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function C(a,b){var c,e,f,g,h=a.lastInterval||b,i=b.timeStamp-h.timeStamp;if(b.eventType!=Ha&&(i>Da||h.velocity===d)){var j=b.deltaX-h.deltaX,k=b.deltaY-h.deltaY,l=F(i,j,k);e=l.x,f=l.y,c=qa(l.x)>qa(l.y)?l.x:l.y,g=G(j,k),a.lastInterval=b}else c=h.velocity,e=h.velocityX,f=h.velocityY,g=h.direction;b.velocity=c,b.velocityX=e,b.velocityY=f,b.direction=g}function D(a){for(var b=[],c=0;c<a.pointers.length;)b[c]={clientX:pa(a.pointers[c].clientX),clientY:pa(a.pointers[c].clientY)},c++;return{timeStamp:ra(),pointers:b,center:E(b),deltaX:a.deltaX,deltaY:a.deltaY}}function E(a){var b=a.length;if(1===b)return{x:pa(a[0].clientX),y:pa(a[0].clientY)};for(var c=0,d=0,e=0;b>e;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:pa(c/b),y:pa(d/b)}}function F(a,b,c){return{x:b/a||0,y:c/a||0}}function G(a,b){return a===b?Ia:qa(a)>=qa(b)?0>a?Ja:Ka:0>b?La:Ma}function H(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function I(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function J(a,b){return I(b[1],b[0],Ra)+I(a[1],a[0],Ra)}function K(a,b){return H(b[0],b[1],Ra)/H(a[0],a[1],Ra)}function L(){this.evEl=Ta,this.evWin=Ua,this.pressed=!1,x.apply(this,arguments)}function M(){this.evEl=Xa,this.evWin=Ya,x.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function N(){this.evTarget=$a,this.evWin=_a,this.started=!1,x.apply(this,arguments)}function O(a,b){var c=s(a.touches),d=s(a.changedTouches);return b&(Ga|Ha)&&(c=t(c.concat(d),"identifier",!0)),[c,d]}function P(){this.evTarget=bb,this.targetIds={},x.apply(this,arguments)}function Q(a,b){var c=s(a.touches)Line truncated
//# sourceMappingURL=hammer.min.js.map