[turbolizer] Display live ranges in portrait mode

Allow live ranges to be displayed beside the
instruction sequence in turbolizer.

Bug: v8:7327
Change-Id: Idec5130655ccc9365dd32ec6927d8615a3e5c570
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3585960
Commit-Queue: George Wort <george.wort@arm.com>
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80226}
This commit is contained in:
George Wort 2022-04-14 11:27:13 +01:00 committed by V8 LUCI CQ
parent 750b5f37fb
commit d67a14b2fc
6 changed files with 242 additions and 53 deletions

View File

@ -25,8 +25,10 @@ code is governed by a BSD-style license that can be found in the LICENSE file.
<div id="resizer-ranges" class="resizer" style="visibility:hidden;"></div> <div id="resizer-ranges" class="resizer" style="visibility:hidden;"></div>
<div id="ranges" class="content" style="visibility:hidden;"></div> <div id="ranges" class="content" style="visibility:hidden;"></div>
<div id="show-hide-ranges" class="show-hide-pane" style="visibility: hidden"> <div id="show-hide-ranges" class="show-hide-pane" style="visibility: hidden">
<input id="ranges-expand" type="image" title="show ranges" src="up-arrow.png" class="button-input invisible"> <input id="ranges-expand-vert" type="image" title="show ranges" src="up-arrow.png" class="button-input invisible">
<input id="ranges-shrink" type="image" title="hide ranges" src="down-arrow.png" class="button-input"> <input id="ranges-shrink-vert" type="image" title="hide ranges" src="down-arrow.png" class="button-input">
<input id="ranges-expand-hor" type="image" title="show ranges" src="left-arrow.png" class="button-input invisible">
<input id="ranges-shrink-hor" type="image" title="hide ranges" src="right-arrow.png" class="button-input invisible">
</div> </div>
</div> </div>
<div id="resizer-right" class="resizer"></div> <div id="resizer-right" class="resizer"></div>

View File

@ -15,8 +15,10 @@ export const DISASSEMBLY_PANE_ID = 'disassembly';
export const DISASSEMBLY_COLLAPSE_ID = 'disassembly-shrink'; export const DISASSEMBLY_COLLAPSE_ID = 'disassembly-shrink';
export const DISASSEMBLY_EXPAND_ID = 'disassembly-expand'; export const DISASSEMBLY_EXPAND_ID = 'disassembly-expand';
export const RANGES_PANE_ID = "ranges"; export const RANGES_PANE_ID = "ranges";
export const RANGES_COLLAPSE_ID = "ranges-shrink"; export const RANGES_COLLAPSE_VERT_ID = "ranges-shrink-vert";
export const RANGES_EXPAND_ID = "ranges-expand"; export const RANGES_EXPAND_VERT_ID = "ranges-expand-vert";
export const RANGES_COLLAPSE_HOR_ID = "ranges-shrink-hor";
export const RANGES_EXPAND_HOR_ID = "ranges-expand-hor";
export const UNICODE_BLOCK = '&#9611;'; export const UNICODE_BLOCK = '&#9611;';
export const PROF_COLS = [ export const PROF_COLS = [
{ perc: 0, col: { r: 255, g: 255, b: 255 } }, { perc: 0, col: { r: 255, g: 255, b: 255 } },

View File

@ -40,6 +40,7 @@ export class GraphMultiView extends View {
} }
hide() { hide() {
this.container.className = "";
this.hideCurrentPhase(); this.hideCurrentPhase();
super.hide(); super.hide();
} }

View File

@ -139,6 +139,75 @@ class CSSVariables {
} }
} }
class UserSettingsObject {
value: boolean;
resetFunction: (boolean) => void;
}
// Manages the user's setting options regarding how the grid is displayed.
class UserSettings {
static readonly SESSION_STORAGE_PREFIX = "ranges-setting-";
settings: Map<string, UserSettingsObject>;
constructor() {
this.settings = new Map<string, UserSettingsObject>();
}
addSetting(settingName: string, value: boolean, resetFunction: (boolean) => void) {
this.settings.set(settingName, {value, resetFunction});
}
getToggleElement(settingName: string, settingLabel: string) {
const toggleEl = createElement("label", "range-toggle-setting", settingLabel);
const toggleInput = createElement("input", "range-toggle-setting") as HTMLInputElement;
toggleInput.id = "range-toggle-" + settingName;
toggleInput.setAttribute("type", "checkbox");
toggleInput.oninput = () => {
toggleInput.disabled = true;
this.set(settingName, toggleInput.checked);
this.reset(settingName);
toggleInput.disabled = false;
};
toggleEl.insertBefore(toggleInput, toggleEl.firstChild);
return toggleEl;
}
reset(settingName: string) {
const settingObject = this.settings.get(settingName);
window.sessionStorage.setItem(UserSettings.SESSION_STORAGE_PREFIX + settingName,
settingObject.value.toString());
settingObject.resetFunction(settingObject.value);
}
get(settingName: string) {
return this.settings.get(settingName).value;
}
set(settingName: string, value: boolean) {
this.settings.get(settingName).value = value;
}
resetFromSessionStorage() {
this.settings.forEach((settingObject: UserSettingsObject,
settingName: string) => {
const storedString =
window.sessionStorage.getItem(UserSettings.SESSION_STORAGE_PREFIX + settingName);
if (storedString) {
const storedValue = storedString == "true" ? true : false;
this.set(settingName, storedValue);
if (storedValue) {
const toggle =
(document.getElementById("range-toggle-" + settingName) as HTMLInputElement);
if (!toggle.checked) {
toggle.checked = storedValue;
settingObject.resetFunction(storedValue);
}
}
}
});
}
}
// Store the required data from the blocks JSON. // Store the required data from the blocks JSON.
class BlocksData { class BlocksData {
blockBorders: Set<number>; blockBorders: Set<number>;
@ -185,13 +254,13 @@ class Divs {
yAxis: HTMLElement; yAxis: HTMLElement;
grid: HTMLElement; grid: HTMLElement;
constructor() { constructor(userSettings: UserSettings) {
this.container = document.getElementById("ranges"); this.container = document.getElementById("ranges");
this.resizerBar = document.getElementById("resizer-ranges"); this.resizerBar = document.getElementById("resizer-ranges");
this.snapper = document.getElementById("show-hide-ranges"); this.snapper = document.getElementById("show-hide-ranges");
this.content = document.createElement("div"); this.content = document.createElement("div");
this.content.appendChild(this.elementForTitle()); this.content.appendChild(this.elementForTitle(userSettings));
this.showOnLoad = document.createElement("div"); this.showOnLoad = document.createElement("div");
this.showOnLoad.style.visibility = "hidden"; this.showOnLoad.style.visibility = "hidden";
@ -209,7 +278,7 @@ class Divs {
this.registerHeaders.appendChild(this.registers); this.registerHeaders.appendChild(this.registers);
} }
elementForTitle() { elementForTitle(userSettings: UserSettings) {
const titleEl = createElement("div", "range-title-div"); const titleEl = createElement("div", "range-title-div");
const titleBar = createElement("div", "range-title"); const titleBar = createElement("div", "range-title");
titleBar.appendChild(createElement("div", "", "Live Ranges")); titleBar.appendChild(createElement("div", "", "Live Ranges"));
@ -220,6 +289,7 @@ class Divs {
+ "\nand j, the index of the interval within the LiveRange, to give i:j."; + "\nand j, the index of the interval within the LiveRange, to give i:j.";
titleEl.appendChild(titleBar); titleEl.appendChild(titleBar);
titleEl.appendChild(titleHelp); titleEl.appendChild(titleHelp);
titleEl.appendChild(userSettings.getToggleElement("landscapeMode", "Landscape Mode"));
return titleEl; return titleEl;
} }
} }
@ -862,6 +932,7 @@ export class RangeView {
isShown: boolean; isShown: boolean;
numPositions: number; numPositions: number;
cssVariables: CSSVariables; cssVariables: CSSVariables;
userSettings: UserSettings;
divs: Divs; divs: Divs;
rowConstructor: RowConstructor; rowConstructor: RowConstructor;
phaseChangeHandler: PhaseChangeHandler; phaseChangeHandler: PhaseChangeHandler;
@ -881,8 +952,11 @@ export class RangeView {
this.gridAccessor = new GridAccessor(this.sequenceView); this.gridAccessor = new GridAccessor(this.sequenceView);
this.intervalsAccessor = new IntervalElementsAccessor(this.sequenceView); this.intervalsAccessor = new IntervalElementsAccessor(this.sequenceView);
this.cssVariables = new CSSVariables(); this.cssVariables = new CSSVariables();
this.userSettings = new UserSettings();
// Indicates whether the RangeView is displayed beside or below the SequenceView.
this.userSettings.addSetting("landscapeMode", false, this.resetLandscapeMode.bind(this));
this.blocksData = new BlocksData(blocks); this.blocksData = new BlocksData(blocks);
this.divs = new Divs(); this.divs = new Divs(this.userSettings);
this.scrollHandler = new ScrollHandler(this.divs); this.scrollHandler = new ScrollHandler(this.divs);
this.numPositions = this.sequenceView.numInstructions * Constants.POSITIONS_PER_INSTRUCTION; this.numPositions = this.sequenceView.numInstructions * Constants.POSITIONS_PER_INSTRUCTION;
this.rowConstructor = new RowConstructor(this); this.rowConstructor = new RowConstructor(this);
@ -909,6 +983,7 @@ export class RangeView {
window.dispatchEvent(new Event('resize')); window.dispatchEvent(new Event('resize'));
setTimeout(() => { setTimeout(() => {
this.userSettings.resetFromSessionStorage();
this.scrollHandler.restoreScroll(); this.scrollHandler.restoreScroll();
this.scrollHandler.syncHidden(); this.scrollHandler.syncHidden();
this.divs.showOnLoad.style.visibility = "visible"; this.divs.showOnLoad.style.visibility = "visible";
@ -935,4 +1010,15 @@ export class RangeView {
onresize() { onresize() {
if (this.isShown) this.scrollHandler.syncHidden(); if (this.isShown) this.scrollHandler.syncHidden();
} }
resetLandscapeMode(isInLandscapeMode: boolean) {
// Used to communicate the setting to Resizer.
this.divs.container.dataset.landscapeMode = isInLandscapeMode.toString();
window.dispatchEvent(new Event('resize'));
// Required to adjust scrollbar spacing.
setTimeout(() => {
window.dispatchEvent(new Event('resize'));
}, 100);
}
} }

View File

@ -11,8 +11,12 @@ class Snapper {
sourceCollapse: HTMLElement; sourceCollapse: HTMLElement;
disassemblyExpand: HTMLElement; disassemblyExpand: HTMLElement;
disassemblyCollapse: HTMLElement; disassemblyCollapse: HTMLElement;
rangesExpand: HTMLElement;
rangesCollapse: HTMLElement; rangesShowHide: HTMLElement;
rangesExpandVert: HTMLElement;
rangesCollapseVert: HTMLElement;
rangesExpandHor: HTMLElement;
rangesCollapseHor: HTMLElement;
constructor(resizer: Resizer) { constructor(resizer: Resizer) {
this.resizer = resizer; this.resizer = resizer;
@ -20,8 +24,11 @@ class Snapper {
this.sourceCollapse = document.getElementById(C.SOURCE_COLLAPSE_ID); this.sourceCollapse = document.getElementById(C.SOURCE_COLLAPSE_ID);
this.disassemblyExpand = document.getElementById(C.DISASSEMBLY_EXPAND_ID); this.disassemblyExpand = document.getElementById(C.DISASSEMBLY_EXPAND_ID);
this.disassemblyCollapse = document.getElementById(C.DISASSEMBLY_COLLAPSE_ID); this.disassemblyCollapse = document.getElementById(C.DISASSEMBLY_COLLAPSE_ID);
this.rangesExpand = document.getElementById(C.RANGES_EXPAND_ID); this.rangesShowHide = document.getElementById("show-hide-ranges");
this.rangesCollapse = document.getElementById(C.RANGES_COLLAPSE_ID); this.rangesExpandVert = document.getElementById(C.RANGES_EXPAND_VERT_ID);
this.rangesCollapseVert = document.getElementById(C.RANGES_COLLAPSE_VERT_ID);
this.rangesExpandHor = document.getElementById(C.RANGES_EXPAND_HOR_ID);
this.rangesCollapseHor = document.getElementById(C.RANGES_COLLAPSE_HOR_ID);
document.getElementById("show-hide-source").addEventListener("click", () => { document.getElementById("show-hide-source").addEventListener("click", () => {
this.resizer.resizerLeft.classed("snapped", !this.resizer.resizerLeft.classed("snapped")); this.resizer.resizerLeft.classed("snapped", !this.resizer.resizerLeft.classed("snapped"));
@ -33,9 +40,10 @@ class Snapper {
this.setDisassemblyExpanded(!this.disassemblyExpand.classList.contains("invisible")); this.setDisassemblyExpanded(!this.disassemblyExpand.classList.contains("invisible"));
this.resizer.updatePanes(); this.resizer.updatePanes();
}); });
document.getElementById("show-hide-ranges").addEventListener("click", () => { this.rangesShowHide.dataset.expanded = "1";
this.rangesShowHide.addEventListener("click", () => {
this.resizer.resizerRanges.classed("snapped", !this.resizer.resizerRanges.classed("snapped")); this.resizer.resizerRanges.classed("snapped", !this.resizer.resizerRanges.classed("snapped"));
this.setRangesExpanded(!this.rangesExpand.classList.contains("invisible")); this.setRangesExpanded(this.rangesShowHide.dataset.expanded != "1");
this.resizer.updatePanes(); this.resizer.updatePanes();
}); });
} }
@ -59,7 +67,6 @@ class Snapper {
window.sessionStorage.setItem("expandedState-source", `${isSourceExpanded}`); window.sessionStorage.setItem("expandedState-source", `${isSourceExpanded}`);
this.sourceExpand.classList.toggle("invisible", isSourceExpanded); this.sourceExpand.classList.toggle("invisible", isSourceExpanded);
this.sourceCollapse.classList.toggle("invisible", !isSourceExpanded); this.sourceCollapse.classList.toggle("invisible", !isSourceExpanded);
document.getElementById("show-hide-ranges").style.marginLeft = isSourceExpanded ? null : "40px";
} }
setSourceExpanded(isSourceExpanded: boolean): void { setSourceExpanded(isSourceExpanded: boolean): void {
@ -76,12 +83,35 @@ class Snapper {
setDisassemblyExpanded(isDisassemblyExpanded: boolean): void { setDisassemblyExpanded(isDisassemblyExpanded: boolean): void {
this.disassemblyUpdate(isDisassemblyExpanded); this.disassemblyUpdate(isDisassemblyExpanded);
this.resizer.updateRightWidth(); this.resizer.updateRightWidth();
this.resizer.updateRanges();
} }
rangesUpdate(isRangesExpanded: boolean): void { rangesUpdate(isRangesExpanded: boolean): void {
window.sessionStorage.setItem("expandedState-ranges", `${isRangesExpanded}`); window.sessionStorage.setItem("expandedState-ranges", `${isRangesExpanded}`);
this.rangesExpand.classList.toggle("invisible", isRangesExpanded); this.rangesShowHide.dataset.expanded = isRangesExpanded ? "1" : "0";
this.rangesCollapse.classList.toggle("invisible", !isRangesExpanded); const landscapeMode = this.resizer.isRangesInLandscapeMode();
this.rangesExpandVert.classList.toggle("invisible", !landscapeMode || isRangesExpanded);
this.rangesCollapseVert.classList.toggle("invisible", !landscapeMode || !isRangesExpanded);
this.rangesExpandHor.classList.toggle("invisible", landscapeMode || isRangesExpanded);
this.rangesCollapseHor.classList.toggle("invisible", landscapeMode || !isRangesExpanded);
let left: number;
if (landscapeMode) {
left = this.resizer.sepLeft + this.resizer.RESIZER_SIZE;
} else {
left = isRangesExpanded ? this.resizer.sepRangesX + this.resizer.RESIZER_SIZE
: (this.resizer.sepRangesX - this.rangesShowHide.clientWidth
- (2 * this.resizer.RESIZER_SIZE));
}
const marginLeft = parseInt(window.getComputedStyle(this.rangesShowHide, null)
.getPropertyValue('margin-left').slice(0, -2), 10);
const marginRight = parseInt(window.getComputedStyle(this.rangesShowHide, null)
.getPropertyValue('margin-right').slice(0, -2), 10);
const width = this.rangesShowHide.clientWidth + marginLeft + marginRight;
// The left value is bounded on both sides by another show/hide button of the same width. The
// max value must also account for its own width. marginRight is subtracted from both sides to
// reduce the separation between buttons.
const maxLeft = document.body.getBoundingClientRect().width - (2 * width) + marginRight;
this.rangesShowHide.style.left = Math.max(width - marginRight, Math.min(left, maxLeft)) + "px";
} }
setRangesExpanded(isRangesExpanded: boolean): void { setRangesExpanded(isRangesExpanded: boolean): void {
@ -100,7 +130,9 @@ export class Resizer {
middle: HTMLElement; middle: HTMLElement;
sepLeft: number; sepLeft: number;
sepRight: number; sepRight: number;
sepRangesX: number;
sepRangesHeight: number; sepRangesHeight: number;
rangesInLandscapeMode: boolean;
panesUpdatedCallback: () => void; panesUpdatedCallback: () => void;
resizerRight: d3.Selection<HTMLDivElement, any, any, any>; resizerRight: d3.Selection<HTMLDivElement, any, any, any>;
resizerLeft: d3.Selection<HTMLDivElement, any, any, any>; resizerLeft: d3.Selection<HTMLDivElement, any, any, any>;
@ -109,8 +141,9 @@ export class Resizer {
private readonly SOURCE_PANE_DEFAULT_PERCENT = 1 / 4; private readonly SOURCE_PANE_DEFAULT_PERCENT = 1 / 4;
private readonly DISASSEMBLY_PANE_DEFAULT_PERCENT = 3 / 4; private readonly DISASSEMBLY_PANE_DEFAULT_PERCENT = 3 / 4;
private readonly RANGES_PANE_HEIGHT_DEFAULT_PERCENT = 3 / 4; private readonly RANGES_PANE_HEIGHT_DEFAULT_PERCENT = 3 / 4;
private readonly RANGES_PANE_WIDTH_DEFAULT_PERCENT = 1 / 2;
private readonly RESIZER_RANGES_HEIGHT_BUFFER_PERCENTAGE = 5; private readonly RESIZER_RANGES_HEIGHT_BUFFER_PERCENTAGE = 5;
private readonly RESIZER_SIZE = document.getElementById("resizer-ranges").offsetHeight; readonly RESIZER_SIZE = document.getElementById("resizer-ranges").offsetHeight;
constructor(panesUpdatedCallback: () => void, deadWidth: number, deadHeight: number) { constructor(panesUpdatedCallback: () => void, deadWidth: number, deadHeight: number) {
const resizer = this; const resizer = this;
@ -134,22 +167,29 @@ export class Resizer {
if (window.sessionStorage.getItem("ranges-pane-height-percent") === null) { if (window.sessionStorage.getItem("ranges-pane-height-percent") === null) {
window.sessionStorage.setItem("ranges-pane-height-percent", `${this.RANGES_PANE_HEIGHT_DEFAULT_PERCENT}`); window.sessionStorage.setItem("ranges-pane-height-percent", `${this.RANGES_PANE_HEIGHT_DEFAULT_PERCENT}`);
} }
if (window.sessionStorage.getItem("ranges-pane-width-percent") === null) {
window.sessionStorage.setItem("ranges-pane-width-percent", `${this.RANGES_PANE_WIDTH_DEFAULT_PERCENT}`);
}
this.updateSizes(); this.updateSizes();
const dragResizeLeft = d3.drag() const dragResizeLeft = d3.drag()
.on('drag', function () { .on('drag', function () {
const x = d3.mouse(this.parentElement)[0]; const x = d3.mouse(document.body)[0];
resizer.sepLeft = Math.min(Math.max(0, x), resizer.sepRight); resizer.sepLeft = Math.min(Math.max(0, x), resizer.sepRight);
if (resizer.sepLeft > resizer.sepRangesX) {
resizer.sepRangesX = resizer.sepLeft;
}
resizer.updatePanes(); resizer.updatePanes();
}) })
.on('start', function () { .on('start', function () {
resizer.rangesInLandscapeMode = resizer.isRangesInLandscapeMode();
resizer.resizerLeft.classed("dragged", true); resizer.resizerLeft.classed("dragged", true);
}) })
.on('end', function () { .on('end', function () {
// If the panel is close enough to the left, treat it as if it was pulled all the way to the lefg. // If the panel is close enough to the left, treat it as if it was pulled all the way to the left.
const x = d3.mouse(this.parentElement)[0]; const coords = d3.mouse(document.body);
if (x <= deadWidth) { if (coords[0] <= deadWidth) {
resizer.sepLeft = 0; resizer.sepLeft = 0;
resizer.updatePanes(); resizer.updatePanes();
} }
@ -160,23 +200,30 @@ export class Resizer {
} }
resizer.snapper.setSourceExpanded(!resizer.isLeftSnapped()); resizer.snapper.setSourceExpanded(!resizer.isLeftSnapped());
resizer.resizerLeft.classed("dragged", false); resizer.resizerLeft.classed("dragged", false);
if (!resizer.rangesInLandscapeMode) {
resizer.dragRangesEnd(coords, resizer.sepRangesX >= resizer.sepRight - deadWidth);
}
}); });
resizer.resizerLeft.call(dragResizeLeft); resizer.resizerLeft.call(dragResizeLeft);
const dragResizeRight = d3.drag() const dragResizeRight = d3.drag()
.on('drag', function () { .on('drag', function () {
const x = d3.mouse(this.parentElement)[0]; const x = d3.mouse(document.body)[0];
resizer.sepRight = Math.max(resizer.sepLeft, Math.min(x, document.body.getBoundingClientRect().width)); resizer.sepRight = Math.max(resizer.sepLeft, Math.min(x, document.body.getBoundingClientRect().width));
if (resizer.sepRight < resizer.sepRangesX || resizer.isRangesSnapped()) {
resizer.sepRangesX = resizer.sepRight;
}
resizer.updatePanes(); resizer.updatePanes();
}) })
.on('start', function () { .on('start', function () {
resizer.rangesInLandscapeMode = resizer.isRangesInLandscapeMode();
resizer.resizerRight.classed("dragged", true); resizer.resizerRight.classed("dragged", true);
}) })
.on('end', function () { .on('end', function () {
// If the panel is close enough to the right, treat it as if it was pulled all the way to the right. // If the panel is close enough to the right, treat it as if it was pulled all the way to the right.
const x = d3.mouse(this.parentElement)[0]; const coords = d3.mouse(document.body);
const clientWidth = document.body.getBoundingClientRect().width; const clientWidth = document.body.getBoundingClientRect().width;
if (x >= (clientWidth - deadWidth)) { if (coords[0] >= (clientWidth - deadWidth)) {
resizer.sepRight = clientWidth - 1; resizer.sepRight = clientWidth - 1;
resizer.updatePanes(); resizer.updatePanes();
} }
@ -187,32 +234,28 @@ export class Resizer {
} }
resizer.snapper.setDisassemblyExpanded(!resizer.isRightSnapped()); resizer.snapper.setDisassemblyExpanded(!resizer.isRightSnapped());
resizer.resizerRight.classed("dragged", false); resizer.resizerRight.classed("dragged", false);
if (!resizer.rangesInLandscapeMode) {
resizer.dragRangesEnd(coords, resizer.sepRangesX >= resizer.sepRight - deadWidth);
}
}); });
resizer.resizerRight.call(dragResizeRight); resizer.resizerRight.call(dragResizeRight);
const dragResizeRanges = d3.drag() const dragResizeRanges = d3.drag()
.on('drag', function () { .on('drag', function () {
const y = d3.mouse(this.parentElement)[1]; const coords = d3.mouse(document.body);
resizer.sepRangesHeight = Math.max(100, Math.min(y, window.innerHeight) - resizer.RESIZER_RANGES_HEIGHT_BUFFER_PERCENTAGE); resizer.sepRangesX = Math.max(resizer.sepLeft, Math.min(coords[0], resizer.sepRight));
resizer.sepRangesHeight = Math.max(100, Math.min(coords[1], window.innerHeight)
- resizer.RESIZER_RANGES_HEIGHT_BUFFER_PERCENTAGE);
resizer.updatePanes(); resizer.updatePanes();
}) })
.on('start', function () { .on('start', function () {
resizer.rangesInLandscapeMode = resizer.isRangesInLandscapeMode();
resizer.resizerRanges.classed("dragged", true); resizer.resizerRanges.classed("dragged", true);
}) })
.on('end', function () { .on('end', function () {
// If the panel is close enough to the bottom, treat it as if it was pulled all the way to the bottom. const coords = d3.mouse(document.body);
const y = d3.mouse(this.parentElement)[1]; const isSnappedX = !resizer.rangesInLandscapeMode && (coords[0] >= (resizer.sepRight - deadWidth));
if (y >= (window.innerHeight - deadHeight)) { resizer.dragRangesEnd(coords, isSnappedX);
resizer.sepRangesHeight = window.innerHeight;
resizer.updatePanes();
}
// Snap if dragged all the way to the bottom.
resizer.resizerRanges.classed("snapped", resizer.sepRangesHeight >= window.innerHeight - 1);
if (!resizer.isRangesSnapped()) {
window.sessionStorage.setItem("ranges-pane-height-percent", `${resizer.sepRangesHeight / window.innerHeight}`);
}
resizer.snapper.setRangesExpanded(!resizer.isRangesSnapped());
resizer.resizerRanges.classed("dragged", false);
}); });
resizer.resizerRanges.call(dragResizeRanges); resizer.resizerRanges.call(dragResizeRanges);
@ -236,23 +279,66 @@ export class Resizer {
return this.resizerRanges.classed("snapped"); return this.resizerRanges.classed("snapped");
} }
isRangesInLandscapeMode() {
return this.ranges.dataset.landscapeMode == "true";
}
dragRangesEnd(coords: [number, number], isSnappedX: boolean) {
// If the panel is close enough to the bottom, treat it as if it was pulled all the way to the
// bottom.
const isSnappedY = this.rangesInLandscapeMode
&& (coords[1] >= (window.innerHeight - this.deadHeight));
if (isSnappedX || isSnappedY) {
if (isSnappedX) {
this.sepRangesX = this.sepRight;
}
if (isSnappedY) {
this.sepRangesHeight = window.innerHeight;
}
this.updatePanes();
}
// Snap if dragged all the way to the bottom.
this.resizerRanges.classed("snapped", (!this.rangesInLandscapeMode && (this.sepRangesX >= this.sepRight - 1))
|| (this.rangesInLandscapeMode
&& (this.sepRangesHeight >= window.innerHeight - 1)));
if (!this.isRangesSnapped()) {
if (this.rangesInLandscapeMode) {
window.sessionStorage.setItem("ranges-pane-height-percent",
`${this.sepRangesHeight / window.innerHeight}`);
} else {
window.sessionStorage.setItem("ranges-pane-width-percent",
`${(this.sepRangesX - this.sepLeft) / (this.sepRight - this.sepLeft)}`);
}
}
this.snapper.setRangesExpanded(!this.isRangesSnapped());
this.resizerRanges.classed("dragged", false);
}
updateRangesPane() { updateRangesPane() {
const clientHeight = window.innerHeight; const clientHeight = window.innerHeight;
const rangesIsHidden = this.ranges.style.visibility == "hidden"; const rangesIsHidden = this.ranges.style.visibility == "hidden";
let resizerSize = this.RESIZER_SIZE; const resizerSize = rangesIsHidden ? 0 : this.RESIZER_SIZE;
if (rangesIsHidden) { const sepRangesHeight = rangesIsHidden ? clientHeight : this.sepRangesHeight;
resizerSize = 0; const sepRangesX = rangesIsHidden ? this.sepRight : this.sepRangesX;
this.sepRangesHeight = clientHeight;
}
const rangeHeight = clientHeight - this.sepRangesHeight; this.snapper.rangesUpdate(this.snapper.rangesShowHide.dataset.expanded == "1");
const inLandscapeMode = this.isRangesInLandscapeMode();
const rangeHeight = inLandscapeMode ? clientHeight - sepRangesHeight : clientHeight;
this.ranges.style.height = rangeHeight + 'px'; this.ranges.style.height = rangeHeight + 'px';
const panelWidth = this.sepRight - this.sepLeft - (2 * resizerSize); const panelWidth = this.sepRight - this.sepLeft - (2 * resizerSize);
this.ranges.style.width = panelWidth + 'px'; const rangeWidth = inLandscapeMode ? panelWidth : this.sepRight - sepRangesX;
this.ranges.style.width = rangeWidth + 'px';
const multiview = document.getElementById("multiview"); const multiview = document.getElementById("multiview");
if (multiview && multiview.style) { if (multiview && multiview.style) {
multiview.style.height = (this.sepRangesHeight - resizerSize) + 'px'; multiview.style.height = (inLandscapeMode ? sepRangesHeight - resizerSize : clientHeight) + 'px';
multiview.style.width = panelWidth + 'px'; const midWidth = inLandscapeMode ? panelWidth : sepRangesX - this.sepLeft - (3 * resizerSize);
multiview.style.width = midWidth + 'px';
if (inLandscapeMode) {
this.middle.classList.remove("display-inline-flex");
} else {
this.middle.classList.add("display-inline-flex");
}
} }
// Resize the range grid and labels. // Resize the range grid and labels.
@ -261,12 +347,12 @@ export class Resizer {
const yAxis = (this.ranges.getElementsByClassName("range-y-axis")[0] as HTMLElement); const yAxis = (this.ranges.getElementsByClassName("range-y-axis")[0] as HTMLElement);
const rangeHeader = (this.ranges.getElementsByClassName("range-header")[0] as HTMLElement); const rangeHeader = (this.ranges.getElementsByClassName("range-header")[0] as HTMLElement);
const gridWidth = panelWidth - yAxis.clientWidth; const gridWidth = rangeWidth - yAxis.clientWidth;
rangeGrid.style.width = Math.floor(gridWidth - 1) + 'px'; rangeGrid.style.width = Math.floor(gridWidth - 1) + 'px';
// Take live ranges' right scrollbar into account. // Take live ranges' right scrollbar into account.
rangeHeader.style.width = (gridWidth - rangeGrid.offsetWidth + rangeGrid.clientWidth - 1) + 'px'; rangeHeader.style.width = (gridWidth - rangeGrid.offsetWidth + rangeGrid.clientWidth - 1) + 'px';
// Set resizer to horizontal. this.resizerRanges.style('width', inLandscapeMode ? rangeWidth + 'px' : resizerSize + 'px');
this.resizerRanges.style('width', panelWidth + 'px'); this.resizerRanges.style('height', inLandscapeMode ? resizerSize + 'px' : clientHeight + 'px');
const rangeTitle = (this.ranges.getElementsByClassName("range-title-div")[0] as HTMLElement); const rangeTitle = (this.ranges.getElementsByClassName("range-title-div")[0] as HTMLElement);
const rangeHeaderLabel = (this.ranges.getElementsByClassName("range-header-label-x")[0] as HTMLElement); const rangeHeaderLabel = (this.ranges.getElementsByClassName("range-header-label-x")[0] as HTMLElement);
@ -274,6 +360,9 @@ export class Resizer {
rangeGrid.style.height = gridHeight + 'px'; rangeGrid.style.height = gridHeight + 'px';
// Take live ranges' bottom scrollbar into account. // Take live ranges' bottom scrollbar into account.
yAxis.style.height = (gridHeight - rangeGrid.offsetHeight + rangeGrid.clientHeight) + 'px'; yAxis.style.height = (gridHeight - rangeGrid.offsetHeight + rangeGrid.clientHeight) + 'px';
} else {
this.resizerRanges.style('width', '0px');
this.resizerRanges.style('height', '0px');
} }
this.resizerRanges.style('ranges', this.ranges.style.height); this.resizerRanges.style('ranges', this.ranges.style.height);
} }
@ -290,9 +379,12 @@ export class Resizer {
updateRanges() { updateRanges() {
if (this.isRangesSnapped()) { if (this.isRangesSnapped()) {
this.sepRangesHeight = window.innerHeight; this.sepRangesHeight = window.innerHeight;
this.sepRangesX = this.sepRight;
} else { } else {
const sepRangesHeight = window.sessionStorage.getItem("ranges-pane-height-percent"); const sepRangesHeight = window.sessionStorage.getItem("ranges-pane-height-percent");
this.sepRangesHeight = window.innerHeight * Number.parseFloat(sepRangesHeight); this.sepRangesHeight = window.innerHeight * Number.parseFloat(sepRangesHeight);
const sepRangesWidth = window.sessionStorage.getItem("ranges-pane-width-percent");
this.sepRangesX = this.sepLeft + ((this.sepRight - this.sepLeft) * Number.parseFloat(sepRangesWidth));
} }
} }

View File

@ -46,7 +46,13 @@
display: inline-block; display: inline-block;
} }
input.range-toggle-show { label.range-toggle-setting {
text-align: right;
float: right;
}
input.range-toggle-show,
input.range-toggle-setting {
vertical-align: middle; vertical-align: middle;
} }