Refactor token outline and add SVG option for token bar image previews

This commit is contained in:
Mitchell McCaffrey 2021-06-12 18:40:02 +10:00
parent 870d2de5de
commit e73d6d8317
3 changed files with 127 additions and 44 deletions

View File

@ -1,5 +1,5 @@
import React, { useState, useRef } from "react"; import React, { useState, useRef } from "react";
import { Image as KonvaImage, Group, Line, Rect, Circle } from "react-konva"; import { Image as KonvaImage, Group } from "react-konva";
import { useSpring, animated } from "react-spring/konva"; import { useSpring, animated } from "react-spring/konva";
import useImage from "use-image"; import useImage from "use-image";
import Konva from "konva"; import Konva from "konva";
@ -18,8 +18,7 @@ import { useDataURL } from "../../contexts/AssetsContext";
import TokenStatus from "../token/TokenStatus"; import TokenStatus from "../token/TokenStatus";
import TokenLabel from "../token/TokenLabel"; import TokenLabel from "../token/TokenLabel";
import TokenOutline from "../token/TokenOutline";
import colors from "../../helpers/colors";
import { tokenSources } from "../../tokens"; import { tokenSources } from "../../tokens";
@ -235,43 +234,6 @@ function MapToken({
} }
} }
function renderOutline() {
const outline = getScaledOutline();
const sharedProps = {
fill: colors.black,
opacity: tokenImage ? 0 : 0.8,
};
if (outline.type === "rect") {
return (
<Rect
width={outline.width}
height={outline.height}
x={outline.x}
y={outline.y}
{...sharedProps}
/>
);
} else if (outline.type === "circle") {
return (
<Circle
radius={outline.radius}
x={outline.x}
y={outline.y}
{...sharedProps}
/>
);
} else {
return (
<Line
points={outline.points}
closed
tension={outline.points < 200 ? 0 : 0.33}
{...sharedProps}
/>
);
}
}
return ( return (
<animated.Group <animated.Group
{...props} {...props}
@ -302,7 +264,7 @@ function MapToken({
offsetX={tokenWidth / 2} offsetX={tokenWidth / 2}
offsetY={tokenHeight / 2} offsetY={tokenHeight / 2}
> >
{renderOutline()} <TokenOutline outline={getScaledOutline()} hidden={!!tokenImage} />
</Group> </Group>
<KonvaImage <KonvaImage
ref={imageRef} ref={imageRef}

View File

@ -1,10 +1,12 @@
import React from "react"; import React, { useState } from "react";
import { Image } from "theme-ui"; import { Image, Box } from "theme-ui";
import { useDataURL } from "../../contexts/AssetsContext"; import { useDataURL } from "../../contexts/AssetsContext";
import { tokenSources as defaultTokenSources } from "../../tokens"; import { tokenSources as defaultTokenSources } from "../../tokens";
import { TokenOutlineSVG } from "./TokenOutline";
const TokenImage = React.forwardRef(({ token, ...props }, ref) => { const TokenImage = React.forwardRef(({ token, ...props }, ref) => {
const tokenURL = useDataURL( const tokenURL = useDataURL(
token, token,
@ -13,7 +15,32 @@ const TokenImage = React.forwardRef(({ token, ...props }, ref) => {
token.type === "file" token.type === "file"
); );
return <Image src={tokenURL} ref={ref} {...props} />; const [showOutline, setShowOutline] = useState(true);
return (
<>
{showOutline && (
<Box
title={props.alt}
aria-label={props.alt}
sx={{ width: "100%", height: "100%" }}
>
<TokenOutlineSVG
outline={token.outline}
width={token.width}
height={token.height}
/>
</Box>
)}
<Image
onLoad={() => setShowOutline(false)}
src={tokenURL}
ref={ref}
style={showOutline ? { display: "none" } : props.style}
{...props}
/>
</>
);
}); });
export default TokenImage; export default TokenImage;

View File

@ -0,0 +1,94 @@
import React from "react";
import { Rect, Circle, Line } from "react-konva";
import colors from "../../helpers/colors";
export function TokenOutlineSVG({ outline, width, height }) {
if (outline.type === "rect") {
return (
<svg
width="100%"
height="100%"
xmlns="http://www.w3.org/2000/svg"
fill="rgba(0, 0, 0, 0.3)"
viewBox={`0, 0, ${width} ${height}`}
preserveAspectRatio="xMidYMid slice"
>
<rect
x={outline.x}
y={outline.y}
width={outline.width}
height={outline.height}
/>
</svg>
);
} else if (outline.type === "circle") {
return (
<svg
width="100%"
height="100%"
xmlns="http://www.w3.org/2000/svg"
fill="rgba(0, 0, 0, 0.3)"
viewBox={`0, 0, ${width} ${height}`}
preserveAspectRatio="xMidYMid slice"
>
<circle r={outline.radius} cx={outline.x} cy={outline.y} />
</svg>
);
} else {
let points = [];
for (let i = 0; i < outline.points.length; i += 2) {
points.push(`${outline.points[i]}, ${outline.points[i + 1]}`);
}
return (
<svg
width="100%"
height="100%"
xmlns="http://www.w3.org/2000/svg"
fill="rgba(0, 0, 0, 0.3)"
viewBox={`0, 0, ${width} ${height}`}
preserveAspectRatio="xMidYMid slice"
>
<polygon points={points.join(" ")} />
</svg>
);
}
}
function TokenOutline({ outline, hidden }) {
const sharedProps = {
fill: colors.black,
opacity: hidden ? 0 : 0.8,
};
if (outline.type === "rect") {
return (
<Rect
width={outline.width}
height={outline.height}
x={outline.x}
y={outline.y}
{...sharedProps}
/>
);
} else if (outline.type === "circle") {
return (
<Circle
radius={outline.radius}
x={outline.x}
y={outline.y}
{...sharedProps}
/>
);
} else {
return (
<Line
points={outline.points}
closed
tension={outline.points < 200 ? 0 : 0.33}
{...sharedProps}
/>
);
}
}
export default TokenOutline;