859 lines
25 KiB
TypeScript
859 lines
25 KiB
TypeScript
import React, { useEffect, useState } from "react";
|
|
import Canvas from "ventilation/Canvas";
|
|
import Zoom from "ventilation/Zoom";
|
|
import { pond } from "protobuf-ts/pond";
|
|
import {
|
|
CircularProgress,
|
|
ListItemIcon,
|
|
ListItemText,
|
|
Menu,
|
|
MenuItem,
|
|
ToggleButton,
|
|
Typography,
|
|
useTheme
|
|
} from "@mui/material";
|
|
import { Info, AddCircle, InfoRounded } from "@mui/icons-material";
|
|
import { VentShaft } from "./drawable/VentShaft";
|
|
import { VentCorner } from "./drawable/VentCorner";
|
|
import { Placeable } from "./drawable/Placeable";
|
|
import VentDialog from "./VentDialog";
|
|
import DeleteIcon from "@mui/icons-material/DeleteForever";
|
|
import ClockwiseIcon from "@mui/icons-material/RotateRight";
|
|
import CounterclockwiseIcon from "@mui/icons-material/RotateLeft";
|
|
import { useGlobalState, useMineAPI } from "providers";
|
|
import { Component, Device } from "models";
|
|
import { Sensor } from "./drawable/Sensor";
|
|
import { VentTBreak } from "./drawable/VentTBreak";
|
|
import InteractionSettings from "interactions/InteractionSettings";
|
|
import { UnitMeasurement } from "models/UnitMeasurement";
|
|
|
|
interface Props {
|
|
width?: number;
|
|
height?: number;
|
|
mode?: Mode;
|
|
undoRef: any;
|
|
redoRef: any;
|
|
saveRef: any;
|
|
addBlockRef: any;
|
|
devices: pond.Device[];
|
|
blocks: Placeable[];
|
|
setBlocks: React.Dispatch<React.SetStateAction<Placeable[]>>;
|
|
components: Component[];
|
|
setComponents: React.Dispatch<React.SetStateAction<Component[]>>;
|
|
componentPreferences: Map<string, pond.MineComponentPreferences>;
|
|
setComponentPreferences: React.Dispatch<
|
|
React.SetStateAction<Map<string, pond.MineComponentPreferences>>
|
|
>;
|
|
componentDevices: Map<string, number>;
|
|
sensors: Sensor[];
|
|
setSensors: React.Dispatch<React.SetStateAction<Sensor[]>>;
|
|
loading: boolean;
|
|
}
|
|
|
|
enum Mode {
|
|
NORMAL,
|
|
MOVE,
|
|
ADD,
|
|
DELETE
|
|
}
|
|
|
|
enum ViewMode {
|
|
NORMAL,
|
|
INFO
|
|
}
|
|
|
|
export default function Editor(props: Props) {
|
|
const {
|
|
blocks,
|
|
setBlocks,
|
|
devices,
|
|
components,
|
|
componentDevices,
|
|
componentPreferences,
|
|
sensors,
|
|
setSensors,
|
|
setComponentPreferences,
|
|
loading
|
|
} = props;
|
|
const [selected, setSelected] = useState<Placeable[]>([]);
|
|
const [width, setWidth] = useState<number>(props.width ? props.width : 800);
|
|
const [height, setHeight] = useState<number>(props.width ? props.width : 600);
|
|
const [cameraOffsetX, setCameraOffsetX] = useState<number>(0);
|
|
const [cameraOffsetY, setCameraOffsetY] = useState<number>(0);
|
|
const [clickX, setClickX] = useState<number>(0);
|
|
const [clickY, setClickY] = useState<number>(0);
|
|
const [mode, setMode] = useState<Mode>(props.mode ? props.mode : Mode.NORMAL);
|
|
const [viewMode, setViewMode] = useState<ViewMode>(ViewMode.NORMAL);
|
|
const [mouseDown, setMouseDown] = useState<boolean>(false);
|
|
const [undoStates, setUndoStates] = useState<Placeable[][]>([]);
|
|
const [redoStates, setRedoStates] = useState<Placeable[][]>([]);
|
|
const [ctrl, setCtrl] = useState<boolean>(false);
|
|
const [moveOrigin, setMoveOrigin] = useState<Placeable[]>([]);
|
|
const [mousePosX, setMousePosX] = useState<number>(0);
|
|
const [mousePosY, setMousePosY] = useState<number>(0);
|
|
const [hoveredBlock, setHoveredBlock] = useState<number | undefined>(undefined);
|
|
const [placementBlock, setPlacementBlock] = useState<Placeable | undefined>(undefined);
|
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
|
const [anchorPosX, setAnchorPosX] = useState<number>(0);
|
|
const [anchorPosY, setAnchorPosY] = useState<number>(0);
|
|
const [ventType, setVentType] = useState<pond.ShaftType | undefined>(undefined);
|
|
//const [placeableType, setPlaceableType] = useState<pond.PlaceableType | undefined>(undefined);
|
|
const [direction, setDirection] = useState<number>(0);
|
|
const [scale, setScale] = useState(1);
|
|
const [interactionDevice, setInteractionDevice] = useState<Device>();
|
|
const [interactionComponent, setInteractionComponent] = useState<Component>();
|
|
const [interactionSensor, setInteractionSensor] = useState<Sensor>();
|
|
const [isAddInteractionOpen, setIsAddInteractionOpen] = useState(false);
|
|
const mineAPI = useMineAPI();
|
|
const theme = useTheme();
|
|
|
|
const [componentMeasurements, setComponentMeasurements] = useState<
|
|
undefined | Map<string, UnitMeasurement[]>
|
|
>(undefined);
|
|
|
|
const [{ user, as }] = useGlobalState();
|
|
|
|
const save = () => {
|
|
let settings = pond.MineSettings.create();
|
|
props.devices.forEach(device => {
|
|
if (device.settings) settings.devices.push(device.settings?.deviceId);
|
|
});
|
|
mineAPI.addMine(settings, as).then((resp: any) => {
|
|
console.log(resp);
|
|
});
|
|
};
|
|
|
|
useEffect(() => {
|
|
setWidth(props.width ? props.width : 800);
|
|
setHeight(props.height ? props.height : 600);
|
|
}, [props.width, props.height]);
|
|
|
|
useEffect(() => {
|
|
setMode(props.mode ? props.mode : Mode.NORMAL);
|
|
}, [props.mode]);
|
|
|
|
useEffect(() => {
|
|
if (selected.length > 0) {
|
|
selected[0].setDirection(direction);
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [direction]);
|
|
|
|
useEffect(() => {
|
|
let compMeasurements: Map<string, UnitMeasurement[]> = new Map();
|
|
components.forEach(comp => {
|
|
let measurements: UnitMeasurement[] = [];
|
|
comp.lastMeasurement.forEach(m => {
|
|
let um = UnitMeasurement.create(m, user);
|
|
measurements.push(um);
|
|
});
|
|
compMeasurements.set(comp.key(), measurements);
|
|
});
|
|
setComponentMeasurements(compMeasurements);
|
|
}, [components, user]);
|
|
|
|
useEffect(() => {
|
|
if (
|
|
componentMeasurements === undefined ||
|
|
componentPreferences.size < 1 ||
|
|
components.length < 1 ||
|
|
!user ||
|
|
componentDevices.size < 1 ||
|
|
componentMeasurements.size < 1
|
|
)
|
|
return;
|
|
let sensors: Sensor[] = [];
|
|
components.forEach(comp => {
|
|
if (componentPreferences.get(comp.key())) {
|
|
let p = componentPreferences.get(comp.key());
|
|
if (p?.sensors)
|
|
p?.sensors.forEach((s, i) => {
|
|
if (s.enabled) {
|
|
let id = componentDevices.get(comp.key());
|
|
let device = devices.find(dev => dev.settings?.deviceId === id);
|
|
let measurements = componentMeasurements.get(comp.key());
|
|
if (measurements !== undefined)
|
|
sensors.push(Sensor.create(comp, Device.create(device), s, measurements, i, user));
|
|
}
|
|
});
|
|
}
|
|
});
|
|
setSensors(sensors);
|
|
}, [
|
|
components,
|
|
componentPreferences,
|
|
setSensors,
|
|
user,
|
|
devices,
|
|
componentDevices,
|
|
componentMeasurements
|
|
]);
|
|
|
|
const getOffsetX = (e: any): number => {
|
|
if (e.offsetParent) {
|
|
return e.offsetLeft + getOffsetX(e.offsetParent);
|
|
}
|
|
return e.offsetLeft;
|
|
};
|
|
|
|
const getAbsoluteX = (e: any): number => {
|
|
return e.pageX - getOffsetX(e.currentTarget);
|
|
};
|
|
|
|
const getX = (e: any): number => {
|
|
let offset = getOffsetX(e.currentTarget);
|
|
offset = offset - cameraOffsetX * scale;
|
|
return (e.pageX - offset) / scale;
|
|
};
|
|
|
|
const getOffsetY = (e: any): number => {
|
|
if (e.offsetParent) {
|
|
return e.offsetTop + getOffsetY(e.offsetParent);
|
|
}
|
|
return e.offsetTop;
|
|
};
|
|
|
|
const getAbsoluteY = (e: any): number => {
|
|
return e.pageY - getOffsetY(e.currentTarget);
|
|
};
|
|
|
|
const getY = (e: any): number => {
|
|
let offset = getOffsetY(e.currentTarget);
|
|
offset = offset - cameraOffsetY * scale;
|
|
//offset = offset + mouseOffsetY;
|
|
return (e.pageY - offset) / scale;
|
|
};
|
|
|
|
const addPlaceable = (p: Placeable) => {
|
|
let r = blocks;
|
|
saveState();
|
|
if (selected.length > 0) {
|
|
let xy = selected[0].getEndXAndY();
|
|
p.y = xy.y;
|
|
p.x = xy.x;
|
|
p.setAngle(selected[0].getEndAngle(), selected[0].getEndAngle());
|
|
} else {
|
|
p.x = clickX;
|
|
p.y = clickY;
|
|
}
|
|
selected[0] = p;
|
|
r.push(p);
|
|
setBlocks([...r]);
|
|
};
|
|
|
|
useEffect(() => {
|
|
props.addBlockRef.current = addPlaceable;
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [selected, addPlaceable, blocks]);
|
|
|
|
const add = (x?: number, y?: number) => {
|
|
let r = blocks;
|
|
saveState();
|
|
let p = VentShaft.create();
|
|
if (x && y) {
|
|
let v = VentCorner.create(x, y, 32, 0);
|
|
setBlocks([...r]);
|
|
return v;
|
|
} else if (Boolean(anchorEl)) {
|
|
p.x = anchorPosX + cameraOffsetX;
|
|
p.y = anchorPosY + cameraOffsetY;
|
|
p.angle = 0;
|
|
} else {
|
|
p.x = p.x + cameraOffsetX;
|
|
p.y = p.y + cameraOffsetY;
|
|
}
|
|
r.push(p);
|
|
setBlocks([...r]);
|
|
//return p;
|
|
};
|
|
|
|
const saveState = () => {
|
|
let u = undoStates;
|
|
let newBlocks: Placeable[] = [];
|
|
blocks.forEach(block => {
|
|
let b = block.clone();
|
|
newBlocks.push(b);
|
|
});
|
|
u.push(newBlocks);
|
|
setRedoStates([]);
|
|
};
|
|
|
|
const click = (e: any) => {
|
|
if (hoveredBlock !== undefined) {
|
|
setMode(hoveredBlock);
|
|
setMouseDown(false);
|
|
return;
|
|
}
|
|
selected.forEach(s => {
|
|
s.selected = false;
|
|
});
|
|
let hit = false;
|
|
let r = blocks;
|
|
let x = getX(e);
|
|
let y = getY(e);
|
|
setClickX(x);
|
|
setClickY(y);
|
|
let newBlocks: Placeable[] = [];
|
|
if (mode === Mode.NORMAL) {
|
|
r.forEach(block => {
|
|
newBlocks.push(block.clone());
|
|
if (block.clickCheck(x, y, scale)) {
|
|
hit = true;
|
|
setSelected([block]);
|
|
}
|
|
});
|
|
sensors.forEach(sensor => {
|
|
if (sensor.clickCheck(x, y, scale)) {
|
|
hit = true;
|
|
setSelected([sensor]);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!hit) setSelected([]);
|
|
|
|
if (e.button === 2) return;
|
|
|
|
if (hit) setMoveOrigin(newBlocks);
|
|
|
|
if (mode === Mode.ADD) {
|
|
add();
|
|
} else if (mode === Mode.DELETE) {
|
|
deleteBlock(x, y, true);
|
|
}
|
|
setMouseDown(true);
|
|
};
|
|
|
|
const mouseUp = (_e: any) => {
|
|
setMouseDown(false);
|
|
if (mode === Mode.NORMAL && selected !== undefined) {
|
|
let state = [...moveOrigin];
|
|
let states = [...undoStates];
|
|
states.push(state);
|
|
setUndoStates([...states]);
|
|
setRedoStates([]);
|
|
selected.forEach(placeable => {
|
|
if (placeable.type === pond.PlaceableType.PLACEABLE_TYPE_SENSOR) {
|
|
let s = placeable as Sensor;
|
|
let prefs = componentPreferences.get(s.getComponent().key());
|
|
if (prefs?.sensors[s.index]) {
|
|
prefs.sensors[s.index].x = s.x;
|
|
prefs.sensors[s.index].y = s.y;
|
|
componentPreferences.set(s.getComponent().key(), prefs);
|
|
setComponentPreferences(new Map(componentPreferences));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
//setSelected(undefined);
|
|
};
|
|
|
|
const keyDown = (e: any) => {
|
|
if (e.key === "1") {
|
|
setMode(Mode.NORMAL);
|
|
} else if (e.key === "2") {
|
|
setMode(Mode.MOVE);
|
|
} else if (e.key === "3") {
|
|
setMode(Mode.ADD);
|
|
} else if (e.key === "4") {
|
|
setMode(Mode.DELETE);
|
|
} else if (e.key === "Control") {
|
|
setCtrl(true);
|
|
} else if (e.key === "z" && ctrl) {
|
|
undo();
|
|
} else if (e.key === "Z" && ctrl) {
|
|
redo();
|
|
} else if (e.key === "s" && ctrl) {
|
|
save();
|
|
} else if (e.key === "v") {
|
|
if (viewMode === ViewMode.NORMAL) {
|
|
setViewMode(ViewMode.INFO);
|
|
} else {
|
|
setViewMode(ViewMode.NORMAL);
|
|
}
|
|
}
|
|
};
|
|
|
|
const keyUp = (e: any) => {
|
|
if (e.key === "Control") {
|
|
setCtrl(false);
|
|
}
|
|
};
|
|
|
|
const deleteBlock = (x: number, y: number, save?: boolean) => {
|
|
if (save) saveState();
|
|
let b = [...blocks];
|
|
blocks.forEach((block, index) => {
|
|
if (block.clickCheck(x + cameraOffsetX, y + cameraOffsetY, scale)) {
|
|
b.splice(index, 1);
|
|
return;
|
|
}
|
|
});
|
|
setBlocks(b);
|
|
};
|
|
|
|
const drag = (e: any) => {
|
|
setHoveredBlock(undefined);
|
|
let x = getAbsoluteX(e);
|
|
let y = getAbsoluteY(e);
|
|
setMousePosX(x);
|
|
setMousePosY(y);
|
|
|
|
if (!mouseDown) {
|
|
// Set position for placement block
|
|
if (mode === Mode.ADD && placementBlock) {
|
|
let p = placementBlock.clone() as Placeable;
|
|
p.x = x; // - p.width() / 2;
|
|
p.y = y; // - p.height() / 2;
|
|
setPlacementBlock(p);
|
|
}
|
|
} else {
|
|
// If the mouse is clicked down
|
|
if (mode === Mode.MOVE) {
|
|
setCameraOffsetX(clickX - x / scale);
|
|
setCameraOffsetY(clickY - y / scale);
|
|
} else if (selected.length > 0 && mode === Mode.NORMAL) {
|
|
selected[0].drag(getX(e), getY(e), scale);
|
|
blocks.forEach(block => {
|
|
if (block.x !== selected[0].x && block.y !== selected[0].y) {
|
|
selected[0].snap(block, 16);
|
|
}
|
|
});
|
|
} else if (mode === Mode.DELETE) {
|
|
deleteBlock(x, y);
|
|
}
|
|
}
|
|
};
|
|
|
|
const redo = () => {
|
|
if (redoStates.length < 1) return;
|
|
let rects = redoStates.pop();
|
|
let undos = undoStates;
|
|
if (rects) {
|
|
undos.push(rects);
|
|
setUndoStates([...undos]);
|
|
setBlocks(rects);
|
|
}
|
|
};
|
|
|
|
const undo = () => {
|
|
let states = undoStates;
|
|
let redo = redoStates;
|
|
let rects = states.pop();
|
|
if (rects) {
|
|
redo.push([...rects]);
|
|
setRedoStates([...redo]);
|
|
setUndoStates([...states]);
|
|
setBlocks(rects);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
props.saveRef.current = save;
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [save]);
|
|
|
|
useEffect(() => {
|
|
props.undoRef.current = undo;
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [undo]);
|
|
|
|
useEffect(() => {
|
|
props.redoRef.current = redo;
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [redo]);
|
|
|
|
const wheel = (e: WheelEvent) => {
|
|
// Scroll down
|
|
if (e.deltaY > 0) {
|
|
let newScale = scale - 0.05;
|
|
if (newScale > 0) {
|
|
let mouseRatioX = mousePosX / width;
|
|
let mouseRatioY = mousePosY / height;
|
|
let newWidth = width / newScale;
|
|
let dx = (width - newWidth) * mouseRatioX;
|
|
let olddx = (width - width / scale) * mouseRatioX;
|
|
let newHeight = height / newScale;
|
|
let dy = (height - newHeight) * mouseRatioY;
|
|
let olddy = (height - height / scale) * mouseRatioY;
|
|
setScale(Math.round(newScale * 1000) / 1000);
|
|
setCameraOffsetX(cameraOffsetX - olddx + dx);
|
|
setCameraOffsetY(cameraOffsetY - olddy + dy);
|
|
}
|
|
}
|
|
// Scroll up
|
|
if (e.deltaY < 0) {
|
|
let mouseRatioX = mousePosX / width;
|
|
let mouseRatioY = mousePosY / height;
|
|
let newScale = scale + 0.05;
|
|
let newWidth = width / newScale;
|
|
let dx = (width - newWidth) * mouseRatioX;
|
|
let olddx = (width - width / scale) * mouseRatioX;
|
|
let newHeight = height / newScale;
|
|
let dy = (height - newHeight) * mouseRatioY;
|
|
let olddy = (height - height / scale) * mouseRatioY;
|
|
setScale(Math.round(newScale * 1000) / 1000);
|
|
setCameraOffsetX(cameraOffsetX - olddx + dx);
|
|
setCameraOffsetY(cameraOffsetY - olddy + dy);
|
|
}
|
|
// If the mouse is at the top, scroll mode selection
|
|
/*if (mousePosY < 100) {
|
|
// Scroll down
|
|
if (e.deltaY > 0) {
|
|
//if (mode === Mode.NORMAL) setMode(Mode.DELETE);
|
|
//else setMode(mode - 1);
|
|
|
|
console.log("scroll down")
|
|
let newScale = scale - 0.1
|
|
setScale(newScale)
|
|
|
|
}
|
|
// Scroll up
|
|
if (e.deltaY < 0) {
|
|
//if (mode === Mode.DELETE) setMode(Mode.NORMAL);
|
|
//else setMode(mode + 1);
|
|
|
|
console.log("scroll up")
|
|
let newScale = scale + 0.1
|
|
setScale(newScale)
|
|
|
|
}
|
|
}*/
|
|
};
|
|
|
|
const drawBlocks = (context: CanvasRenderingContext2D) => {
|
|
blocks.forEach(block => {
|
|
if (block.draw) block.draw(context, cameraOffsetX, cameraOffsetY, scale);
|
|
});
|
|
selected.forEach(block => {
|
|
block.highlight(context, cameraOffsetX, cameraOffsetY, scale);
|
|
});
|
|
};
|
|
|
|
const drawSensors = (context: CanvasRenderingContext2D) => {
|
|
/*components.forEach(comp => {
|
|
let x = or(componentPreferences.get(comp.key())?.x, 10)
|
|
let y = or(componentPreferences.get(comp.key())?.y, 10)
|
|
context.arc(x - cameraOffsetX, y - cameraOffsetY, 25, 2 * Math.PI, 0, false)
|
|
context.fill()
|
|
})*/
|
|
sensors.forEach(sensor => {
|
|
sensor.draw(context, cameraOffsetX, cameraOffsetY, scale);
|
|
if (viewMode === ViewMode.INFO)
|
|
sensor.highlight(context, cameraOffsetX, cameraOffsetY, scale);
|
|
});
|
|
};
|
|
|
|
const draw = (context: CanvasRenderingContext2D) => {
|
|
context.clearRect(0, 0, width, height);
|
|
context.fillStyle = "rgba(150, 150, 255, 150)";
|
|
context.strokeStyle = "rgba(247, 202, 24, 1)";
|
|
|
|
drawBlocks(context);
|
|
drawSensors(context);
|
|
|
|
// Draw placement block if in add mode
|
|
if (mode === Mode.ADD) {
|
|
context.globalAlpha = 0.3;
|
|
if (placementBlock) placementBlock.draw(context);
|
|
context.globalAlpha = 1;
|
|
}
|
|
|
|
// Draw garbage can if in delete mode
|
|
if (mode === Mode.DELETE) {
|
|
let i = new Image();
|
|
i.src = "https://img.icons8.com/material-outlined/48/000000/delete-forever.png";
|
|
context.globalAlpha = 1;
|
|
context.drawImage(i, mousePosX - 16, mousePosY - 16, 32, 32);
|
|
}
|
|
};
|
|
|
|
const contextMenu = (e: Event) => {
|
|
e.preventDefault();
|
|
setAnchorPosX(getAbsoluteX(e));
|
|
setAnchorPosY(getAbsoluteY(e));
|
|
if (!anchorEl) setAnchorEl(e.currentTarget as any);
|
|
};
|
|
|
|
/*const isTBreak = (p: Placeable) => {
|
|
if (p.type === pond.PlaceableType.PLACEABLE_TYPE_SHAFT) {
|
|
if (p.subtype === pond.ShaftType.SHAFT_TYPE_T_BREAK) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};*/
|
|
|
|
const isDefaultShaft = (p: Placeable) => {
|
|
if (p.type === pond.PlaceableType.PLACEABLE_TYPE_SHAFT) {
|
|
if (p.subtype === pond.ShaftType.SHAFT_TYPE_DEFAULT) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
cursor:
|
|
mode === Mode.MOVE
|
|
? mouseDown
|
|
? "grabbing"
|
|
: "grab"
|
|
: mode === Mode.ADD || mode === Mode.DELETE
|
|
? "none"
|
|
: "default"
|
|
}}>
|
|
<div style={{ position: "relative" }}>
|
|
<div
|
|
style={{
|
|
borderRadius: 4,
|
|
backgroundColor: "rgba(255,255,255,0.1)",
|
|
position: "absolute",
|
|
bottom: 0,
|
|
right: 0,
|
|
margin: theme.spacing(2)
|
|
}}>
|
|
<Zoom scale={scale} setScale={setScale} />
|
|
</div>
|
|
{loading && (
|
|
<div
|
|
style={{
|
|
position: "absolute",
|
|
margin: theme.spacing(8)
|
|
}}>
|
|
<CircularProgress
|
|
size={theme.spacing(8)}
|
|
//style={{ margin: theme.spacing(6) }}
|
|
/>
|
|
<Typography>Loading...</Typography>
|
|
</div>
|
|
)}
|
|
<div
|
|
style={{
|
|
//borderRadius: 4,
|
|
//backgroundColor: "rgba(255,255,255,0.1)",
|
|
position: "absolute",
|
|
bottom: 0,
|
|
right: theme.spacing(19),
|
|
margin: theme.spacing(2)
|
|
}}>
|
|
<ToggleButton
|
|
value={viewMode}
|
|
selected={viewMode === ViewMode.INFO}
|
|
onChange={() => {
|
|
if (viewMode === ViewMode.INFO) {
|
|
setViewMode(ViewMode.NORMAL);
|
|
} else {
|
|
setViewMode(ViewMode.INFO);
|
|
}
|
|
}}>
|
|
<InfoRounded />
|
|
</ToggleButton>
|
|
</div>
|
|
<Canvas
|
|
draw={draw}
|
|
height={height}
|
|
width={width}
|
|
onMouseDown={click}
|
|
onMouseMove={drag}
|
|
onMouseUp={mouseUp}
|
|
onKeyDown={keyDown}
|
|
onKeyUp={keyUp}
|
|
onWheel={wheel}
|
|
onContextMenu={contextMenu}
|
|
/>
|
|
</div>
|
|
<VentDialog type={ventType} setType={setVentType} setDirection={setDirection} />
|
|
{interactionDevice && interactionComponent && (
|
|
<InteractionSettings
|
|
device={interactionDevice}
|
|
components={components}
|
|
initialComponent={interactionComponent}
|
|
mode="add"
|
|
isDialogOpen={isAddInteractionOpen}
|
|
closeDialogCallback={() => setIsAddInteractionOpen(false)}
|
|
refreshCallback={() => {}}
|
|
canEdit={true}
|
|
sensor={interactionSensor}
|
|
/>
|
|
)}
|
|
<Menu
|
|
id="groupMenu"
|
|
anchorEl={anchorEl}
|
|
open={Boolean(anchorEl)}
|
|
onClose={() => setAnchorEl(null)}
|
|
// getContentAnchorEl={null}
|
|
anchorOrigin={{ vertical: anchorPosY, horizontal: anchorPosX }}
|
|
keepMounted
|
|
onContextMenu={(e: any) => {
|
|
e.preventDefault();
|
|
setAnchorEl(null);
|
|
}}
|
|
disableAutoFocusItem>
|
|
{selected.length > 0 && selected[0].type === pond.PlaceableType.PLACEABLE_TYPE_SHAFT && (
|
|
<MenuItem
|
|
dense
|
|
divider
|
|
onClick={() => {
|
|
setAnchorEl(null);
|
|
setVentType(selected[0].subtype);
|
|
}}
|
|
>
|
|
<ListItemIcon>
|
|
<Info />
|
|
</ListItemIcon>
|
|
<ListItemText primary="Edit Shaft" />
|
|
</MenuItem>
|
|
)}
|
|
{selected.length > 0 && selected[0].type === pond.PlaceableType.PLACEABLE_TYPE_SENSOR && (
|
|
<MenuItem
|
|
dense
|
|
divider
|
|
onClick={() => {
|
|
let s = selected[0] as Sensor;
|
|
setAnchorEl(null);
|
|
//setVentType(selected[0].subtype);
|
|
setInteractionComponent(s.getComponent());
|
|
setInteractionDevice(s.getDevice());
|
|
setInteractionSensor(s);
|
|
setIsAddInteractionOpen(true);
|
|
}}
|
|
>
|
|
<ListItemIcon>
|
|
<AddCircle />
|
|
</ListItemIcon>
|
|
<ListItemText primary={"Add Interaction"} />
|
|
</MenuItem>
|
|
)}
|
|
{!(selected.length > 0 && isDefaultShaft(selected[0])) && (
|
|
<MenuItem
|
|
dense
|
|
onClick={() => {
|
|
setAnchorEl(null);
|
|
let v = VentShaft.create();
|
|
addPlaceable(v);
|
|
}}
|
|
>
|
|
<ListItemIcon>
|
|
<AddCircle />
|
|
</ListItemIcon>
|
|
<ListItemText primary="Add Straight Shaft" />
|
|
</MenuItem>
|
|
)}
|
|
<MenuItem
|
|
dense
|
|
onClick={() => {
|
|
setAnchorEl(null);
|
|
let v = VentCorner.create();
|
|
addPlaceable(v);
|
|
}}
|
|
>
|
|
<ListItemIcon>
|
|
<AddCircle />
|
|
</ListItemIcon>
|
|
<ListItemText primary="Add Corner" />
|
|
</MenuItem>
|
|
<MenuItem
|
|
dense
|
|
onClick={() => {
|
|
let v = VentTBreak.create();
|
|
addPlaceable(v);
|
|
setAnchorEl(null);
|
|
}}
|
|
>
|
|
<ListItemIcon>
|
|
<AddCircle />
|
|
</ListItemIcon>
|
|
<ListItemText primary="Add T-Break" />
|
|
</MenuItem>
|
|
{selected.length > 0 &&
|
|
(selected[0].subtype === pond.ShaftType.SHAFT_TYPE_CORNER ||
|
|
selected[0].subtype === pond.ShaftType.SHAFT_TYPE_T_BREAK) && (
|
|
<MenuItem
|
|
dense
|
|
onClick={() => {
|
|
selected[0].setDirection(0);
|
|
setAnchorEl(null);
|
|
}}
|
|
>
|
|
<ListItemIcon>
|
|
<ClockwiseIcon />
|
|
</ListItemIcon>
|
|
<ListItemText primary="Clockwise" />
|
|
</MenuItem>
|
|
)}
|
|
{selected.length > 0 &&
|
|
(selected[0].subtype === pond.ShaftType.SHAFT_TYPE_CORNER ||
|
|
selected[0].subtype === pond.ShaftType.SHAFT_TYPE_T_BREAK) && (
|
|
<MenuItem
|
|
dense
|
|
onClick={() => {
|
|
selected[0].setDirection(1);
|
|
setAnchorEl(null);
|
|
}}
|
|
>
|
|
<ListItemIcon>
|
|
<CounterclockwiseIcon />
|
|
</ListItemIcon>
|
|
<ListItemText primary="Counterclockwise" />
|
|
</MenuItem>
|
|
)}
|
|
{selected.length > 0 && (
|
|
<MenuItem
|
|
style={{ color: "red" }}
|
|
dense
|
|
onClick={() => {
|
|
saveState();
|
|
let b = [...blocks];
|
|
blocks.forEach((block, index) => {
|
|
if (
|
|
selected[0].x === block.x &&
|
|
selected[0].y === block.y &&
|
|
block.angle === selected[0].angle &&
|
|
block.type === selected[0].type
|
|
) {
|
|
b.splice(index, 1);
|
|
return;
|
|
}
|
|
});
|
|
setAnchorEl(null);
|
|
setSelected([]);
|
|
setBlocks(b);
|
|
}}
|
|
>
|
|
<ListItemIcon>
|
|
<DeleteIcon />
|
|
</ListItemIcon>
|
|
<ListItemText primary="Delete" />
|
|
</MenuItem>
|
|
)}
|
|
{selected.length > 0 && false && (
|
|
<MenuItem
|
|
dense
|
|
onClick={() => {
|
|
setAnchorEl(null);
|
|
let xy = selected[0].getEndXAndY();
|
|
let x = xy.x;
|
|
let y = xy.y;
|
|
//let startBlock = selected[0].clone();
|
|
let block = add(x, y);
|
|
if (block) {
|
|
//block.circle.selected = true;
|
|
//block.startSnap = startBlock;
|
|
//setSelected([block]);
|
|
}
|
|
//setMouseDown(true);
|
|
}}
|
|
>
|
|
<ListItemIcon>
|
|
<AddCircle />
|
|
</ListItemIcon>
|
|
<ListItemText primary="Extend" />
|
|
</MenuItem>
|
|
)}
|
|
</Menu>
|
|
</div>
|
|
);
|
|
}
|