Skip to content

Commit

Permalink
feat: Minimap responsive sizing (#1850)
Browse files Browse the repository at this point in the history
* added sizing feature and api function

* added dispose

* feedback updates

* feeback update: refactoring resize listener
  • Loading branch information
cesarades authored Aug 10, 2023
1 parent 8b5b549 commit c463a32
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export class FocusRegion {
dispose() {
if (this.onChangeWrapper) {
this.primaryWorkspace.removeChangeListener(this.onChangeWrapper);
this.onChangeWrapper = null;
}
if (this.svgGroup) {
Blockly.utils.dom.removeNode(this.svgGroup);
Expand Down Expand Up @@ -175,6 +176,7 @@ export class FocusRegion {
this.rect.setAttribute('height', height.toString());
}


/**
* Returns whether focus region is initialized or not.
* @returns True if focus region is initialized else false.
Expand Down
69 changes: 58 additions & 11 deletions plugins/workspace-minimap/src/minimap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
*/

import * as Blockly from 'blockly/core';
import {FocusRegion} from './focus_mode';
import {FocusRegion} from './focus_region';

// Events that should be send over to the minimap from the primary workspace
const BlockEvents = new Set([
const blockEvents = new Set([
Blockly.Events.BLOCK_CHANGE,
Blockly.Events.BLOCK_CREATE,
Blockly.Events.BLOCK_DELETE,
Expand All @@ -31,7 +31,12 @@ export class Minimap {
protected primaryWorkspace: Blockly.WorkspaceSvg;
protected minimapWorkspace: Blockly.WorkspaceSvg;
protected focusRegion: FocusRegion;
private onMouseMoveWrapper: Blockly.browserEvents.Data;
protected onMouseMoveWrapper: Blockly.browserEvents.Data;
protected onMouseDownWrapper: Blockly.browserEvents.Data;
protected onMouseUpWrapper: Blockly.browserEvents.Data;
protected minimapWrapper: HTMLDivElement;


/**
* Constructor for a minimap.
* @param workspace The workspace to mirror.
Expand All @@ -40,22 +45,23 @@ export class Minimap {
this.primaryWorkspace = workspace;
}


/**
* Initialize.
*/
init(): void {
// Create a wrapper div for the minimap injection.
const minimapWrapper = document.createElement('div');
minimapWrapper.id = 'minimapWrapper_' + this.primaryWorkspace.id;
minimapWrapper.className = 'minimapWrapper';
this.minimapWrapper = document.createElement('div');
this.minimapWrapper.id = 'minimapWrapper' + this.primaryWorkspace.id;
this.minimapWrapper.className = 'minimapWrapper';

// Make the wrapper a sibling to the primary injection div.
const primaryInjectParentDiv =
this.primaryWorkspace.getInjectionDiv().parentNode;
primaryInjectParentDiv.appendChild(minimapWrapper);
primaryInjectParentDiv.appendChild(this.minimapWrapper);

// Inject the minimap workspace.
this.minimapWorkspace = Blockly.inject(minimapWrapper.id,
this.minimapWorkspace = Blockly.inject(this.minimapWrapper.id,
{
// Inherit the layout of the primary workspace.
rtl: this.primaryWorkspace.RTL,
Expand All @@ -77,13 +83,16 @@ export class Minimap {

this.minimapWorkspace.scrollbar.setContainerVisible(false);
this.primaryWorkspace.addChangeListener((e) => void this.mirror(e));
window.addEventListener('resize', () => {
this.minimapWorkspace.zoomToFit();
});

// The mouseup binds to the parent container div instead of the minimap
// because if a drag begins on the minimap and ends outside of it the
// mousemove should still unbind.
Blockly.browserEvents.bind(
this.onMouseDownWrapper = Blockly.browserEvents.bind(
this.minimapWorkspace.svgGroup_, 'mousedown', this, this.onClickDown);
Blockly.browserEvents.bind(
this.onMouseUpWrapper = Blockly.browserEvents.bind(
primaryInjectParentDiv, 'mouseup', this, this.onClickUp);

// Initializes the focus region.
Expand All @@ -92,6 +101,28 @@ export class Minimap {
this.enableFocusRegion();
}

/**
* Disposes the minimap.
* Unlinks from all DOM elements and remove all event listeners
* to prevent memory leaks.
*/
dispose() {
if (this.isFocusEnabled()) {
this.disableFocusRegion();
}
this.minimapWorkspace.dispose();
Blockly.utils.dom.removeNode(this.minimapWrapper);
if (this.onMouseMoveWrapper) {
Blockly.browserEvents.unbind(this.onMouseMoveWrapper);
}
if (this.onMouseDownWrapper) {
Blockly.browserEvents.unbind(this.onMouseDownWrapper);
}
if (this.onMouseUpWrapper) {
Blockly.browserEvents.unbind(this.onMouseUpWrapper);
}
}


/**
* Creates the mirroring between workspaces. Passes on all desired events
Expand All @@ -101,7 +132,7 @@ export class Minimap {
private mirror(event: Blockly.Events.Abstract): void {
// TODO: shadow blocks get mirrored too (not supposed to happen)

if (!BlockEvents.has(event.type)) {
if (!blockEvents.has(event.type)) {
return; // Filter out events.
}
// Run the event in the minimap.
Expand All @@ -116,6 +147,7 @@ export class Minimap {
});
}


/**
* Converts the coorindates from a mouse event on the minimap
* into scroll coordinates for the primary viewport.
Expand Down Expand Up @@ -151,6 +183,7 @@ export class Minimap {
return [x, y];
}


/**
* Scrolls the primary workspace viewport based on a minimap event.
* @param event The minimap browser event.
Expand All @@ -164,6 +197,7 @@ export class Minimap {
this.primaryWorkspace.scroll(x, y);
}


/**
* Updates the primary workspace viewport based on a click in the minimap.
* @param event The minimap browser event.
Expand All @@ -174,6 +208,7 @@ export class Minimap {
this.primaryScroll(event);
}


/**
* Unbinds the minimap mousemove when the mouse is not clicked.
*/
Expand All @@ -183,6 +218,7 @@ export class Minimap {
}
}


/**
* Updates the primary workspace viewport based on a drag in the minimap.
* @param event The minimap browser event.
Expand All @@ -191,17 +227,28 @@ export class Minimap {
this.primaryScroll(event);
}


/**
* Enables the focus region; A highlight of the viewport in the minimap.
*/
enableFocusRegion(): void {
this.focusRegion.init();
}


/**
* Disables the focus region.
*/
disableFocusRegion(): void {
this.focusRegion.dispose();
}


/**
* Returns whether the focus region is enabled.
* @returns True if the focus region is enabled.
*/
isFocusEnabled(): boolean {
return this.focusRegion.isEnabled();
}
}
21 changes: 20 additions & 1 deletion plugins/workspace-minimap/src/positioned_minimap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import * as Blockly from 'blockly/core';
import {Minimap} from './minimap';

const minWidth = 200;

/**
* A positionable version of minimap that implements IPositionable.
*/
Expand All @@ -23,6 +25,7 @@ export class PositionedMinimap extends Minimap implements Blockly.IPositionable
protected height: number;
id: string;


/**
* Constructor for a positionable minimap.
* @param workspace The workspace to mirror.
Expand All @@ -33,10 +36,11 @@ export class PositionedMinimap extends Minimap implements Blockly.IPositionable
this.margin = 20;
this.top = 0;
this.left = 0;
this.width = 225; // TODO: Bumping size responsiveness to future branch.
this.width = 225;
this.height = 150;
}


/**
* Initialize.
*/
Expand All @@ -50,6 +54,7 @@ export class PositionedMinimap extends Minimap implements Blockly.IPositionable
this.primaryWorkspace.resize();
}


/**
* Returns the bounding rectangle of the UI element in pixel units
* relative to the Blockly injection div.
Expand All @@ -61,13 +66,16 @@ export class PositionedMinimap extends Minimap implements Blockly.IPositionable
this.left, this.left + this.width);
}


/**
* Positions the minimap.
* @param metrics The workspace metrics.
* @param savedPositions List of rectangles already on the workspace.
*/
position(metrics: Blockly.MetricsManager.UiMetrics,
savedPositions: Blockly.utils.Rect[]): void {
this.resize();

// Aliases.
const workspace = this.primaryWorkspace;
const scrollbars = workspace.scrollbar;
Expand Down Expand Up @@ -127,6 +135,17 @@ export class PositionedMinimap extends Minimap implements Blockly.IPositionable
this.setMinimapCss();
}


/**
* Sizes the minimap.
*/
resize(): void {
const viewWidth = this.primaryWorkspace.getMetrics().viewWidth;
this.width = Math.max(minWidth, viewWidth / 5);
this.height = this.width * 2 / 3;
}


/**
* Updates the CSS attribute for the minimap.
*/
Expand Down

0 comments on commit c463a32

Please sign in to comment.