From 8eed49067b82c7ec017ace069427185a2e135e41 Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Wed, 18 Dec 2024 00:49:41 +0100 Subject: Add display and fix many issues --- src/clicks_display.ts | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 src/clicks_display.ts (limited to 'src/clicks_display.ts') diff --git a/src/clicks_display.ts b/src/clicks_display.ts new file mode 100644 index 0000000..ff54705 --- /dev/null +++ b/src/clicks_display.ts @@ -0,0 +1,137 @@ +import h337 from "heatmap.js" + +namespace Clicks { + export type ClickEvent = { + x: number + y: number + tag: string + } + + export type UrlEvent = { + url: string + } + + export type Event = ClickEvent | UrlEvent + + export interface Format { + format: string + version: string + width: number + height: number + brands: string + events: Event[] + } +} + +class PageData { + readonly url: string + readonly data: h337.HeatmapData + + constructor(url: string, data: h337.DataPoint[]) { + this.url = url + let maxValue = 0 + for (const d of data) { + if (d.value > maxValue) maxValue = d.value + } + this.data = { + data: data, + min: 0, + max: maxValue, + } + } +} + +class Display { + private status: HTMLElement + private frame: HTMLIFrameElement + private heatmap: HTMLElement + private data: PageData[] | undefined + private map: h337.Heatmap<"value", "x", "y"> + + constructor() { + this.status = document.getElementById("status")!! + this.frame = document.getElementById("frame")!! as HTMLIFrameElement + this.heatmap = document.getElementById("heatmap")!! + this.map = h337.create({ + container: this.heatmap + }) + } + + loadFile(file: File) { + this.setStatus("Loading...") + const reader = new FileReader() + reader.addEventListener('load', () => { + const data = JSON.parse(reader.result as string) as Clicks.Format + if (data.format !== "clicks" || data.version !== "1.0") { + this.setStatus("Unknown format") + return + } + this.data = [] + const scaleX = this.frame.clientWidth + const scaleY = data.width + let url: string | undefined + let clicks: h337.DataPoint[] = [] + let map = new Map() + for (const event of data.events) { + if ("url" in event) { + if (url !== undefined) { + console.log(clicks) + this.data.push(new PageData(url, clicks)) + } + url = event.url + clicks = [] + map.clear() + } else { + const ce = event as Clicks.ClickEvent + const x = Math.round(ce.x * scaleX) + const y = Math.round(ce.y * scaleY) + const pos = `${x}x${y}` + const index = map.get(pos) + if (index === undefined) { + map.set(pos, clicks!!.length) + clicks.push({ x: x, y: y, value: 1}) + } else { + clicks[index].value++ + } + } + } + if (url !== undefined) { + console.log(clicks) + this.data.push(new PageData(url, clicks)) + } + + this.setStatus("Loaded") + if (this.data.length > 0) + this.show(this.data[0]) + }) + reader.readAsText(file) + } + + private setStatus(newStatus: string) { + this.status.innerText = newStatus + } + + private show(data: PageData) { + this.frame.src = data.url + this.heatmap.style.transform = 'translateY(0px)' + this.frame.addEventListener('load', () => { + this.frame.contentDocument?.addEventListener('scroll', () => { + const y = this.frame.contentDocument!!.documentElement.scrollTop + this.heatmap.style.transform = `translateY(${-y}px)` + }) + }) + this.map.setData(data.data) + } +} + +document.addEventListener('DOMContentLoaded', () => { + const file = document.getElementById('file') + const display = new Display() + file?.addEventListener('change', (event: Event) => { + const files = (event.target as HTMLInputElement | null)!!.files + if (files === null) return + if (files.length > 0) { + display.loadFile(files[0]) + } + }) +}) \ No newline at end of file -- cgit v1.2.3-70-g09d2