Better graph performance, light theme fixes

This commit is contained in:
Luke Street
2024-09-17 19:16:56 -06:00
parent 7b47efd66d
commit 9aa82494fc
10 changed files with 77 additions and 35 deletions
Generated
+3 -2
View File
@@ -2354,8 +2354,9 @@ dependencies = [
[[package]]
name = "objdiff-core"
version = "2.0.0-beta.6"
source = "git+https://github.com/encounter/objdiff?tag=v2.0.0-beta.6#e1ae369d172240091735c7063f85d54c5052ac62"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5a4a551c6f2c06663c06c4b8f5829e7ed4e12c15e10f644d76021f2287bf5a8"
dependencies = [
"anyhow",
"byteorder",
+1 -1
View File
@@ -16,7 +16,7 @@ mime = "0.3"
minijinja = { version = "2.2", features = ["loader", "json"] }
minijinja-autoreload = "2.2"
moka = { version = "0.12", features = ["future"] }
objdiff-core = { git = "https://github.com/encounter/objdiff", tag = "v2.0.0-beta.6", features = ["bindings"] }
objdiff-core = { version = "2.0", features = ["bindings"] }
#objdiff-core = { path = "../objdiff/objdiff-core", features = ["bindings"] }
octocrab = "0.39"
oxc = { version = "0.27", features = ["codegen", "minifier", "transformer", "semantic"] }
+10 -5
View File
@@ -97,12 +97,16 @@ $breakpoints: (
:root:not([data-theme=dark]) {
--pico-code-kbd-color: #000;
--pico-code-kbd-background-color: #fff;
--progress-background-color: #{$slate-100};
--progress-stripe-color: rgba(0, 0, 0, 0.15);
}
@mixin pico-theme-dark {
--pico-background-color: #181c25;
--pico-code-kbd-color: #fff;
--pico-code-kbd-background-color: #333;
--progress-background-color: #{$slate-800};
--progress-stripe-color: rgba(255, 255, 255, 0.15);
}
[data-theme=dark] {
@@ -163,17 +167,17 @@ $progress-height: 2rem;
height: $progress-height;
overflow: hidden;
border-radius: var(--pico-border-radius);
background-color: $slate-800;
background-color: var(--progress-background-color);
.progress-section.striped {
//animation: progress-stripes 1s linear infinite;
background-image: linear-gradient(
45deg,
rgba(255, 255, 255, .15) 25%,
var(--progress-stripe-color) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, .15) 50%,
rgba(255, 255, 255, .15) 75%,
var(--progress-stripe-color) 50%,
var(--progress-stripe-color) 75%,
transparent 75%,
transparent);
background-size: calc(1.25rem) calc(1.25rem);
@@ -190,7 +194,7 @@ $progress-height: 2rem;
}
.progress-section:nth-child(3) {
background-color: $slate-800;
background-color: transparent;
}
}
@@ -259,4 +263,5 @@ $unit-size: 0.75rem;
--font-size: 0.875rem;
--font-family: var(--pico-font-family);
--tooltip-background: var(--pico-tooltip-background-color);
--tooltip-color: var(--pico-tooltip-color);
}
+43 -17
View File
@@ -28,6 +28,7 @@ const drawTooltip = (ctx: CanvasRenderingContext2D, unit: Unit, width: number, h
const fontSize = style.getPropertyValue('--font-size') || '16px';
const fontFamily = style.getPropertyValue('--font-family') || 'sans-serif';
const tooltipBackground = style.getPropertyValue('--tooltip-background') || "#fff"
const tooltipColor = style.getPropertyValue('--tooltip-color') || "#000"
ctx.font = `${fontWeight} ${fontSize} ${fontFamily}`;
ctx.textBaseline = "middle";
@@ -65,18 +66,34 @@ const drawTooltip = (ctx: CanvasRenderingContext2D, unit: Unit, width: number, h
ctx.lineTo(ax - margin, y - margin);
}
ctx.fill();
ctx.fillStyle = "#000";
ctx.fillStyle = tooltipColor;
ctx.fillText(text, bx + PADDING_W, by + bh / 2);
};
let hovered = null;
let dirty = false;
let isTouch = false;
let cachedCanvas: HTMLCanvasElement = null;
const setup = (ctx: CanvasRenderingContext2D, ratio: number, width: number, height: number) => {
ctx.setTransform(ratio, 0, 0, ratio, 0, 0); // Scale to device pixel ratio
ctx.clearRect(0, 0, width, height);
ctx.lineWidth = 1;
ctx.strokeStyle = "#000";
}
const drawUnits = (ctx: CanvasRenderingContext2D, units: Unit[], width: number, height: number) => {
for (const unit of units) {
const {x, y, w, h} = unitBounds(unit, width, height);
ctx.fillStyle = unit.color;
ctx.beginPath();
ctx.rect(x, y, w, h);
ctx.fill();
ctx.stroke();
}
}
const draw = (canvas: HTMLCanvasElement, units: Unit[]) => {
if (!canvas.getContext) {
return;
}
const {width, height} = canvas.getBoundingClientRect();
const ratio = window.devicePixelRatio;
const renderWidth = width * ratio;
@@ -91,19 +108,25 @@ const draw = (canvas: HTMLCanvasElement, units: Unit[]) => {
canvas.width = renderWidth;
canvas.height = renderHeight;
}
const ctx = canvas.getContext("2d");
ctx.setTransform(ratio, 0, 0, ratio, 0, 0); // Scale to device pixel ratio
ctx.clearRect(0, 0, width, height);
ctx.lineWidth = 1;
ctx.strokeStyle = "#000";
for (const unit of units) {
const {x, y, w, h} = unitBounds(unit, width, height);
ctx.fillStyle = unit.color;
ctx.beginPath();
ctx.rect(x, y, w, h);
ctx.fill();
ctx.stroke();
// Update cached canvas if needed
if (cachedCanvas.width !== renderWidth || cachedCanvas.height !== renderHeight) {
cachedCanvas.width = renderWidth;
cachedCanvas.height = renderHeight;
const cachedCtx = cachedCanvas.getContext("2d");
if (!cachedCtx) {
return;
}
setup(cachedCtx, ratio, width, height);
drawUnits(cachedCtx, units, width, height);
}
const ctx = canvas.getContext("2d");
if (!ctx) {
return;
}
// Use 1:1 scale for rendering cached canvas
setup(ctx, 1, renderWidth, renderHeight);
ctx.drawImage(cachedCanvas, 0, 0);
ctx.scale(ratio, ratio); // Restore device scale
if (hovered) {
const {x, y, w, h} = unitBounds(hovered, width, height);
ctx.lineWidth = 2;
@@ -115,9 +138,12 @@ const draw = (canvas: HTMLCanvasElement, units: Unit[]) => {
const drawGraph = (id: string, units: Unit[]) => {
const canvas = document.getElementById(id) as HTMLCanvasElement;
if (!canvas) {
if (!canvas || !canvas.getContext) {
return;
}
if (!cachedCanvas) {
cachedCanvas = document.createElement("canvas");
}
const queueDraw = () => requestAnimationFrame(() => draw(canvas, units));
const resizeObserver = new ResizeObserver(queueDraw);
resizeObserver.observe(canvas);
+3 -2
View File
@@ -1,4 +1,4 @@
use std::{ffi::OsStr, path::PathBuf};
use std::ffi::OsStr;
use anyhow::anyhow;
use axum::{
@@ -8,9 +8,10 @@ use axum::{
};
use super::AppError;
use crate::util::join_normalized;
pub async fn get_css(Path(filename): Path<String>) -> Result<Response, AppError> {
let mut path = PathBuf::from(format!("css/{filename}"));
let mut path = join_normalized("css", &filename);
if path.extension() != Some(OsStr::new("css")) {
return Err(AppError::Status(StatusCode::NOT_FOUND));
}
+4 -4
View File
@@ -1,4 +1,4 @@
use std::{ffi::OsStr, path::PathBuf};
use std::ffi::OsStr;
use anyhow::{anyhow, Result};
use axum::{
@@ -16,10 +16,10 @@ use oxc::{
transformer::{EnvOptions, Targets, TransformOptions, Transformer},
};
use crate::handlers::AppError;
use crate::{handlers::AppError, util::join_normalized};
pub async fn get_js(Path(filename): Path<String>) -> Result<Response, AppError> {
let mut path = PathBuf::from(format!("js/{filename}"));
let mut path = join_normalized("js", &filename);
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum ResponseType {
Js,
@@ -82,7 +82,7 @@ fn transform(
.into_symbol_table_and_scope_tree();
let transform_options = TransformOptions::from_preset_env(&EnvOptions {
targets: Targets::from_query("es2020"),
targets: Targets::from_query("defaults"),
..EnvOptions::default()
})
.map_err(|v| anyhow!("{}", v.first().unwrap()))?;
+1 -1
View File
@@ -2,7 +2,7 @@ use std::{iter, str::FromStr, time::Instant};
use anyhow::{Context, Result};
use axum::{
extract::{ Path, Query, State},
extract::{Path, Query, State},
http::{header, HeaderMap, StatusCode, Uri},
response::{Html, IntoResponse, Response},
Json,
+9
View File
@@ -1,3 +1,5 @@
use std::path::{Path, PathBuf};
use url::Url;
pub trait UrlExt {
@@ -48,3 +50,10 @@ impl UrlExt for Url {
#[inline]
fn path_and_query(&self) -> &str { &self[url::Position::BeforePath..] }
}
/// Join two paths, only including the normal components.
pub fn join_normalized(base: impl AsRef<Path>, path: impl AsRef<Path>) -> PathBuf {
let mut out = base.as_ref().to_path_buf();
out.extend(path.as_ref().components().filter(|v| matches!(v, std::path::Component::Normal(_))));
out
}
+1 -1
View File
@@ -61,7 +61,7 @@
data-tooltip="{{ measures.fuzzy_match_percent | round(2) }}% fuzzy match"></div>
</div>
<small class="muted">
<span title="{{ project.timestamp | date }}">Last updated: {{ project.timestamp | timeago }}</span>
<span title="{{ project.timestamp | date }}">Updated {{ project.timestamp | timeago }}</span>
in commit <a href="https://github.com/{{ project.owner }}/{{ project.repo }}/commit/{{ project.commit }}"
target="_blank">{{ project.commit[:7] }}</a>
</small>
+2 -2
View File
@@ -7,11 +7,11 @@
<meta name="darkreader-lock">
<meta name="description" content="Decompilation progress report for {{ project_name }}{% if current_category.id != 'all' %} ({{ current_category.name }}){% endif %}">
<title>{{ project_short_name }}{% if current_category.id != "all" %} ({{ current_category.name }}){% endif %} • Progress Report</title>
<link rel="stylesheet" href="/css/main.min.css?3">
<link rel="stylesheet" href="/css/main.min.css?4">
<script src="https://unpkg.com/htmx.org@2.0.2"
integrity="sha384-Y7hw+L/jvKeWIRRkqWYfPcvVxHzVzn5REgzbawhxAuQGwX1XWe70vji+VSeHOThJ"
crossorigin="anonymous"></script>
<script src="/js/graph.min.js?5"></script>
<script src="/js/graph.min.js?6"></script>
<meta property="og:title" content="{{ project_short_name }}{% if current_category.id != 'all' %} ({{ current_category.name }}){% endif %} is {{ measures.matched_code_percent | round(2) }}% decompiled">
<meta property="og:description" content="Decompilation progress report for {{ project_name }}{% if current_category.id != 'all' %} ({{ current_category.name }}){% endif %}">
<meta property="og:image" content="{{ image_url | safe }}">