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

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more