Implement edge highlighting and finished state

This commit is contained in:
Dennis Schoepf 2021-08-01 22:39:51 +02:00
parent 3633b32b3f
commit 748e1e0739
8 changed files with 141 additions and 11 deletions

View file

@ -23,8 +23,12 @@
<button type="button" id="message-confirm">Weiter</button> <button type="button" id="message-confirm">Weiter</button>
</div> </div>
<div id="info-message"> <div id="info-message">
<div id="info-message-header">
<h2 id="info-message-headline">Test</h2> <h2 id="info-message-headline">Test</h2>
<img id="info-message-img" src="" />
</div>
<div id="info-message-contents">Test</div> <div id="info-message-contents">Test</div>
<a id="info-message-link" href="" target="_blank">Check this out on Github</a>
<div id="info-message-close"> <div id="info-message-close">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path <path

View file

@ -50,6 +50,10 @@ export class DetailScene {
this.revealableObjects.every((revObj) => revObj.wasInteractedWith) && this.revealableObjects.every((revObj) => revObj.wasInteractedWith) &&
!(store.getState().companionState === CompanionState.ACTIVE) !(store.getState().companionState === CompanionState.ACTIVE)
) { ) {
store.setState((state) => ({
finishedSubProjects: [...state.finishedSubProjects, state.currentSubproject],
}));
store.getState().addUserMessage({ store.getState().addUserMessage({
text: "Yaay! You've found all of the important parts of this part of the repository. You will be returned to the subproject overview now. Pick the next subproject you want to take a look at there.", text: "Yaay! You've found all of the important parts of this part of the repository. You will be returned to the subproject overview now. Pick the next subproject you want to take a look at there.",
inputWanted: false, inputWanted: false,

View file

@ -6,9 +6,12 @@ import store from '../store';
import { generateEdges } from '../helpers'; import { generateEdges } from '../helpers';
import { Scenes } from './scenes'; import { Scenes } from './scenes';
import projectMetadata from '../../metadata/project.json'; import projectMetadata from '../../metadata/project.json';
import { playerHead$ } from '../area';
import { Area } from '../types';
export class OverviewScene { export class OverviewScene {
player: Player; player: Player;
playerHead: Area;
edges: Edge[]; edges: Edge[];
constructor() { constructor() {
@ -29,12 +32,18 @@ export class OverviewScene {
const dist = mp5.dist(mp5.mouseX, mp5.mouseY, edge.x, edge.y); const dist = mp5.dist(mp5.mouseX, mp5.mouseY, edge.x, edge.y);
if (dist < edge.r) { if (dist < edge.r) {
store.getState().setProjectMetadata(edge.name); store.getState().setProjectMetadata(edge.name);
store.setState({ currentScene: Scenes.DETAIL }); store.setState({ currentSubproject: edge.name, currentScene: Scenes.DETAIL });
} }
}); });
} }
private drawLocations() { private drawLocations() {
this.edges.forEach((edgeShape) => edgeShape.draw()); this.edges.forEach((edgeShape) => {
if (store.getState().finishedSubProjects.some((fsp) => fsp === edgeShape.name)) {
edgeShape.finished = true;
}
edgeShape.draw();
});
} }
} }

View file

@ -1,4 +1,5 @@
import { mp5 } from '../../main'; import { mp5 } from '../../main';
import { areasColliding, playerHead$ } from '../area';
import { colors } from '../constants/colors'; import { colors } from '../constants/colors';
export class Edge { export class Edge {
@ -7,18 +8,58 @@ export class Edge {
r: number; r: number;
name: string; name: string;
currentSize: number;
maxSize: number;
isHovered: boolean;
hoverColor: any;
finished: boolean;
constructor({ x, y, r, name }: { x: number; y: number; r: number; name: string }) { constructor({ x, y, r, name }: { x: number; y: number; r: number; name: string }) {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.r = r; this.r = r;
this.name = name; this.name = name;
this.maxSize = r * 2 + 20;
this.currentSize = r * 2;
this.hoverColor = mp5.color(colors.red);
this.hoverColor.setAlpha(200);
playerHead$.subscribe((playerHead) => {
this.isHovered = areasColliding(playerHead, { x: this.x, y: this.y, w: this.r * 2 });
});
} }
draw() { draw() {
mp5.fill(mp5.color(colors.grey)); if (this.finished) {
mp5.fill(mp5.color(colors.greyLight));
mp5.ellipse(this.x, this.y, this.r * 2); mp5.ellipse(this.x, this.y, this.r * 2);
mp5.textSize(20); mp5.textSize(20);
mp5.fill(0); mp5.fill(mp5.color(colors.grey));
mp5.text(this.name, this.x, this.y); mp5.text(`packages/${this.name}`, this.x - this.r / 2, this.y);
} else {
mp5.fill(mp5.color(colors.grey));
if (this.isHovered) {
mp5.fill(mp5.color(this.hoverColor));
if (this.currentSize < this.maxSize) {
this.currentSize++;
} else {
this.currentSize = this.maxSize;
}
} else {
if (this.currentSize > this.r * 2) {
this.currentSize--;
} else {
this.currentSize = this.r * 2;
}
}
mp5.ellipse(this.x, this.y, this.currentSize);
mp5.textSize(20);
mp5.fill(mp5.color(colors.black));
mp5.text(`packages/${this.name}`, this.x - this.r / 2, this.y);
}
} }
} }

View file

@ -122,6 +122,8 @@ export class Revealable {
store.getState().addInfoMessage({ store.getState().addInfoMessage({
headline: this.name, headline: this.name,
innerHTML: this.contents, innerHTML: this.contents,
imgUrl: this.imageUrl,
url: this.url,
}); });
} }
} }

View file

@ -6,9 +6,11 @@ import project from '../metadata/project.json';
import { InfoMessageType } from './ui/info'; import { InfoMessageType } from './ui/info';
import { RevealableInterface, RevealableTypes } from './sketchObjects/Revealable'; import { RevealableInterface, RevealableTypes } from './sketchObjects/Revealable';
import { getRevealablesforSubproject } from './helpers'; import { getRevealablesforSubproject } from './helpers';
import { SubProject } from './types';
export interface State { export interface State {
currentScene: Scenes; currentScene: Scenes;
currentSubproject?: string;
companionState: CompanionState; companionState: CompanionState;
infoMessageShown: boolean; infoMessageShown: boolean;
infoMessages: InfoMessageType[]; infoMessages: InfoMessageType[];
@ -16,12 +18,14 @@ export interface State {
userMessages: CompanionMessage[]; userMessages: CompanionMessage[];
addUserMessage: (newMessage: CompanionMessage) => void; addUserMessage: (newMessage: CompanionMessage) => void;
revealables: RevealableInterface[]; revealables: RevealableInterface[];
finishedSubProjects: string[];
setProjectMetadata: (projectName: string) => void; setProjectMetadata: (projectName: string) => void;
} }
const store = create<State>( const store = create<State>(
devtools((set) => ({ devtools((set) => ({
currentScene: Scenes.OVERVIEW, currentScene: Scenes.OVERVIEW,
currentSubproject: null,
companionState: CompanionState.IDLE, companionState: CompanionState.IDLE,
infoMessageShown: false, infoMessageShown: false,
infoMessages: [], infoMessages: [],
@ -33,6 +37,7 @@ const store = create<State>(
userMessages: [...state.userMessages, newMessage], userMessages: [...state.userMessages, newMessage],
})), })),
revealables: [], revealables: [],
finishedSubProjects: [],
setProjectMetadata: (projectName) => setProjectMetadata: (projectName) =>
set((state) => ({ set((state) => ({
...state, ...state,

View file

@ -3,6 +3,8 @@ import store from '../store';
export interface InfoMessageType { export interface InfoMessageType {
headline: string; headline: string;
innerHTML: string; innerHTML: string;
imgUrl?: string;
url?: string;
} }
export class InfoMessage { export class InfoMessage {
@ -10,6 +12,8 @@ export class InfoMessage {
infoMessageHeadline: HTMLElement; infoMessageHeadline: HTMLElement;
infoMessageContents: HTMLElement; infoMessageContents: HTMLElement;
infoMessageClose: HTMLElement; infoMessageClose: HTMLElement;
infoMessageImgRef: HTMLImageElement;
infoMessageLinkRef: HTMLAnchorElement;
backdrop: HTMLElement; backdrop: HTMLElement;
constructor() { constructor() {
@ -17,6 +21,8 @@ export class InfoMessage {
this.infoMessageHeadline = document.getElementById('info-message-headline'); this.infoMessageHeadline = document.getElementById('info-message-headline');
this.infoMessageContents = document.getElementById('info-message-contents'); this.infoMessageContents = document.getElementById('info-message-contents');
this.infoMessageClose = document.getElementById('info-message-close'); this.infoMessageClose = document.getElementById('info-message-close');
this.infoMessageImgRef = document.getElementById('info-message-img') as HTMLImageElement;
this.infoMessageLinkRef = document.getElementById('info-message-link') as HTMLAnchorElement;
this.backdrop = document.getElementById('backdrop'); this.backdrop = document.getElementById('backdrop');
this.backdrop.addEventListener('click', this.onBackdropClick); this.backdrop.addEventListener('click', this.onBackdropClick);
@ -32,6 +38,19 @@ export class InfoMessage {
if (state.infoMessages.length > prevState.infoMessages.length) { if (state.infoMessages.length > prevState.infoMessages.length) {
const newMessage = state.infoMessages[state.infoMessages.length - 1]; const newMessage = state.infoMessages[state.infoMessages.length - 1];
this.setContents(newMessage.headline, newMessage.innerHTML); this.setContents(newMessage.headline, newMessage.innerHTML);
if (newMessage.imgUrl) {
this.setImg(newMessage.imgUrl);
} else {
this.infoMessageImgRef.style.display = 'none';
}
if (newMessage.url) {
this.setLink(newMessage.url);
} else {
this.infoMessageLinkRef.style.display = 'none';
}
store.setState({ infoMessageShown: true }); store.setState({ infoMessageShown: true });
} }
}); });
@ -42,6 +61,16 @@ export class InfoMessage {
this.infoMessageContents.innerHTML = innerHTML; this.infoMessageContents.innerHTML = innerHTML;
} }
private setImg(imgUrl: string) {
this.infoMessageImgRef.src = imgUrl;
this.infoMessageImgRef.style.display = 'block';
}
private setLink(url: string) {
this.infoMessageLinkRef.href = url;
this.infoMessageLinkRef.style.display = 'block';
}
private show() { private show() {
this.infoMessage.style.display = 'block'; this.infoMessage.style.display = 'block';
this.backdrop.style.display = 'block'; this.backdrop.style.display = 'block';

View file

@ -149,6 +149,8 @@ button {
z-index: 10; z-index: 10;
top: 50%; top: 50%;
left: 50%; left: 50%;
min-width: 60%;
max-width: 90%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
background-color: #fff; background-color: #fff;
padding: 2.5rem 4rem; padding: 2.5rem 4rem;
@ -157,11 +159,45 @@ button {
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000),
var(--tw-shadow); var(--tw-shadow);
#info-message-header {
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-bottom: 25px;
#info-message-img {
display: none;
height: 100px;
width: 100px;
border-radius: 50%;
}
#info-message-headline { #info-message-headline {
margin: 0; margin: 0;
padding-bottom: 1rem;
text-align: center; text-align: center;
} }
}
#info-message-link {
display: none;
min-width: 20%;
padding: 6px 15px;
background-color: transparent;
border: 2px solid black;
border-radius: 5px;
font-weight: bold;
text-decoration: none;
color: black;
text-align: center;
margin-top: 50px;
float: right;
&:hover {
cursor: pointer;
background-color: black;
color: white;
}
}
#info-message-close { #info-message-close {
position: absolute; position: absolute;