Skip to content

Instantly share code, notes, and snippets.

@MatthiasKunnen
Created September 1, 2018 00:54
Show Gist options
  • Save MatthiasKunnen/43997754dba643e1b4c6bcc03b72cf06 to your computer and use it in GitHub Desktop.
Save MatthiasKunnen/43997754dba643e1b4c6bcc03b72cf06 to your computer and use it in GitHub Desktop.
Visualize a hierarchy.xml file. Outputted by uiautomator dump /sdcard/hierarchy.xml
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<style>
body {
display: flex;
flex-direction: column;
align-items: center;
}
#render {
position: relative;
}
#render > * {
border: 1px solid;
}
#render > *:hover {
border-width: 3px;
}
.info > * {
margin-right: 1rem;
}
</style>
</head>
<body>
<div id="render-wrapper">
<div class="info">
<span>
x:
<span id="coord-x">-</span>
</span>
<span>
y:
<span id="coord-y">-</span>
</span>
</div>
<div id="render">
</div>
</div>
<label for="hierarchyInput">Input</label>
<textarea id="hierarchyInput">
</textarea>
<button id="renderButton">Render</button>
<script>
jQuery(() => {
const coordX = jQuery('#coord-x');
const coordY = jQuery('#coord-y');
const renderInput = jQuery('#hierarchyInput');
const render = jQuery('#render');
let zoomPercentage = 1;
const processBoundsFormat = (bounds) => {
const [left, top] = bounds.substring(1, bounds.indexOf(']')).split(',');
const [xBottom, yBottom] = bounds.substring(bounds.indexOf('[', 1) + 1, bounds.lastIndexOf(']')).split(',');
return {
left,
top,
width: xBottom - left,
height: yBottom - top,
};
};
const getRenderRelativeCoords = () => {
const renderOffset = render.offset();
return {
x: ((event.pageX - renderOffset.left * zoomPercentage) / zoomPercentage).toFixed(),
y: ((event.pageY - renderOffset.top * zoomPercentage) / zoomPercentage).toFixed()
}
};
render.mousemove(() => {
const coords = getRenderRelativeCoords();
coordX.text(coords.x);
coordY.text(coords.y);
});
render.mousedown(() => {
console.log(Object.values(getRenderRelativeCoords()).join(','));
});
jQuery('#renderButton').click(() => {
render.html('');
const hierarchy = jQuery(renderInput.val());
const hierarchyBounds = processBoundsFormat(hierarchy.find('node').first().attr('bounds'));
const viewPortHeight = window.innerHeight;
// 150 to keep coords and input on screen
zoomPercentage = (viewPortHeight - 150) / hierarchyBounds.height;
render.css({
width: hierarchyBounds.width + 'px',
height: hierarchyBounds.height + 'px',
zoom: zoomPercentage,
});
hierarchy.find('node').each((index, item) => {
const e = jQuery(item);
const attributes = Object.keys(item.attributes).reduce((acc, curr) => {
const attribute = item.attributes[curr];
acc.push(`${attribute.name}: ${attribute.value}`);
return acc;
}, []);
const bounds = processBoundsFormat(e.attr('bounds'));
render.append(jQuery('<div>')
.css({
position: 'absolute',
left: bounds.left + 'px',
top: bounds.top + 'px',
width: bounds.width + 'px',
height: bounds.height + 'px',
})
.html('<!--' + attributes.join('\n') + '-->'));
});
})
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment