vanillaCanvasScatter = async (data, vx, vy) => {
const size = 50;
const margin = {l: 0.2 * width, r: 0.1 * width, t: 0.1 * height, b: 0.1 * height};
const wm = width - margin.l - margin.r;
const hm = height - margin.t - margin.b;
const filtered = data;
const domainX = [...new Set(filtered.map(d => d[vx]))];
const domainY = [...new Set(filtered.map(d => d[vy]))];
const scaleX = d3.scalePoint().domain(domainX).range([0, wm]).padding(0.5).round(true);
const scaleY = d3.scalePoint().domain(domainY).range([0, hm]).padding(0.5).round(true);
const imgs = [];
for (let d of filtered) {
const img = new Image();
img.setAttribute('crossorigin', 'anonymous');
img.src = d.url;
await new Promise(r => { img.onload = () => { r(true) }});
imgs.push({ url: d.url, x: scaleX(d[vx]), y: scaleY(d[vy]), img: img, r: size, n: d.n });
}
const simulation = d3.forceSimulation(imgs)
.force("charge", d3.forceManyBody().strength(5))
.force("collide", d3.forceCollide(10))
.tick(200)
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
ctx.fillStyle = "#313131";
ctx.fillRect(0, 0, width, height);
ctx.strokeStyle = "white";
ctx.font = "14px serif";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
for (let d of domainX) {
ctx.fillStyle = "white";
ctx.fillText(d, margin.l + scaleX(d), margin.t + hm + (margin.b / 2));
}
ctx.beginPath();
ctx.moveTo(margin.l, margin.t + hm);
ctx.lineTo(margin.l + wm, margin.t + hm);
ctx.stroke();
ctx.textAlign = "right";
for (let d of domainY) {
ctx.fillStyle = "white";
ctx.fillText(d, margin.l - 5, margin.t + scaleY(d));
}
ctx.beginPath();
ctx.moveTo(margin.l, margin.t);
ctx.lineTo(margin.l, margin.t + hm);
ctx.stroke();
ctx.strokeStyle = "black";
const areas = [];
for (let i of imgs) {
const w = size;
const h = w * i.img.height / i.img.width;
const j = Math.random() * 100;
const x = i.x + margin.l + j;
const y = i.y + margin.t
ctx.save();
ctx.translate(-w/2, -h/2);
ctx.drawImage(i.img, x, y, w, h);
ctx.restore();
const area = {
x, y, w, h,
btn: "",
scene: `ind_${i.n}`,
tooltip: ""
}
areas.push(area);
}
return {viz: canvas.toDataURL('image/png'), areas}
}