Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d65b877dd
|
||
|
|
8a34443b77
|
||
|
|
7c662f67e9
|
No files matched your search
+114
-83
@@ -4,15 +4,12 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<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/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="css/dataTables.bootstrap5.min.css" rel="stylesheet">
|
<link href="css/dataTables.bootstrap5.min.css" rel="stylesheet">
|
||||||
<script src="js/lucide.min.js"></script>
|
<script src="js/lucide.min.js"></script>
|
||||||
|
|
||||||
<script src="js/chart.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>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
@@ -21,6 +18,8 @@
|
|||||||
--bg-dark: #0f172a;
|
--bg-dark: #0f172a;
|
||||||
--card-dark: #1e293b;
|
--card-dark: #1e293b;
|
||||||
--border-color: #334155;
|
--border-color: #334155;
|
||||||
|
--selection-bg: rgba(74, 222, 128, 0.2);
|
||||||
|
--selection-border: rgba(74, 222, 128, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -92,14 +91,34 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Chart Area with Selection Overlay */
|
||||||
.chart-container {
|
.chart-container {
|
||||||
height: 160px;
|
height: 160px;
|
||||||
background: #0b0e14;
|
background: #0b0e14;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
position: relative;
|
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 {
|
.level-toggles .btn {
|
||||||
border: none;
|
border: none;
|
||||||
font-size: 0.7rem;
|
font-size: 0.7rem;
|
||||||
@@ -133,7 +152,6 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search Input Styling */
|
|
||||||
.search-container {
|
.search-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 280px;
|
width: 280px;
|
||||||
@@ -168,10 +186,6 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.clear-btn:hover {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-area {
|
.content-area {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
@@ -216,10 +230,10 @@
|
|||||||
<aside>
|
<aside>
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<h6 class="mb-3 d-flex align-items-center gap-2">
|
<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>
|
</h6>
|
||||||
<button class="btn btn-sm btn-outline-secondary w-100" onclick="$('#dir-input').click()">
|
<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>
|
</button>
|
||||||
<input type="file" id="dir-input" webkitdirectory hidden>
|
<input type="file" id="dir-input" webkitdirectory hidden>
|
||||||
</div>
|
</div>
|
||||||
@@ -240,9 +254,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-flex align-items-center gap-2">
|
<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">
|
<div id="filter-info" class="small text-muted me-2" style="display:none">
|
||||||
<i data-lucide="maximize" size="14"></i> Reset Chart
|
<span class="badge bg-secondary">Time Filtered</span>
|
||||||
</button>
|
</div>
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
<i data-lucide="search" size="14" class="search-icon"></i>
|
<i data-lucide="search" size="14" class="search-icon"></i>
|
||||||
<input type="text" id="global-search" placeholder="Search... (RegEx enabled)">
|
<input type="text" id="global-search" placeholder="Search... (RegEx enabled)">
|
||||||
@@ -251,8 +265,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</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>
|
<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>
|
||||||
|
|
||||||
<div class="content-area">
|
<div class="content-area">
|
||||||
@@ -276,10 +293,6 @@
|
|||||||
<div class="modal fade" id="logModal" tabindex="-1">
|
<div class="modal fade" id="logModal" tabindex="-1">
|
||||||
<div class="modal-dialog modal-xl modal-dialog-centered">
|
<div class="modal-dialog modal-xl modal-dialog-centered">
|
||||||
<div class="modal-content bg-dark border-secondary">
|
<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">
|
<div class="modal-body p-0">
|
||||||
<pre id="modal-content" class="m-0 p-4 text-success-emphasis"
|
<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>
|
style="font-size: 0.75rem; background: #000; overflow-x: auto; font-family: 'Fira Code', monospace;"></pre>
|
||||||
@@ -296,8 +309,7 @@
|
|||||||
<script>
|
<script>
|
||||||
lucide.createIcons();
|
lucide.createIcons();
|
||||||
let chart, table;
|
let chart, table;
|
||||||
let rawLogs = [];
|
let timeRange = { start: null, end: null };
|
||||||
let visibleTimeRange = { min: null, max: null };
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
table = $('#log-table').DataTable({
|
table = $('#log-table').DataTable({
|
||||||
@@ -314,35 +326,30 @@
|
|||||||
drawCallback: () => lucide.createIcons()
|
drawCallback: () => lucide.createIcons()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Search Controls
|
// Global Search
|
||||||
$('#global-search').on('keyup', function () {
|
$('#global-search').on('keyup', function () {
|
||||||
table.search(this.value, true, false).draw();
|
table.search(this.value, true, false).draw();
|
||||||
$('#clear-search').toggle(this.value.length > 0);
|
$('#clear-search').toggle(this.value.length > 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#clear-search').on('click', function () {
|
$('#clear-search').on('click', resetFilters);
|
||||||
$('#global-search').val('').trigger('keyup');
|
|
||||||
chart.resetZoom();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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');
|
const ctx = document.getElementById('intensityChart').getContext('2d');
|
||||||
chart = new Chart(ctx, {
|
chart = new Chart(ctx, {
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
data: { labels: [], datasets: [{ label: 'Logs', data: [], backgroundColor: '#4ade80', barPercentage: 0.9, categoryPercentage: 0.9 }] },
|
data: { labels: [], datasets: [{ label: 'Logs', data: [], backgroundColor: '#4ade80', barPercentage: 0.9, categoryPercentage: 0.9 }] },
|
||||||
options: {
|
options: {
|
||||||
responsive: true, maintainAspectRatio: false,
|
responsive: true, maintainAspectRatio: false,
|
||||||
plugins: {
|
plugins: { legend: { display: false }, tooltip: { enabled: true } },
|
||||||
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) }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scales: {
|
scales: {
|
||||||
x: { ticks: { color: '#64748b', font: { size: 10 } }, grid: { display: false } },
|
x: { ticks: { color: '#64748b', font: { size: 10 } }, grid: { display: false } },
|
||||||
y: { beginAtZero: true, grid: { color: '#1e293b' }, ticks: { color: '#64748b', font: { size: 10 } } }
|
y: { beginAtZero: true, grid: { color: '#1e293b' }, ticks: { color: '#64748b', font: { size: 10 } } }
|
||||||
@@ -350,51 +357,78 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Manual Zoom Controls
|
// --- DRAG TO SELECT LOGIC ---
|
||||||
$('#reset-chart-btn').on('click', () => chart.resetZoom());
|
let isDragging = false;
|
||||||
|
let startX = 0;
|
||||||
|
const $overlay = $('#selection-overlay');
|
||||||
|
const $rect = $('.selection-rect');
|
||||||
|
|
||||||
// Right Click on Canvas to Zoom Out
|
$('#chart-parent').on('mousedown', function (e) {
|
||||||
document.getElementById('intensityChart').addEventListener('contextmenu', (e) => {
|
isDragging = true;
|
||||||
e.preventDefault();
|
startX = e.pageX - $overlay.offset().left;
|
||||||
chart.resetZoom();
|
$rect.attr({ 'x': startX, 'width': 0 }).show();
|
||||||
});
|
});
|
||||||
|
|
||||||
function updateFiltersFromZoom(chartInstance) {
|
$(window).on('mousemove', function (e) {
|
||||||
const minIndex = Math.floor(chartInstance.scales.x.min);
|
if (!isDragging) return;
|
||||||
const maxIndex = Math.ceil(chartInstance.scales.x.max);
|
let currentX = e.pageX - $overlay.offset().left;
|
||||||
const labels = chartInstance.data.labels;
|
let width = currentX - startX;
|
||||||
|
if (width < 0) {
|
||||||
|
$rect.attr('x', currentX).attr('width', Math.abs(width));
|
||||||
|
} else {
|
||||||
|
$rect.attr('width', width);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
visibleTimeRange = {
|
$(window).on('mouseup', function (e) {
|
||||||
min: labels[Math.max(0, minIndex)],
|
if (!isDragging) return;
|
||||||
max: labels[Math.min(labels.length - 1, maxIndex)]
|
isDragging = false;
|
||||||
|
|
||||||
|
const finalX = parseInt($rect.attr('x'));
|
||||||
|
const finalWidth = parseInt($rect.attr('width'));
|
||||||
|
|
||||||
|
if (finalWidth < 5) { // If just a click
|
||||||
|
resetFilters();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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))];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update main level counters based on zoomed logs
|
timeRange.start = getValAtPixel(finalX);
|
||||||
const filteredLogs = rawLogs.filter(l => {
|
timeRange.end = getValAtPixel(finalX + finalWidth);
|
||||||
const time = l.time.substring(0, 5);
|
|
||||||
return time >= visibleTimeRange.min && time <= visibleTimeRange.max;
|
|
||||||
});
|
|
||||||
|
|
||||||
updateLevelCounts(filteredLogs);
|
$('#filter-info').show();
|
||||||
table.draw(); // Refresh table view based on global search + new time range
|
table.draw();
|
||||||
}
|
});
|
||||||
|
|
||||||
// Combined Filter (DataTable search + Level toggles + Zoom range)
|
// Right-click reset
|
||||||
|
$('#chart-parent').on('contextmenu', e => { e.preventDefault(); resetFilters(); });
|
||||||
|
|
||||||
|
// Custom Table Filter (Time + Level)
|
||||||
$.fn.dataTable.ext.search.push((settings, data, dataIndex) => {
|
$.fn.dataTable.ext.search.push((settings, data, dataIndex) => {
|
||||||
const lvl = data[1];
|
const lvl = data[1];
|
||||||
const checked = $('.btn-check:checked').map((i, el) => $(el).val()).get();
|
const checked = $('.btn-check:checked').map((i, el) => $(el).val()).get();
|
||||||
if (!checked.includes(lvl)) return false;
|
if (!checked.includes(lvl)) return false;
|
||||||
|
|
||||||
if (visibleTimeRange.min && visibleTimeRange.max) {
|
if (timeRange.start && timeRange.end) {
|
||||||
const logTime = data[2].substring(0, 5);
|
const logTime = data[2].substring(0, 5); // HH:mm
|
||||||
return logTime >= visibleTimeRange.min && logTime <= visibleTimeRange.max;
|
return logTime >= timeRange.start && logTime <= timeRange.end;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.btn-check').on('change', () => table.draw());
|
$('.btn-check').on('change', () => table.draw());
|
||||||
|
|
||||||
// File/Directory logic
|
// File loading
|
||||||
$('#dir-input').on('change', function (e) {
|
$('#dir-input').on('change', function (e) {
|
||||||
const files = Array.from(e.target.files).filter(f => f.name.endsWith('.log'));
|
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>`));
|
$('#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');
|
$('.file-item').removeClass('active').eq(idx).addClass('active');
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = e => {
|
reader.onload = e => {
|
||||||
rawLogs = parseLogs(e.target.result);
|
const logs = parseLogs(e.target.result);
|
||||||
table.clear().rows.add(rawLogs).draw();
|
table.clear().rows.add(logs).draw();
|
||||||
|
updateAnalytics(logs);
|
||||||
// Set initial chart data
|
resetFilters();
|
||||||
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);
|
|
||||||
};
|
};
|
||||||
reader.readAsText(window.loadedFiles[idx]);
|
reader.readAsText(window.loadedFiles[idx]);
|
||||||
};
|
};
|
||||||
|
|
||||||
function parseLogs(text) {
|
function parseLogs(text) {
|
||||||
const logs = [];
|
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 => {
|
text.split(/\r?\n/).forEach(line => {
|
||||||
const match = line.match(regex);
|
const match = line.match(regex);
|
||||||
if (match) logs.push({ time: match[1], level: match[2], message: match[3], exception: "" });
|
if (match) logs.push({ time: match[1], level: match[2], message: match[3], exception: "" });
|
||||||
@@ -435,10 +458,18 @@
|
|||||||
return logs;
|
return logs;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateLevelCounts(logs) {
|
function updateAnalytics(logs) {
|
||||||
const counts = { INF: 0, WRN: 0, ERR: 0, CRT: 0 };
|
const counts = { INF: 0, WRN: 0, ERR: 0, CRT: 0 }, bins = {};
|
||||||
logs.forEach(l => { if (counts[l.level] !== undefined) counts[l.level]++; });
|
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()));
|
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 () {
|
$('#log-table tbody').on('click', 'tr', function () {
|
||||||
|
|||||||
Vendored
-7
@@ -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
|
|
||||||
Vendored
-7
@@ -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
|
|
||||||
Reference in new issue
Block a user