Select Git revision
ElasticMinimap.js
ElasticMinimap.js 4.43 KiB
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Rnd } from 'react-rnd';
import ns from '../config/css-ns';
import { getWorkspaceBoundingBox } from '../state/selectors';
const minimapContainer = {
width: 200,
height: 200,
innerPadding: 10,
};
// There is a minimum bounding box based on the viewport dimensions,
// and the bounding box is always square
/**
* ElasticMinimap
*/
const scaledViewport = (workspaceViewport, boundingBox) => {
const viewportAspectRatio = workspaceViewport.width / workspaceViewport.height;
const viewportScaleFactor = workspaceViewport.width / boundingBox.width;
const scaledViewportWidth = viewportScaleFactor * minimapContainer.width;
const scaledViewportHeight = scaledViewportWidth / viewportAspectRatio;
const scaledViewportX = (-workspaceViewport.x / boundingBox.width) * minimapContainer.width;
const scaledViewportY = (-workspaceViewport.y / boundingBox.height) * minimapContainer.height;
return {
x: scaledViewportX,
y: scaledViewportY,
width: scaledViewportWidth,
height: scaledViewportHeight,
};
};
/**
* ElasticMinimap
*/
const minimapToWorkspaceCoordinates = (x, y, boundingBox) => {
const newX = -x * boundingBox.width / minimapContainer.width;
const newY = -y * boundingBox.height / minimapContainer.height;
return {
x: newX,
y: newY,
};
};
/**
* ElasticMinimap
*/
const windowStyle = (window, boundingBox) => {
const windowAspectRatio = window.width / window.height;
const windowScaleFactor = window.width / boundingBox.width;
const scaledWindowWidth = windowScaleFactor * 100;
const scaledWindowX = (window.x / boundingBox.width) * 100;
const scaledWindowY = (window.y / boundingBox.height) * 100;
const scaledWindowHeight = scaledWindowWidth / windowAspectRatio;
return {
top: `${scaledWindowY}%`,
left: `${scaledWindowX}%`,
height: `${scaledWindowHeight}%`,
width: `${scaledWindowWidth}%`,
};
};
/**
* ElasticMinimap
*/
const boundingBoxStyle = (windows, boundingBox) => {
const windowBoundingBox = getWorkspaceBoundingBox(windows);
const windowBBAspectRatio = windowBoundingBox.width / windowBoundingBox.height;
const windowBBScaleFactor = windowBoundingBox.width / boundingBox.width;
const scaledWindowBBWidth = windowBBScaleFactor * 100;
const scaledWindowBBX = (windowBoundingBox.x / boundingBox.width) * 100;
const scaledWindowBBY = (windowBoundingBox.y / boundingBox.height) * 100;
const scaledWindowBBHeight = scaledWindowBBWidth / windowBBAspectRatio;
return {
top: `${scaledWindowBBY}%`,
left: `${scaledWindowBBX}%`,
height: `${scaledWindowBBHeight}%`,
width: `${scaledWindowBBWidth}%`,
};
};
/**
* ElasticMinimap
*/
export class ElasticMinimap extends Component {
/**
* render
* @return
*/
render() {
const boundingBox = {
width: 5000,
height: 5000,
};
const {
windows,
workspaceViewport,
setWorkspaceViewportPosition,
} = this.props;
const viewport = scaledViewport(
workspaceViewport,
boundingBox,
);
return (
<div className={ns('elastic-minimap')}>
{
Object.values(windows).map(window => (
<div
key={window.id}
className="minimap-window"
style={windowStyle(window, boundingBox)}
/>
))
}
<div
className="window-bounding-box"
style={boundingBoxStyle(windows, boundingBox)}
/>
<Rnd
position={{ x: viewport.x, y: viewport.y }}
size={{ width: viewport.width, height: viewport.height }}
enableResizing={{
top: false,
right: false,
bottom: false,
left: false,
topRight: false,
bottomRight: false,
bottomLeft: false,
topLeft: false,
}}
onDragStart={(e, d) => null}
onDrag={(e, d) => {
const newPosition = minimapToWorkspaceCoordinates(d.x, d.y, boundingBox);
setWorkspaceViewportPosition(newPosition.x, newPosition.y);
}}
className="minimap-viewport"
/>
</div>
);
}
}
ElasticMinimap.propTypes = {
windows: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
setWorkspaceViewportPosition: PropTypes.func.isRequired,
workspaceViewport: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};