This commit is contained in:
Lani Aung
2021-10-17 13:24:24 -06:00
parent d1d891881f
commit 36e5726eaf
9 changed files with 207 additions and 93 deletions
+13 -6
View File
@@ -15,6 +15,16 @@ namespace fxl.codes.kisekae.Models
internal CelModel(ILogger<ConfigurationReaderService> logger, string line) internal CelModel(ILogger<ConfigurationReaderService> logger, string line)
{ {
logger.LogTrace($"Parsing cel line {line}"); logger.LogTrace($"Parsing cel line {line}");
if (line.Contains("%t"))
{
var opacity = line[line.IndexOf("%t")..].Trim();
opacity = opacity.Split(';', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)[0];
opacity = opacity.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)[0];
opacity = opacity.Replace("%t", "");
Opacity = 1.0 - double.Parse(opacity) / 255;
}
var matcher = new Regex(Regex); var matcher = new Regex(Regex);
var match = matcher.Match(line); var match = matcher.Match(line);
@@ -26,13 +36,9 @@ namespace fxl.codes.kisekae.Models
if (string.IsNullOrEmpty(group?.Value)) if (string.IsNullOrEmpty(group?.Value))
{ {
if (string.Equals(groupName, "Sets")) if (string.Equals(groupName, "Sets"))
{
for (var index = 0; index < Sets.Length; index++) for (var index = 0; index < Sets.Length; index++)
{
Sets[index] = true; Sets[index] = true;
}
}
logger.LogWarning($"Unable to find regex group {groupName} in {line}"); logger.LogWarning($"Unable to find regex group {groupName} in {line}");
continue; continue;
} }
@@ -42,7 +48,7 @@ namespace fxl.codes.kisekae.Models
if (property.PropertyType == typeof(int)) property.SetValue(this, int.Parse(value)); if (property.PropertyType == typeof(int)) property.SetValue(this, int.Parse(value));
if (property.PropertyType != Sets.GetType()) continue; if (property.PropertyType != Sets.GetType()) continue;
foreach (var id in value.Split(' ', StringSplitOptions.RemoveEmptyEntries)) foreach (var id in value.Split(' ', StringSplitOptions.RemoveEmptyEntries))
{ {
var success = int.TryParse(id, out var result); var success = int.TryParse(id, out var result);
@@ -58,6 +64,7 @@ namespace fxl.codes.kisekae.Models
public int PaletteId { get; init; } public int PaletteId { get; init; }
public bool[] Sets { get; } = new bool[10]; public bool[] Sets { get; } = new bool[10];
public string Comment { get; init; } public string Comment { get; init; }
public double Opacity { get; } = 1.0;
public Coordinate[] InitialPositions { get; } = new Coordinate[10]; public Coordinate[] InitialPositions { get; } = new Coordinate[10];
[JsonIgnore] public string DefaultImage => ImageByPalette.ContainsKey(PaletteId) ? ImageByPalette[PaletteId] : null; [JsonIgnore] public string DefaultImage => ImageByPalette.ContainsKey(PaletteId) ? ImageByPalette[PaletteId] : null;
public Coordinate Offset { get; set; } public Coordinate Offset { get; set; }
+1 -1
View File
@@ -2,7 +2,7 @@ namespace fxl.codes.kisekae.Models
{ {
public class Coordinate public class Coordinate
{ {
public Coordinate(int x, int y) public Coordinate(int x = 0, int y = 0)
{ {
X = x; X = x;
Y = y; Y = y;
-24
View File
@@ -1,24 +0,0 @@
import {Playset} from "./pto"
const cssClass = "active-set"
export function setPlayArea(header: HTMLElement, container: HTMLElement, playset: Playset, set: number): void {
header.querySelectorAll("button").forEach(button => {
button.classList.remove(cssClass)
})
header.querySelector(`button[data-set="${set}"]`).classList.add(cssClass)
let elements = container.querySelectorAll(".cel-image")
playset.cels.forEach((cel, index) => {
let element = elements[index] as HTMLDivElement
element.style.visibility = "hidden"
if (cel.sets[set]) {
let position = cel.currentPositions[set]
element.style.visibility = "visible"
element.style.left = `${position.x}px`
element.style.top = `${position.y}px`
}
})
}
+4 -33
View File
@@ -1,8 +1,8 @@
import {MDCLinearProgress} from "@material/linear-progress" import {MDCLinearProgress} from "@material/linear-progress"
import {MDCRipple} from "@material/ripple" import {MDCRipple} from "@material/ripple"
import {MDCTopAppBar} from "@material/top-app-bar" import {MDCTopAppBar} from "@material/top-app-bar"
import {setPlayArea} from "./function"
import {Playset} from "./pto" import {Playset} from "./pto"
import Tracker from "./tracker"
import Builder from "./utility" import Builder from "./utility"
declare global { declare global {
@@ -30,39 +30,10 @@ export default class Main {
public load(containerId: string, headerId: string, playset: Playset, set: number = 0): void { public load(containerId: string, headerId: string, playset: Playset, set: number = 0): void {
let container = document.getElementById(containerId) let container = document.getElementById(containerId)
let header = document.getElementById(headerId) let menu = document.getElementById(headerId).querySelector("ul")
let menu = header.querySelector("ul")
let reset = header.querySelector(`button[data-rel="reset"]`) let tracker = new Tracker(playset, menu, container)
reset.addEventListener("click", () => { tracker.setPlayArea(set)
// TODO reset positions
setPlayArea(header, container, playset, set)
})
playset.enabledSets.forEach((enabled, index) => {
if (enabled) {
let button = new Builder("li")
.addChildren(new Builder("button")
.addClass("mdc-button")
.addAttributes({"data-set": index})
.addChildren(
new Builder("span").addClass("mdc-button__ripple"),
new Builder("span").addClass("mdc-button__label").setText(index.toString())
)).build()
button.addEventListener("click", () => {
setPlayArea(header, container, playset, index)
})
menu.appendChild(button)
}
})
playset.cels.forEach(cel => {
cel.currentPositions = [...cel.initialPositions]
})
setPlayArea(header, container, playset, set)
} }
private init() { private init() {
+15 -14
View File
@@ -1,24 +1,25 @@
export class Playset { export interface Playset {
name: string readonly name: string
height: number readonly height: number
width: number readonly width: number
readonly cels: Cel[]
cels: Cel[] readonly enabledSets: boolean[]
enabledSets: boolean[]
} }
export class Cel { export interface Cel {
defaultImage: string readonly id: number
initialPositions: Coordinate[] readonly fix: number
offset: Coordinate readonly initialPositions: Coordinate[]
sets: boolean[] readonly offset: Coordinate
readonly sets: boolean[]
currentPositions: Coordinate[] currentPositions: Coordinate[]
currentFix: number
} }
export class Coordinate { export class Coordinate {
x: number readonly x: number
y: number readonly y: number
constructor(x: number = 0, y: number = 0) { constructor(x: number = 0, y: number = 0) {
this.x = x this.x = x
+158
View File
@@ -0,0 +1,158 @@
import {Cel, Coordinate, Playset} from "./pto"
import Builder from "./utility"
const cssClass = "active-set"
export default class Tracker {
set: number = 0
setPalettes: number[] = []
private playset: Playset
private menu: HTMLElement
private playSpace: HTMLElement
private maxFixById: { [key: number]: number } = {}
constructor(playset: Playset, menu: HTMLElement, playSpace: HTMLElement) {
this.playset = playset
this.menu = menu
this.playSpace = playSpace
this.addEvents()
this.reset()
this.setMenu()
}
private static adjustPlacement(cel: Cel, set: number, movement: Coordinate): Coordinate {
let x = cel.currentPositions[set].x + movement.x
let y = cel.currentPositions[set].y + movement.y
cel.currentPositions[set] = new Coordinate(x, y)
return Tracker.getCoordinate(cel, set)
}
private static getCoordinate(cel: Cel, set: number): Coordinate {
let position = cel.currentPositions[set]
if (!position) return new Coordinate()
if (!cel.offset) return position
return new Coordinate(position.x + cel.offset.x, position.y + cel.offset.y)
}
setPlayArea(set: number): void {
this.set = set
this.menu.querySelectorAll("button").forEach(button => {
button.classList.remove(cssClass)
})
this.menu.querySelector(`button[data-set="${set}"]`).classList.add(cssClass)
let elements = this.playSpace.querySelectorAll(".cel-image")
this.playset.cels.forEach((cel, index) => {
let element = elements[index] as HTMLDivElement
element.style.visibility = "hidden"
if (cel.sets[set]) {
element.style.visibility = "visible"
let position = Tracker.getCoordinate(cel, set)
element.style.left = `${position.x}px`
element.style.top = `${position.y}px`
}
})
}
private addEvents() {
let previousEvent: MouseEvent | null = null
let elements = this.playSpace.querySelectorAll(".cel-image")
elements.forEach((element: HTMLElement) => {
let mousemove = (move: MouseEvent) => {
let movement = new Coordinate(move.clientX - previousEvent.clientX, move.clientY - previousEvent.clientY)
previousEvent = move
let group = this.getGroup(element)
group.forEach((item: HTMLElement) => {
let index = parseInt(item.attributes.getNamedItem("data-index").value)
let cel = this.playset.cels[index]
if (cel.currentFix == 0) {
let position = Tracker.adjustPlacement(cel, this.set, movement)
item.style.left = `${position.x}px`
item.style.top = `${position.y}px`
}
})
}
element.addEventListener("mousedown", (down: MouseEvent) => {
previousEvent = down
this.getGroup(element).forEach(item => {
let index = parseInt(item.attributes.getNamedItem("data-index").value)
let cel = this.playset.cels[index]
if (cel.currentFix > 0) cel.currentFix--
})
window.addEventListener("mousemove", mousemove)
window.addEventListener("mouseup", () => {
previousEvent = null
window.removeEventListener("mousemove", mousemove)
})
})
})
}
private getGroup(element: Element): NodeListOf<Element> {
let id = element.attributes.getNamedItem("data-id").value
return this.playSpace.querySelectorAll(`.cel-image[data-id="${id}"]`)
}
private reset(): void {
this.playSpace.querySelectorAll(".cel-image").forEach((element: HTMLElement) => {
element.style.visibility = "hidden"
element.style.left = "0"
element.style.top = "0"
})
this.playset.cels.forEach(cel => {
if (!this.maxFixById[cel.id]) {
this.maxFixById[cel.id] = 0
}
if (this.maxFixById[cel.id] < cel.fix) {
this.maxFixById[cel.id] = cel.fix
}
})
this.playset.cels.forEach(cel => {
cel.currentFix = this.maxFixById[cel.id]
cel.currentPositions = cel.initialPositions.map(position => position ? new Coordinate(position.x, position.y) : null)
})
}
private setMenu(): void {
let reset = this.menu.querySelector(`button[data-rel="reset"]`)
reset.addEventListener("click", () => {
this.reset()
this.setPlayArea(this.set)
})
this.playset.enabledSets.forEach((enabled, index) => {
if (enabled) {
let button = new Builder("li")
.addChildren(new Builder("button")
.addClass("mdc-button")
.addAttributes({"data-set": index})
.addChildren(
new Builder("span").addClass("mdc-button__ripple"),
new Builder("span").addClass("mdc-button__label").setText(index.toString())
)).build()
button.addEventListener("click", () => {
this.setPlayArea(index)
})
this.menu.appendChild(button)
}
})
}
}
+10 -10
View File
@@ -1,31 +1,31 @@
export default class Builder { export default class Builder {
element: HTMLElement element: HTMLElement
constructor(tag: string) { constructor(tag: string) {
this.element = document.createElement(tag) this.element = document.createElement(tag)
} }
addAttributes(attributes: {[key: string]: string | number}): Builder { addAttributes(attributes: { [key: string]: string | number }): Builder {
for (let key of Object.keys(attributes)) { for (let key of Object.keys(attributes)) {
this.addAttribute(key, attributes[key]) this.addAttribute(key, attributes[key])
} }
return this return this
} }
addAttribute(name: string, value: string | number): Builder { addAttribute(name: string, value: string | number): Builder {
let attribute = document.createAttribute(name) let attribute = document.createAttribute(name)
attribute.value = value.toString() attribute.value = value.toString()
this.element.attributes.setNamedItem(attribute) this.element.attributes.setNamedItem(attribute)
return this return this
} }
addClass(...classes: string[]): Builder { addClass(...classes: string[]): Builder {
this.element.classList.add(...classes) this.element.classList.add(...classes)
return this return this
} }
addChildren(...children: HTMLElement[] | Builder[]): Builder { addChildren(...children: HTMLElement[] | Builder[]): Builder {
children.forEach(child => { children.forEach(child => {
if (child instanceof HTMLElement) { if (child instanceof HTMLElement) {
@@ -34,15 +34,15 @@ export default class Builder {
this.element.appendChild(child.build()) this.element.appendChild(child.build())
} }
}) })
return this return this
} }
setText(text: string): Builder { setText(text: string): Builder {
this.element.textContent = text this.element.textContent = text
return this return this
} }
build(): HTMLElement { build(): HTMLElement {
return this.element return this.element
} }
+5 -4
View File
@@ -18,12 +18,13 @@
</header> </header>
<article id="play_area" style="background-color: #@Model.BorderColor"> <article id="play_area" style="background-color: #@Model.BorderColor">
<div id="play_space" style="height: @(Model.Height)px; width: @(Model.Width)px"> <div id="play_space" style="height: @(Model.Height)px; width: @(Model.Width)px">
@foreach (var cel in Model.Cels) @for (var index = 0; index < Model.Cels.Count; index++)
{ {
var cel = Model.Cels[index];
<div class="cel-image" <div class="cel-image"
style="background-image: url('data:image/gif;base64,@cel.DefaultImage'); height: @(cel.Height)px; width: @(cel.Width)px; z-index: @cel.ZIndex;" style="background-image: url('data:image/gif;base64,@cel.DefaultImage'); height: @(cel.Height)px; width: @(cel.Width)px; z-index: @cel.ZIndex; opacity: @cel.Opacity"
data-id="@cel.Id" data-id="@cel.Id"
data-fix="@cel.Fix"></div> data-index="@index"></div>
} }
</div> </div>
</article> </article>
@@ -32,4 +33,4 @@
<script> <script>
document.kisekae.load("play_space", "play_menu", @Json.Serialize(Model)) document.kisekae.load("play_space", "play_menu", @Json.Serialize(Model))
</script> </script>
} }
+1 -1
View File
@@ -6,9 +6,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<TypeScriptCompile Include="Scripts\function.ts" />
<TypeScriptCompile Include="Scripts\main.ts" /> <TypeScriptCompile Include="Scripts\main.ts" />
<TypeScriptCompile Include="Scripts\pto.ts" /> <TypeScriptCompile Include="Scripts\pto.ts" />
<TypeScriptCompile Include="Scripts\tracker.ts" />
<TypeScriptCompile Include="Scripts\utility.ts" /> <TypeScriptCompile Include="Scripts\utility.ts" />
</ItemGroup> </ItemGroup>