+import { drag } from 'd3-drag';
+import { select } from 'd3-selection';
import React from 'react';
import Dungeons from './Dungeons';
import Items from './Items';
import Map from './Map';
+import ToggleIcon from './ToggleIcon';
+import ZeldaIcon from '../common/ZeldaIcon';
import { shouldShowDungeonItem } from '../../helpers/tracker';
import { useTracker } from '../../hooks/tracker';
};
const Canvas = () => {
- const { config } = useTracker();
+ const [dragging, setDragging] = React.useState(null);
+ const { addPin, config, pins, removePin } = useTracker();
const layout = React.useMemo(() => {
if (config.mapLayout === 'vertical') {
if (shouldShowDungeonItem(config, 'Big')) {
++count;
}
- return count > 2 ? LAYOUTS.manyDungeonItemsVertical : LAYOUTS.defaultVertical;
+ const compact = config.compactKeysanity && count === 4;
+ return !compact && count > 2
+ ? LAYOUTS.manyDungeonItemsVertical : LAYOUTS.defaultVertical;
} else {
return LAYOUTS.defaultHorizontal;
}
}, [config]);
+ React.useEffect(() => {
+ const canvas = select('.canvas');
+ const bbox = canvas.select('.background');
+ const start = { x: 0, y: 0 };
+ const onStart = function (e) {
+ start.x = e.x;
+ start.y = e.y;
+ };
+ const onDrag = function (e) {
+ const bounds = bbox.node().getBoundingClientRect();
+ const distance = Math.max(Math.abs(e.x - start.x), Math.abs(e.y - start.y));
+ if (distance > 5) {
+ setDragging({
+ icon: this.dataset['icon'],
+ x: (e.x - bounds.x) / bounds.width,
+ y: (e.y - bounds.y) / bounds.height,
+ });
+ } else {
+ setDragging(null);
+ }
+ };
+ const onEnd = function (e) {
+ const bounds = bbox.node().getBoundingClientRect();
+ setDragging(null);
+ const distance = Math.max(Math.abs(e.x - start.x), Math.abs(e.y - start.y));
+ if (distance > 5) {
+ addPin({
+ icon: this.dataset['icon'],
+ x: (e.x - bounds.x) / bounds.width,
+ y: (e.y - bounds.y) / bounds.height,
+ });
+ if (this.classList.contains('map-pin')) {
+ let id = 0;
+ this.classList.forEach(name => {
+ if (name.startsWith('map-pin-')) {
+ id = parseInt(name.substr(8), 10);
+ }
+ });
+ removePin({ id });
+ }
+ }
+ };
+ const selection = canvas.selectAll('.toggle-icon');
+ const draggable = drag()
+ .container(bbox)
+ .clickDistance(5)
+ .on('start', onStart)
+ .on('drag', onDrag)
+ .on('end', onEnd);
+ selection.call(draggable);
+ return () => {
+ selection.on('.drag', null);
+ };
+ }, [pins, removePin]);
+
return <svg
xmlns="http://www.w3.org/2000/svg"
className="canvas"
e.stopPropagation();
}}
>
+ <rect
+ className="background"
+ fill="transparent"
+ x="0" y="0"
+ width={layout.width}
+ height={layout.height}
+ />
<g className="items" transform={layout.itemsTransform}>
<Items />
</g>
<g className="tracker-map" transform={layout.mapTransform}>
<Map />
</g>
+ <g className="pins">
+ {pins.map(pin =>
+ <ToggleIcon
+ key={pin.id}
+ className={`map-pin map-pin-${pin.id}`}
+ controller={ToggleIcon.pinController(pin, removePin)}
+ icons={[pin.icon]}
+ svg
+ transform={
+ `translate(${pin.x * layout.width} ${pin.y * layout.height}) scale(3)`
+ }
+ />
+ )}
+ </g>
+ {dragging ?
+ <g transform={
+ `translate(${dragging.x * layout.width} ${dragging.y * layout.height}) scale(4)`
+ }>
+ <ZeldaIcon name={dragging.icon} svg />
+ </g>
+ : null}
</svg>;
};