Skip to content
456 changes: 259 additions & 197 deletions glue/crumble/crumble.html

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions glue/crumble/draw/main_draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ function defensiveDraw(ctx, body) {
* @param {!StateSnapshot} snap
*/
function draw(ctx, snap) {
const devicePixelRatio = window.devicePixelRatio || 1;
ctx.save();
ctx.scale(devicePixelRatio, devicePixelRatio);
let circuit = snap.circuit;

let numPropagatedLayers = 0;
Expand Down Expand Up @@ -255,7 +258,7 @@ function draw(ctx, snap) {

defensiveDraw(ctx, () => {
ctx.fillStyle = 'white';
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.clearRect(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight);
let [focusX, focusY] = xyToPos(snap.curMouseX, snap.curMouseY);

// Draw the background polygons.
Expand Down Expand Up @@ -390,7 +393,7 @@ function draw(ctx, snap) {
ctx.save();
try {
ctx.strokeStyle = 'black';
ctx.translate(Math.floor(ctx.canvas.width / 2), 0);
ctx.translate(Math.floor(ctx.canvas.clientWidth / 2), 0);
for (let k = 0; k < circuit.layers.length; k++) {
let hasPolygons = false;
let hasXMarker = false;
Expand Down Expand Up @@ -485,6 +488,7 @@ function draw(ctx, snap) {
} finally {
ctx.restore();
}
ctx.restore(); // restore devicePixelRatio scale
}

export {xyToPos, draw, setDefensiveDrawEnabled, OFFSET_X, OFFSET_Y}
12 changes: 6 additions & 6 deletions glue/crumble/draw/timeline_viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ function drawTimelineMarkers(ctx, ds, qubitTimeCoordFunc, propagatedMarkers, mi,
* @param {!int} numLayers
*/
function drawTimeline(ctx, snap, propagatedMarkerLayers, timesliceQubitCoordsFunc, numLayers) {
let w = Math.floor(ctx.canvas.width / 2);
let w = Math.floor(ctx.canvas.clientWidth / 2);

let qubits = snap.timelineQubits();
qubits.sort((a, b) => {
Expand Down Expand Up @@ -133,7 +133,7 @@ function drawTimeline(ctx, snap, propagatedMarkerLayers, timesliceQubitCoordsFun
}

let x_pitch = TIMELINE_PITCH + Math.ceil(rad*max_run*0.25);
let num_cols_half = Math.floor(ctx.canvas.width / 4 / x_pitch);
let num_cols_half = Math.floor(ctx.canvas.clientWidth / 4 / x_pitch);
let min_t_free = snap.curLayer - num_cols_half + 1;
let min_t_clamp = Math.max(0, Math.min(min_t_free, numLayers - num_cols_half*2 + 1));
let max_t = Math.min(min_t_clamp + num_cols_half*2 + 2, numLayers);
Expand All @@ -157,7 +157,7 @@ function drawTimeline(ctx, snap, propagatedMarkerLayers, timesliceQubitCoordsFun

ctx.save();
try {
ctx.clearRect(w, 0, w, ctx.canvas.height);
ctx.clearRect(w, 0, w, ctx.canvas.clientHeight);

// Draw colored indicators showing Pauli propagation.
let hitCounts = new Map();
Expand All @@ -170,7 +170,7 @@ function drawTimeline(ctx, snap, propagatedMarkerLayers, timesliceQubitCoordsFun
ctx.fillStyle = 'black';
{
let x1 = t2t(snap.curLayer) + w * 1.5 - x_pitch / 2;
ctx.fillRect(x1, 0, x_pitch, ctx.canvas.height);
ctx.fillRect(x1, 0, x_pitch, ctx.canvas.clientHeight);
}
ctx.globalAlpha *= 2;

Expand Down Expand Up @@ -214,14 +214,14 @@ function drawTimeline(ctx, snap, propagatedMarkerLayers, timesliceQubitCoordsFun
for (let q of qubits) {
let [x0, y0] = qubitTimeCoords(q, min_t_clamp - 1);
let [x1, y1] = timesliceQubitCoordsFunc(q);
if (snap.curMouseX > ctx.canvas.width / 2 && snap.curMouseY >= y0 + OFFSET_Y - TIMELINE_PITCH * 0.55 && snap.curMouseY <= y0 + TIMELINE_PITCH * 0.55 + OFFSET_Y) {
if (snap.curMouseX > ctx.canvas.clientWidth / 2 && snap.curMouseY >= y0 + OFFSET_Y - TIMELINE_PITCH * 0.55 && snap.curMouseY <= y0 + TIMELINE_PITCH * 0.55 + OFFSET_Y) {
ctx.beginPath();
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.stroke();
ctx.fillStyle = 'black';
ctx.fillRect(x1 - 20, y1 - 20, 40, 40);
ctx.fillRect(ctx.canvas.width / 2, y0 - TIMELINE_PITCH / 3, ctx.canvas.width / 2, TIMELINE_PITCH * 2 / 3);
ctx.fillRect(ctx.canvas.clientWidth / 2, y0 - TIMELINE_PITCH / 3, ctx.canvas.clientWidth / 2, TIMELINE_PITCH * 2 / 3);
}
}
} finally {
Expand Down
12 changes: 8 additions & 4 deletions glue/crumble/keyboard/toolbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,13 @@ function getToolboxFocusedData(ev) {
* @param {!ChordEvent} ev
*/
function drawToolbox(ev) {
toolboxCanvas.width = toolboxCanvas.scrollWidth;
toolboxCanvas.height = toolboxCanvas.scrollHeight;
let ctx = toolboxCanvas.getContext('2d');
ctx.clearRect(0, 0, toolboxCanvas.width, toolboxCanvas.height);
const devicePixelRatio = window.devicePixelRatio || 1;
toolboxCanvas.width = toolboxCanvas.scrollWidth * devicePixelRatio;
toolboxCanvas.height = toolboxCanvas.scrollHeight * devicePixelRatio;
const ctx = toolboxCanvas.getContext('2d');
ctx.save();
ctx.scale(devicePixelRatio, devicePixelRatio);
ctx.clearRect(0, 0, toolboxCanvas.scrollWidth, toolboxCanvas.scrollHeight);
ctx.textAlign = 'right';
ctx.textBaseline = 'middle';
ctx.fillText('X', PAD - 3, PAD + DIAM / 2);
Expand Down Expand Up @@ -277,6 +280,7 @@ function drawToolbox(ev) {
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.fillStyle = 'black';
ctx.restore();
}

export {getToolboxFocusedData, drawToolbox};
42 changes: 29 additions & 13 deletions glue/crumble/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ const btnTimelineFocus = /** @type{!HTMLButtonElement} */ document.getElementByI
const btnClearTimelineFocus = /** @type{!HTMLButtonElement} */ document.getElementById('btnClearTimelineFocus');
const btnClearSelectedMarkers = /** @type{!HTMLButtonElement} */ document.getElementById('btnClearSelectedMarkers');
const btnShowExamples = /** @type {!HTMLButtonElement} */ document.getElementById('btnShowExamples');
const divExamples = /** @type{!HTMLDivElement} */ document.getElementById('examples-div');
const dialogExamples = /** @type{!HTMLDialogElement} */ document.getElementById('examples-dialog');
const btnDialogClose = /** @type{!HTMLDivElement} */ document.getElementById('examples-close-button');

// Prevent typing in the import/export text editor from causing changes in the main circuit editor.
txtStimCircuit.addEventListener('keyup', ev => ev.stopPropagation());
Expand All @@ -48,6 +49,12 @@ btnImport.addEventListener('click', _ev => {
editorState.commit(circuit);
});

function applyDevicePixelScaling() {
const devicePixelRatio = window.devicePixelRatio || 1;
editorState.canvas.width = editorState.canvas.scrollWidth * devicePixelRatio;
editorState.canvas.height = editorState.canvas.scrollHeight * devicePixelRatio;
}

btnImportExport.addEventListener('click', _ev => {
let div = /** @type{!HTMLDivElement} */ document.getElementById('divImportExport');
if (div.style.display === 'none') {
Expand All @@ -61,6 +68,8 @@ btnImportExport.addEventListener('click', _ev => {
}
setTimeout(() => {
window.scrollTo(0, 0);
applyDevicePixelScaling();
editorState.force_redraw();
}, 0);
});

Expand All @@ -83,12 +92,20 @@ btnClearSelectedMarkers.addEventListener('click', _ev => {
});

btnShowExamples.addEventListener('click', _ev => {
if (divExamples.style.display === 'none') {
divExamples.style.display = 'block';
btnShowExamples.textContent = "Hide Example Circuits";
if (dialogExamples.open) {
dialogExamples.close();
} else {
divExamples.style.display = 'none';
btnShowExamples.textContent = "Show Example Circuits";
dialogExamples.showModal();
}
});

btnDialogClose.addEventListener('click', _ev => {
dialogExamples.close();
});

dialogExamples.addEventListener('click', ev => {
if (ev.target === dialogExamples) {
dialogExamples.close();
}
});

Expand Down Expand Up @@ -127,8 +144,7 @@ btnPrevLayer.addEventListener('click', _ev => {
});

window.addEventListener('resize', _ev => {
editorState.canvas.width = editorState.canvas.scrollWidth;
editorState.canvas.height = editorState.canvas.scrollHeight;
applyDevicePixelScaling();
editorState.force_redraw();
});

Expand All @@ -148,7 +164,7 @@ editorState.canvas.addEventListener('mousemove', ev => {
editorState.curMouseY = ev.offsetY + OFFSET_Y;

// Scrubber.
let w = editorState.canvas.width / 2;
let w = editorState.canvas.scrollWidth / 2;
if (isInScrubber && ev.buttons === 1) {
editorState.changeCurLayerTo(Math.floor((ev.offsetX - w) / 8));
return;
Expand All @@ -165,7 +181,7 @@ editorState.canvas.addEventListener('mousedown', ev => {
editorState.mouseDownY = ev.offsetY + OFFSET_Y;

// Scrubber.
let w = editorState.canvas.width / 2;
let w = editorState.canvas.scrollWidth / 2;
isInScrubber = ev.offsetY < 20 && ev.offsetX > w && ev.buttons === 1;
if (isInScrubber) {
editorState.changeCurLayerTo(Math.floor((ev.offsetX - w) / 8));
Expand Down Expand Up @@ -195,7 +211,7 @@ function makeChordHandlers() {

res.set('shift+t', preview => editorState.rotate45(-1, preview));
res.set('t', preview => editorState.rotate45(+1, preview));
res.set('escape', () => editorState.clearFocus());
res.set('escape', () => {if (dialogExamples.open) dialogExamples.close(); else editorState.clearFocus()});
res.set('delete', preview => editorState.deleteAtFocus(preview));
res.set('backspace', preview => editorState.deleteAtFocus(preview));
res.set('ctrl+delete', preview => editorState.deleteCurLayer(preview));
Expand Down Expand Up @@ -497,8 +513,7 @@ function handleKeyboardEvent(ev) {
document.addEventListener('keydown', handleKeyboardEvent);
document.addEventListener('keyup', handleKeyboardEvent);

editorState.canvas.width = editorState.canvas.scrollWidth;
editorState.canvas.height = editorState.canvas.scrollHeight;
applyDevicePixelScaling();
editorState.rev.changes().subscribe(() => {
editorState.obs_val_draw_state.set(editorState.toSnapshot(undefined));
drawToolbox(editorState.chorder.toEvent(false));
Expand All @@ -522,6 +537,7 @@ for (let anchor of document.getElementById('examples-div').querySelectorAll('a')
let circuitText = anchor.href.split('#circuit=')[1];

editorState.rev.commit(circuitText);
dialogExamples.close();
return false;
};
}
Loading
Loading