Public
Edited
Feb 6
Importers
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
let url = QueueExample[1].results[100].link;

return svg`<svg><image href="${url}" width="100" height="32"></image></svg>`
}
Insert cell
QueueExample = {
const renderer = new TextRenderQueueV2(3,3); // Create a pool of workers

async function renderTexts() {
const texts = Array.from({ length: 861 }, (_, i) => `Text ${i}`);
const options = { family: "Arial", size: 20, fill: "blue", resolution: 2 };

// Submit all tasks at once
const promises = texts.map((text) => renderer.render(text, options));

// Wait for all tasks to complete
let t1 = performance.now()
const results = await Promise.all(promises);

return {time:~~(performance.now()-t1),results}
}
invalidation.then(()=>renderer.destroy())
return [renderer,await renderTexts()]

}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function renderTextAsync(textContent, options = {}) {
function workerCode() {
self.onmessage = function (e) {
const { textContent, options } = e.data;

// Apply defaults to options
const {
family = "Arial", // Default font family
size = 10, // Default font size
resolution = 2, // Default resolution
canvas = new OffscreenCanvas(0, 0)
} = options || {};

// Create an OffscreenCanvas
//const canvas = new OffscreenCanvas(0, 0);

const ctx = canvas.getContext("2d");

// Set font size and family
const font = `${size * resolution}px ${family}`;
ctx.font = font;

// Measure text dimensions
const metrics = ctx.measureText(textContent);
const ascent = Math.round(metrics.actualBoundingBoxAscent);
const descent = Math.round(metrics.actualBoundingBoxDescent);
const left = Math.round(metrics.actualBoundingBoxLeft);
const right = Math.round(metrics.actualBoundingBoxRight);

const width = left + right;
const height = ascent + descent;

// Resize canvas
canvas.width = width;
canvas.height = height;
ctx.font = font;

// Draw text
ctx.fillStyle = "black"; // Default text color
ctx.fillText(textContent, left, ascent);

// Convert to blob and send back to main thread
canvas.convertToBlob().then((blob) => {
const reader = new FileReader();
reader.onload = () => {
self.postMessage({
width,
height,
data: reader.result
});
};
reader.readAsDataURL(blob);
});
};
}

let src = workerCode.toString();
src = src.split(/\n/g).slice(1, -1).join("\n");
let blob = new Blob([src], { type: "text/javascript" });

let objectURL = URL.createObjectURL(blob);

return new Promise((resolve) => {
const worker = new Worker(objectURL, { type: "module" });

if (options.canvas) {
worker.postMessage({ textContent, options }, [options.canvas]);
} else {
worker.postMessage({ textContent, options });
}

worker.onmessage = (e) => {
const { width, height, data } = e.data;
worker.terminate(); // Clean up the worker
resolve({ width, height, data });
};
});
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
let Supervisor = {
input: (data) => data,
result: (data) => data,
maxWorkers: 1
};

let TextMetrics = {
input: (data) => data,
output: (data) => data,
maxWorkers: 2
};

let TextRenderer = {
input: (data) => data,
output: (data) => data,
maxWorkers: 4
};

let Workflow = [
{ source: Supervisor.output, target: TextMetrics.input },
{ source: TextMetrics.output, target: TextRenderer.input },
{ source: TextRenderer.input, target: Supervisor.result }
];

return Workflow;
}

Insert cell
class ForwardChannel {
constructor(workerA, workerB, outgoingCallback = null, incomingCallback = null) {
this.source = workerA;
this.target = workerB;
this.outgoingCallback = outgoingCallback;
this.incomingCallback = incomingCallback;
this.channel = new MessageChannel();
this.setupCommunication();
}

setupCommunication() {
// Set up worker A to B communication
this.source.postMessage({
type: "CHANNEL_INIT",
port: this.channel.port1,
});

// Set up worker B to A communication
this.target.postMessage({
type: "CHANNEL_INIT",
port: this.channel.port2,
});

// Handle incoming messages from worker A
this.source.onmessage = (e) => {
if (typeof this.outgoingCallback === "function") {
this.outgoingCallback(e.data);
}

if (e.data.type !== "CHANNEL_INIT") {
this.target.postMessage(e.data);
}
};

// Handle incoming messages from worker B
this.target.onmessage = (e) => {
if (typeof this.incomingCallback === "function") {
this.incomingCallback(e.data);
}

if (e.data.type !== "CHANNEL_INIT") {
this.source.postMessage(e.data);
}
};
}

destroy() {
// Clean up event listeners
this.source.onmessage = null;
this.target.onmessage = null;

// Terminate workers
this.source.terminate();
this.target.terminate();

// Clear callbacks
this.outgoingCallback = null;
this.incomingCallback = null;
}
}
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more