sendou.ink/frontend-react/src/components/plans/MapPlanner.js
2020-01-09 14:26:22 +02:00

376 lines
11 KiB
JavaScript

import React, { useState, useEffect, useRef } from "react"
import { SketchField, Tools } from "@sendou/react-sketch"
import { CirclePicker } from "react-color"
import {
Button,
Icon,
Input,
Grid,
Label,
Message,
Dropdown,
} from "semantic-ui-react"
import weaponDict from "../../utils/english_internal.json"
import useWindowDimensions from "../../hooks/useWindowDimensions"
import academy from "../../assets/plannerMaps/academy-sz.png"
import arena from "../../assets/plannerMaps/arena-sz.png"
import camp from "../../assets/plannerMaps/camp-sz.png"
import canal from "../../assets/plannerMaps/canal-sz.png"
import dome from "../../assets/plannerMaps/dome-sz.png"
import fitness from "../../assets/plannerMaps/fitness-sz.png"
import games from "../../assets/plannerMaps/games-sz.png"
import hotel from "../../assets/plannerMaps/hotel-sz.png"
import institute from "../../assets/plannerMaps/institute-sz.png"
import mainstage from "../../assets/plannerMaps/mainstage-sz.png"
import mall from "../../assets/plannerMaps/mall-sz.png"
import manta from "../../assets/plannerMaps/manta-sz.png"
import mart from "../../assets/plannerMaps/mart-sz.png"
import pavilion from "../../assets/plannerMaps/pavilion-sz.png"
import pit from "../../assets/plannerMaps/pit-sz.png"
import pitrm from "../../assets/plannerMaps/pit-rm.png"
import port from "../../assets/plannerMaps/port-sz.png"
import pumptrack from "../../assets/plannerMaps/pumptrack-sz.png"
import reef from "../../assets/plannerMaps/reef-sz.png"
import shipyard from "../../assets/plannerMaps/shipyard-sz.png"
import skatepark from "../../assets/plannerMaps/skatepark-sz.png"
import towers from "../../assets/plannerMaps/towers-sz.png"
import warehouse from "../../assets/plannerMaps/warehouse-sz.png"
import world from "../../assets/plannerMaps/world-sz.png"
import { wpnMedium } from "../../assets/imageImports"
import ToolsSelector from "./ToolsSelector"
import WeaponSelector from "./WeaponSelector"
const MapPlanner = () => {
let sketch = null
const { containerWidth } = useWindowDimensions()
const defaultValue = {
shadowWidth: 0,
shadowOffset: 0,
enableRemoveSelected: false,
fillWithColor: false,
fillWithBackgroundColor: false,
drawings: [],
canUndo: false,
canRedo: false,
controlledSize: false,
sketchWidth: 600,
sketchHeight: 600,
stretched: true,
stretchedX: false,
stretchedY: false,
originX: "left",
originY: "top",
expandTools: false,
expandControls: false,
expandColors: false,
expandBack: false,
expandImages: false,
expandControlled: false,
enableCopyPaste: false,
}
const fileInput = useRef(null)
const [tool, setTool] = useState(Tools.Pencil)
const [color, setColor] = useState("#f44336")
const [canUndo, setCanUndo] = useState(false)
const [canRedo, setCanRedo] = useState(false)
const [text, setText] = useState("")
const [bg, setBg] = useState(null)
const [uploadError, setUploadError] = useState(null)
const [controlledValue, setControlledValue] = useState(defaultValue)
useEffect(() => {
document.title = "Planner - sendou.ink"
}, [])
// doesn't work properly when coming back from another page - not sure why
useEffect(() => {
if (!sketch) {
return
}
setBg(reef)
sketch.setBackgroundFromDataUrl(reef)
}, [sketch])
const maps = [
{ key: "The Reef", text: "The Reef", value: reef },
{
key: "Musselforge Fitness",
text: "Musselforge Fitness",
value: fitness,
},
{
key: "Starfish Mainstage",
text: "Starfish Mainstage",
value: mainstage,
},
{
key: "Humpback Pump Track",
text: "Humpback Pump Track",
value: pumptrack,
},
{
key: "Inkblot Art Academy",
text: "Inkblot Art Academy",
value: academy,
},
{
key: "Sturgeon Shipyard",
text: "Sturgeon Shipyard",
value: shipyard,
},
{ key: "Moray Towers", text: "Moray Towers", value: towers },
{ key: "Port Mackerel", text: "Port Mackerel", value: port },
{ key: "Manta Maria", text: "Manta Maria", value: manta },
{ key: "Kelp Dome", text: "Kelp Dome", value: dome },
{ key: "Snapper Canal", text: "Snapper Canal", value: canal },
{
key: "Blackbelly Skatepark",
text: "Blackbelly Skatepark",
value: skatepark,
},
{ key: "MakoMart", text: "MakoMart", value: mart },
{
key: "Walleye Warehouse",
text: "Walleye Warehouse",
value: warehouse,
},
{
key: "Shellendorf Institute",
text: "Shellendorf Institute",
value: institute,
},
{ key: "Arowana Mall", text: "Arowana Mall", value: mall },
{ key: "Goby Arena", text: "Goby Arena", value: arena },
{ key: "Piranha Pit", text: "Piranha Pit", value: pit },
{
key: "Piranha Pit (RM)",
text: "Piranha Pit (RM)",
value: pitrm,
},
{
key: "Camp Triggerfish",
text: "Camp Triggerfish",
value: camp,
},
{ key: "Wahoo World", text: "Wahoo World", value: world },
{
key: "New Albacore Hotel",
text: "New Albacore Hotel",
value: hotel,
},
{ key: "Ancho-V Games", text: "Ancho-V Games", value: games },
{
key: "Skipper Pavilion",
text: "Skipper Pavilion",
value: pavilion,
},
]
const addImageToSketch = weapon => {
sketch.addImg(wpnMedium[weaponDict[weapon]])
setTool(Tools.Select)
}
const addTextToSketch = () => {
sketch.addText(text, {
fill: color,
fontFamily: "lato",
stroke: "#000000",
strokeWidth: 3,
paintFirst: "stroke",
})
setTool(Tools.Select)
}
const undo = () => {
sketch.undo()
setCanUndo(sketch.canUndo())
setCanRedo(sketch.canRedo())
}
const redo = () => {
sketch.redo()
setCanUndo(sketch.canUndo())
setCanRedo(sketch.canRedo())
}
const removeSelected = () => {
sketch.removeSelected()
}
const onSketchChange = () => {
let prev = canUndo
let now = sketch.canUndo()
if (prev !== now) {
setCanUndo(now)
}
}
const getDateFormatted = () => {
const today = new Date()
const date =
today.getFullYear() + "-" + (today.getMonth() + 1) + "-" + today.getDate()
const time =
today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds()
return date + " " + time
}
const download = (dataUrl, extension) => {
let a = document.createElement("a")
document.body.appendChild(a)
a.style = "display: none"
a.href = dataUrl
a.download = `${
bg.replace("/static/media/", "").split("-")[0]
} plans ${getDateFormatted()}.${extension}`
a.click()
window.URL.revokeObjectURL(dataUrl)
}
const handleUpload = () => {
if (fileInput.current.files.length === 0) {
setUploadError("Upload file")
setTimeout(() => setUploadError(null), 5000)
return
}
const fileObj = fileInput.current.files[0]
const reader = new FileReader()
reader.onload = function(event) {
const jsonObj = JSON.parse(event.target.result)
setControlledValue(jsonObj)
}
reader.readAsText(fileObj)
}
const onBgChange = value => {
sketch.clear()
setBg(value)
setCanUndo(false)
sketch.setBackgroundFromDataUrl(value)
}
return (
<>
<ToolsSelector tool={tool} setTool={setTool} />
<div style={{ paddingLeft: "950px" }}>
<WeaponSelector addWeaponImage={weapon => addImageToSketch(weapon)} />
</div>
{containerWidth < 1127 && (
<Message negative>
Unfortunately this tool isn't designed for narrow screens but you can
still give it a go.
</Message>
)}
<SketchField
name="sketch"
className="canvas-area"
ref={c => (sketch = c)}
lineColor={color}
lineWidth={5}
width={1127}
height={634}
value={controlledValue}
onChange={onSketchChange}
tool={tool}
style={{ position: "relative", left: "-27px" }}
/>
<div style={{ marginTop: "1em" }}>
<Button primary icon disabled={!canUndo} onClick={() => undo()}>
<Icon name="undo" /> Undo
</Button>
<Button primary icon disabled={!canRedo} onClick={() => redo()}>
<Icon name="redo" /> Redo
</Button>
<Button
primary
icon
disabled={tool !== Tools.Select}
onClick={() => removeSelected()}
>
<Icon name="trash" /> Delete selected
</Button>
<Button
secondary
icon
onClick={() => download(sketch.toDataURL(), "png")}
>
<Icon name="download" /> Download as .png
</Button>
<Button
secondary
icon
onClick={() =>
download(
"data:text/json;charset=utf-8," +
encodeURIComponent(JSON.stringify(sketch.toJSON())),
"json"
)
}
>
<Icon name="cloud download" /> Download as .json
</Button>
<Button secondary icon onClick={() => handleUpload()}>
<Icon name="cloud upload" /> Load from .json
</Button>
<input type="file" accept=".json" ref={fileInput} />
{uploadError && <span style={{ color: "red" }}>{uploadError}</span>}
<div style={{ paddingTop: "10px" }}>
<Grid columns={3}>
<Grid.Column>
<h3>Add text</h3>
<Input value={text} onChange={e => setText(e.target.value)} />
<div style={{ paddingTop: "7px" }}>
<Button
icon="plus"
circular
onClick={() => addTextToSketch()}
/>
</div>
</Grid.Column>
<Grid.Column>
<h3>Choose the map</h3>
<Dropdown
onChange={(e, { value }) => onBgChange(value)}
options={maps}
selection
value={bg}
style={{ width: "250px" }}
/>
<Label basic color="red" pointing="above">
Please note that changing the map also clears all the drawings
</Label>
</Grid.Column>
<Grid.Column>
<CirclePicker
color={color}
width="220px"
onChangeComplete={newColor => setColor(newColor.hex)}
colors={[
"#f44336",
"#e91e63",
"#9c27b0",
"#673ab7",
"#3f51b5",
"#2196f3",
"#03a9f4",
"#00bcd4",
"#009688",
"#4caf50",
"#8bc34a",
"#cddc39",
"#ffeb3b",
"#ffc107",
"#ff9800",
]}
/>
</Grid.Column>
</Grid>
</div>
</div>
</>
)
}
export default MapPlanner