Add UI dump visualizer with HTML, CSS, and JS components
Introduced a new tool for visualizing UI dumps, enabling users to upload XML and image files for inspection. The implementation includes an HTML structure, styled with CSS, and JavaScript for processing files and rendering elements dynamically onto a canvas. This provides a lightweight and functional interface for visual analysis.
This commit is contained in:
parent
0d80a4c11e
commit
6823676e14
28
assets/visualizer/index.html
Normal file
28
assets/visualizer/index.html
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>UI Dump Viewer</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="layout">
|
||||||
|
<div id="sidebar">
|
||||||
|
<h3>UIDump Viewer</h3>
|
||||||
|
<label>XML файл:</label><br>
|
||||||
|
<input type="file" id="xmlInput" accept=".xml"><br><br>
|
||||||
|
|
||||||
|
<label>Скриншот:</label><br>
|
||||||
|
<input type="file" id="imgInput" accept="image/*">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="content">
|
||||||
|
<div id="canvas"></div>
|
||||||
|
<div id="screenshot-container">
|
||||||
|
<img id="screenshot" alt="screenshot">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
70
assets/visualizer/script.js
Normal file
70
assets/visualizer/script.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
let dumpWidth = 1080;
|
||||||
|
let dumpHeight = 1920;
|
||||||
|
|
||||||
|
document.getElementById('xmlInput').addEventListener('change', handleXml);
|
||||||
|
document.getElementById('imgInput').addEventListener('change', handleImage);
|
||||||
|
|
||||||
|
function handleImage(event) {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
|
||||||
|
const url = URL.createObjectURL(file);
|
||||||
|
document.getElementById('screenshot').src = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleXml(event) {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
|
||||||
|
const text = await file.text();
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const xml = parser.parseFromString(text, "text/xml");
|
||||||
|
|
||||||
|
const nodes = Array.from(xml.querySelectorAll("node"));
|
||||||
|
const canvas = document.getElementById("canvas");
|
||||||
|
canvas.innerHTML = "";
|
||||||
|
|
||||||
|
// Автоопределение размеров дампа
|
||||||
|
let maxX = 0, maxY = 0;
|
||||||
|
for (const node of nodes) {
|
||||||
|
const bounds = node.getAttribute("bounds");
|
||||||
|
const match = bounds && bounds.match(/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/);
|
||||||
|
if (!match) continue;
|
||||||
|
|
||||||
|
const [, , , x2, y2] = match.map(Number);
|
||||||
|
if (x2 > maxX) maxX = x2;
|
||||||
|
if (y2 > maxY) maxY = y2;
|
||||||
|
}
|
||||||
|
dumpWidth = maxX;
|
||||||
|
dumpHeight = maxY;
|
||||||
|
|
||||||
|
// Масштабирование по высоте экрана с отступами
|
||||||
|
const padding = 100;
|
||||||
|
const displayHeight = window.innerHeight - padding;
|
||||||
|
const scale = displayHeight / dumpHeight;
|
||||||
|
const displayWidth = dumpWidth * scale;
|
||||||
|
|
||||||
|
// Установка размеров canvas
|
||||||
|
canvas.style.width = `${displayWidth}px`;
|
||||||
|
canvas.style.height = `${displayHeight}px`;
|
||||||
|
|
||||||
|
for (const node of nodes) {
|
||||||
|
const bounds = node.getAttribute("bounds");
|
||||||
|
const match = bounds && bounds.match(/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/);
|
||||||
|
if (!match) continue;
|
||||||
|
|
||||||
|
const [, x1, y1, x2, y2] = match.map(Number);
|
||||||
|
|
||||||
|
const div = document.createElement("div");
|
||||||
|
div.className = "rect";
|
||||||
|
div.style.left = `${x1 * scale}px`;
|
||||||
|
div.style.top = `${y1 * scale}px`;
|
||||||
|
div.style.width = `${(x2 - x1) * scale}px`;
|
||||||
|
div.style.height = `${(y2 - y1) * scale}px`;
|
||||||
|
|
||||||
|
const text = (node.getAttribute("text") || '').trim();
|
||||||
|
if (text) div.innerText = text;
|
||||||
|
|
||||||
|
canvas.appendChild(div);
|
||||||
|
}
|
||||||
|
}
|
||||||
72
assets/visualizer/style.css
Normal file
72
assets/visualizer/style.css
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
body, html {
|
||||||
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
|
font-family: sans-serif;
|
||||||
|
background-color: #f4f4f4; /* вернули светлый фон */
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
#layout {
|
||||||
|
display: flex;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar {
|
||||||
|
width: 250px;
|
||||||
|
padding: 20px;
|
||||||
|
background: #ffffff; /* светлая боковая панель */
|
||||||
|
border-right: 1px solid #ccc;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar h3, label {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar input[type="file"] {
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 6px;
|
||||||
|
margin-top: 4px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 50px 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
gap: 20px;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
#canvas {
|
||||||
|
position: relative;
|
||||||
|
background: #2a2a2a; /* серый фон области дампа */
|
||||||
|
border: 1px solid #444;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#screenshot-container {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#screenshot {
|
||||||
|
max-height: calc(100vh - 100px);
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rect {
|
||||||
|
position: absolute;
|
||||||
|
border: 1px dashed #ff9800;
|
||||||
|
background: transparent;
|
||||||
|
color: #ff9800;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user