Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 79 additions & 42 deletions src/components/tools/PortraitGenerator/Preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ const noteHeight = 45
const noteFont = "bold 25px \"Arial\""
const nameFont = "bold 17px \"Arial\""

export default function Preview({ active, remove, background, secondaryBackground, portraitPadding, changedWidth, names, tripleSplit, artifactSplit }: { active: PortraitIcon[], remove: (i: number) => void, background: boolean, secondaryBackground: string, portraitPadding: boolean, changedWidth: number, names: boolean, tripleSplit: boolean, artifactSplit: boolean }) {
export default function Preview({ active, remove, background, secondaryBackground, portraitPadding, changedWidth, names,
tripleSplit, artifactSplit, twoWeapons, twoWeaponsDistance, threeWeapons, threeWeaponsDistance }:
{ active: PortraitIcon[], remove: (i: number) => void, background: boolean, secondaryBackground: string, portraitPadding: boolean, changedWidth: number, names: boolean,
tripleSplit: boolean, artifactSplit: boolean, twoWeapons: string, twoWeaponsDistance: number, threeWeapons: string, threeWeaponsDistance: number }) {
const canvasRef = useRef(null as HTMLCanvasElement)
const [hovering, setHovering] = useState(false)

Expand All @@ -28,7 +31,7 @@ export default function Preview({ active, remove, background, secondaryBackgroun

function getName(x: PortraitIcon) {
// Filter out Skin or Version number
var filteredName = filterName(x.name);
var filteredName = filterName(x.name)
return `${filteredName}${x.others ? "+" + x.others.map(x => getName(x)).join("+") : ""}`
}
const list = active.map(x => getName(x)).join(" - ")
Expand Down Expand Up @@ -71,9 +74,10 @@ export default function Preview({ active, remove, background, secondaryBackgroun
// https://stackoverflow.com/questions/6011378/how-to-add-image-to-canvas
const x = leftBorder + effectivePortraitPad + portraitSize * (changedWidth - 1) / 2
const y = effectiveFramePad + effectivePortraitPad
await drawIcon(ctx, icon, x, y, portraitSize, names, tripleSplit, artifactSplit)
await drawIcon(ctx, icon, x, y, portraitSize, names, tripleSplit, artifactSplit, twoWeapons, twoWeaponsDistance, threeWeapons, threeWeaponsDistance)
}
})(), [active, background, secondaryBackground, effectivePortraitPad, changedWidth, names, tripleSplit, artifactSplit])
})(), [active, background, secondaryBackground, effectivePortraitPad, changedWidth, names,
tripleSplit, artifactSplit, twoWeapons, twoWeaponsDistance, threeWeapons, threeWeaponsDistance])

return <div>
<canvas
Expand Down Expand Up @@ -111,7 +115,8 @@ function loadImage(path: string): Promise<HTMLImageElement> {
})
}

async function drawIcon(ctx: CanvasRenderingContext2D, icon: PortraitIcon, x: number, y: number, size: number, names: boolean, tripleSplit: boolean, artifactSplit: boolean) {
async function drawIcon(ctx: CanvasRenderingContext2D, icon: PortraitIcon, x: number, y: number, size: number, names: boolean,
tripleSplit: boolean, artifactSplit: boolean, twoWeapons: string, twoWeaponsDistance: number, threeWeapons: string, threeWeaponsDistance: number) {
const baseImage = await loadImage(icon.path)
const firstIconType = imageType(icon.path)

Expand All @@ -121,20 +126,30 @@ async function drawIcon(ctx: CanvasRenderingContext2D, icon: PortraitIcon, x: nu

if (icon.others) {
if (icon.others.length == 1) {
// 2 images
await drawTopHalf(ctx, icon, baseImage, x, y, size)

const secondIconType = imageType(icon.others[0].path)
if (secondIconType == "Artifact") {
icon.others[0].full = artifactSplit
}
const secondIcon = icon.others[0]
const second = await loadImage(secondIcon.path)
await drawBottomHalf(ctx, secondIcon, second, x, y, size)

if (twoWeapons != "Split" && firstIconType == "Weapon" && secondIconType == "Weapon") {
// 2 images (1st Weapon + 2nd Weapon overlapped or side-by-side)
if (twoWeapons == "Overlap") {
await drawImg(ctx, icon, baseImage, x, y, size)
await drawMirroredImg(ctx, secondIcon, second, x, y, size)
} else if (twoWeapons == "SideBySide") {
await drawSlightlyLeft(ctx, icon, baseImage, x, y, size, twoWeaponsDistance * 0.8)
await drawSlightlyRight(ctx, secondIcon, second, x, y, size, twoWeaponsDistance * 0.8)
}
} else {
// 2 images
await drawTopHalf(ctx, icon, baseImage, x, y, size)
await drawBottomHalf(ctx, secondIcon, second, x, y, size)

drawDiagonal(ctx, x, y, size)
drawDiagonal(ctx, x, y, size)
}
} else {
// 3/4 images
const secondIconType = imageType(icon.others[0].path)
if (secondIconType == "Artifact") {
icon.others[0].full = artifactSplit
Expand All @@ -156,43 +171,50 @@ async function drawIcon(ctx: CanvasRenderingContext2D, icon: PortraitIcon, x: nu
icon.others[2].full = artifactSplit
}
}

if (fourthIconType == "None" && tripleSplit) {
await drawTopLeft(ctx, icon, baseImage, x, y, size)
await drawTopRight(ctx, secondIcon, second, x, y, size)

if (threeWeapons == "SideBySide" && firstIconType == "Weapon" && secondIconType == "Weapon" && thirdIconType == "Weapon" && fourthIconType == "None") {
// 3 images (1st Weapon + 2nd Weapon + 3nd Weapon side-by-side)
await drawSlightlyLeft(ctx, icon, baseImage, x, y, size, threeWeaponsDistance)
await drawImg(ctx, secondIcon, second, x, y, size)
await drawSlightlyRight(ctx, thirdIcon, third, x, y, size, threeWeaponsDistance)
} else {
await drawTopCenter(ctx, icon, baseImage, x, y, size)
await drawLeftCenter(ctx, secondIcon, second, x, y, size)
}
// 3/4 images
if (fourthIconType == "None" && tripleSplit) {
await drawTopLeft(ctx, icon, baseImage, x, y, size)
await drawTopRight(ctx, secondIcon, second, x, y, size)
} else {
await drawTopCenter(ctx, icon, baseImage, x, y, size)
await drawLeftCenter(ctx, secondIcon, second, x, y, size)
}

if (fourthIconType == "None") {
// 3 images
if (tripleSplit) {
await drawBottomCenter2(ctx, thirdIcon, third, x, y, size)

drawHalfMiddleSplit(ctx, x, y, size)
drawHalfFirstTripleDiagonal(ctx, x, y, size)
drawHalfSecondTripleDiagonal(ctx, x, y, size)
if (fourthIconType == "None") {
// 3 images
if (tripleSplit) {
await drawBottomCenter2(ctx, thirdIcon, third, x, y, size)

drawHalfMiddleSplit(ctx, x, y, size)
drawHalfFirstTripleDiagonal(ctx, x, y, size)
drawHalfSecondTripleDiagonal(ctx, x, y, size)
} else {
await drawBottomHalf(ctx, thirdIcon, third, x, y, size)

drawDiagonal(ctx, x, y, size)
drawTLHalfDiagonal(ctx, x, y, size)
}
} else {
await drawBottomHalf(ctx, thirdIcon, third, x, y, size)
// 4 images
await drawRightCenter(ctx, thirdIcon, third, x, y, size)

const fourthIcon = icon.others[2]
const fourth = await loadImage(fourthIcon.path)

await drawBottomCenter(ctx, fourthIcon, fourth, x, y, size)

drawDiagonal(ctx, x, y, size)
drawTLHalfDiagonal(ctx, x, y, size)
drawTLDiagonal(ctx, x, y, size)
}
} else {
// 4 images
await drawRightCenter(ctx, thirdIcon, third, x, y, size)

const fourthIcon = icon.others[2]
const fourth = await loadImage(fourthIcon.path)

await drawBottomCenter(ctx, fourthIcon, fourth, x, y, size)

drawDiagonal(ctx, x, y, size)
drawTLDiagonal(ctx, x, y, size)
}
}

} else {
// Draw singular
drawImg(ctx, icon, baseImage, x, y, size)
Expand All @@ -219,7 +241,7 @@ async function drawIcon(ctx: CanvasRenderingContext2D, icon: PortraitIcon, x: nu
ctx.fillStyle = "#FFFFFF"
ctx.textBaseline = "alphabetic"
// Filter out Skin or Version number
var filteredName = filterName(icon.name);
var filteredName = filterName(icon.name)
// ctx.fillText(icon.name, x + size / 2, y + size + 34)
wrapText(ctx, filteredName, x + size / 2, y + size + 34, 180, 20)
.forEach(([text, x, y]) => ctx.fillText(text, x, y))
Expand All @@ -235,6 +257,21 @@ async function drawImg(ctx: CanvasRenderingContext2D, icon: PortraitIcon, baseIm
}
}

async function drawMirroredImg(ctx: CanvasRenderingContext2D, icon: PortraitIcon, img: HTMLImageElement, x: number, y: number, size: number) {
ctx.save()
ctx.scale(-1, 1)
await drawImg(ctx, icon, img, -x -size, y, size)
ctx.restore()
}

async function drawSlightlyLeft(ctx: CanvasRenderingContext2D, icon: PortraitIcon, img: HTMLImageElement, x: number, y: number, size: number, distance: number) {
await drawImg(ctx, icon, img, x - ((size / 6) * distance), y, size)
}

async function drawSlightlyRight(ctx: CanvasRenderingContext2D, icon: PortraitIcon, img: HTMLImageElement, x: number, y: number, size: number, distance: number) {
await drawImg(ctx, icon, img, x + ((size / 6) * distance), y, size)
}

async function drawBottomHalf(ctx: CanvasRenderingContext2D, icon: PortraitIcon, img: HTMLImageElement, x: number, y: number, size: number) {
const half = size / 2
ctx.save()
Expand Down Expand Up @@ -448,7 +485,7 @@ function drawHalfSecondTripleDiagonal(ctx: CanvasRenderingContext2D, x: number,

function filterName(name: string) {
// Filter out Skin or Version number
return name.replace(/ Skin[0-9]+| Alt[0-9]+/g, "");
return name.replace(/ Skin[0-9]+| Alt[0-9]+/g, "")
}

function imageType(path: string) {
Expand Down
47 changes: 47 additions & 0 deletions src/components/tools/PortraitGenerator/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ export default function PortraitGenerator({
const [tripleSplit, setTripleSplit] = useState(true)

const [artifactSplit, setArtifactSplit] = useState(true)
const [twoWeapons, setTwoWeapons] = useState("Split")
const [twoWeaponsDistance, setTwoWeaponsDistance] = useState(1)
const [threeWeapons, setThreeWeapons] = useState("Split")
const [threeWeaponsDistance, setThreeWeaponsDistance] = useState(1)

const [search, setSearch] = useState("")

Expand Down Expand Up @@ -249,6 +253,10 @@ export default function PortraitGenerator({
setTripleSplit(true)

setArtifactSplit(true)
setTwoWeapons("Split")
setTwoWeaponsDistance(1)
setThreeWeapons("Split")
setThreeWeaponsDistance(1)
}
}}>
Reset to default settings</button>
Expand Down Expand Up @@ -290,7 +298,42 @@ export default function PortraitGenerator({
<option value="1">Partial</option>
<option value="">Full</option>
</select>
</label> <br/>
<label>
Two weapons: <select onChange={e => setTwoWeapons(e.target.value)} value={twoWeapons}>
<option value="Split">Split</option>
<option value="Overlap">Overlap</option>
<option value="SideBySide">Side-by-Side</option>
</select>
</label>
{twoWeapons == "SideBySide" && <label>
&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
Distance between two weapons: <select onChange={e => setTwoWeaponsDistance(parseFloat(e.target.value))} value={twoWeaponsDistance}>
<option value="1">x1</option>
<option value="1.1">x1.1</option>
<option value="1.2">x1.2</option>
<option value="1.3">x1.3</option>
<option value="1.4">x1.4</option>
<option value="1.5">x1.5</option>
</select>
</label>} <br/>
<label>
Three weapons: <select onChange={e => setThreeWeapons(e.target.value)} value={threeWeapons}>
<option value="Split">Split</option>
<option value="SideBySide">Side-by-Side</option>
</select>
</label>
{threeWeapons == "SideBySide" && <label>
&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
Distance between three weapons: <select onChange={e => setThreeWeaponsDistance(parseFloat(e.target.value))} value={threeWeaponsDistance}>
<option value="1">x1</option>
<option value="1.1">x1.1</option>
<option value="1.2">x1.2</option>
<option value="1.3">x1.3</option>
<option value="1.4">x1.4</option>
<option value="1.5">x1.5</option>
</select>
</label>}
</MDXComponents.Details>

<Preview
Expand All @@ -303,6 +346,10 @@ export default function PortraitGenerator({
names={names}
tripleSplit={tripleSplit}
artifactSplit={artifactSplit}
twoWeapons={twoWeapons}
twoWeaponsDistance={twoWeaponsDistance}
threeWeapons={threeWeapons}
threeWeaponsDistance={threeWeaponsDistance}
/>

<label>
Expand Down