Optimize parallax

This commit is contained in:
Schmelczer András 2019-12-25 22:30:44 +01:00
parent 5a87d2db71
commit da9d0a1136
15 changed files with 135 additions and 207 deletions

33
.idea/workspace.xml generated
View file

@ -2,21 +2,21 @@
<project version="4">
<component name="ChangeListManager">
<list default="true" id="8edc47ab-1265-4111-9771-536b24cc9310" name="Default Changelist" comment="">
<change afterPath="$PROJECT_DIR$/src/framework/page-event.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/framework/page.ts" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/test.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/element-factory.ts" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/content/en.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/portfolio.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/content/hu.js" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/helper.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/helper.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/page-element.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/page-element.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/about/about.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/about/about.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/page.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/page.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/index.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/background/background.html.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/background/background.html.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/background/background.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/background/background.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/background/background.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/background/background.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/content/content.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/content/content.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/footer/footer.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/footer/footer.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/image-viewer/image-viewer.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/image-viewer/image-viewer.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/footer/footer.html.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/footer/footer.html.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/footer/footer.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/footer/footer.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/index.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/timeline/timeline-element/timeline-element.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/timeline/timeline-element/timeline-element.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/timeline/timeline.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/timeline/timeline.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/styles.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/styles.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/test.html" beforeDir="false" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" />
@ -56,16 +56,16 @@
<property name="ts.external.directory.path" value="C:\Projects\portfolio\CompiledCV\node_modules\typescript\lib" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="C:\Projects\portfolio\CompiledCV\src\static\icons" />
<recent name="$PROJECT_DIR$" />
</key>
<key name="MoveFile.RECENT_KEYS">
<recent name="C:\Projects\portfolio\CompiledCV\src" />
<recent name="C:\Projects\portfolio\CompiledCV\src\static\no-change" />
<recent name="C:\Projects\portfolio\CompiledCV\src\page\timeline" />
<recent name="C:\Projects\portfolio\CompiledCV\src\page" />
<recent name="C:\Projects\portfolio\CompiledCV\src\page\main" />
<recent name="C:\Projects\portfolio\CompiledCV\src\static\media" />
</key>
<key name="CopyFile.RECENT_KEYS">
<recent name="C:\Projects\portfolio\CompiledCV\src\static\icons" />
<recent name="$PROJECT_DIR$" />
</key>
</component>
<component name="RunDashboard">
@ -103,7 +103,8 @@
<workItem from="1577001408085" duration="15739000" />
<workItem from="1577040021962" duration="1657000" />
<workItem from="1577088438195" duration="19038000" />
<workItem from="1577271824791" duration="6178000" />
<workItem from="1577271824791" duration="7691000" />
<workItem from="1577282613892" duration="10464000" />
</task>
<servers />
</component>

View file

@ -1,94 +0,0 @@
/*{
"header": {
"name": "Schmelczer András",
"picture": "/static/me.jpg",
"about": [
"Mind a szoftverfejlesztés, mind pedig a design fontos számomra. Élvezem a problémák megoldását. Motivál, hogy hasznos és érdekes projektekben vegyek részt. Szeretek tanulni.",
"2017-ben kezdtem tanulmányaimat a Budapesti Műszaki és Gazdaságtudományi Egyetem mérnökinformatikus szakán. Azóta is minden félévemet kiváló eredménnyel zártam. Tavaly csatlakoztam a Simonyi Károly Szakkollégium schdesign köréhez. Korábban a Pécsi Tudományegyetem Gyakorló Gimnáziumába jártam, mialatt angol komplex C1-es nyelvvizsgát is szereztem.",
"Az alábbiakban összeszedtem pár izgalmasabb projektemet. A képekből természetesen csak a megoldások megjelenítés részét lehet látni. Emellett azonban igyekeztem a háttérben zajló folyamatokról is írni, hiszen az igazi kihívások általában ott rejlenek."
]
},
"timeline": [
{
"date": "2018 október - november",
"title": "Atomreaktor hűtőrendszerének szimulációja",
"picture": "/static/process-simulator.jpg",
"description": "Egy csőrendszerben lévő víz hőmérsékletének és áramlásának dinamikus számítása.",
"more": [
"A reaktorok (vízmelegítők), szivattyúk, hőcserélők adataiból és a csőrendszer felépítéséből kiszámolja az alkalmazás, hogy melyik időpillanatban hol, mennyi víz folyik, és az milyen meleg.",
"Ezt egy érdekes gráfelméleti algoritmussal, illetve egy mátrix ügyes manipulálásával éri el.",
"A szimuláció backendje python Flask-ben lett írva. Ezzel kommunikálni egy REST API-n keresztül lehet. A megjelenítés HTML5 canvas segítségével történik."
]
},
{
"date": "2018 október - november",
"title": "Gráf szerkesztő alkalmazás",
"picture": "/static/process-simulator-input.jpg",
"description": "A fentebb látható szoftverhez tartozó csőrendszert lehet vele létrehozni.",
"more": [
"A grafikus és felhasználóbarát szerkesztőprogram a végeredményt megfelelő JSON formátumba alakítja, amit a szimulátor már könnyedén fel tud dolgozni.",
"Szerkeszteni klikkeléssel, illetve drag & droppal lehetséges. Az alkalmazásban továbbá lehet a vízmelegítők, szivattyúk stb. paramétereit is beállítani.",
"Java-ban lett írva, a megjelenítést a JavaFX biztosítja."
]
},
{
"date": "2018 július - augusztus",
"title": "Közlekedés szimuláció",
"picture": "/static/sim.jpg",
"description": "A modellek Blenderben, a szimuláció Unityben készült.",
"more": [
"Egy versenyhez készült program. REST API-kon keresztül lehet a lámpák színét változtatni és a szimulációt befolyásolni, (akár még tweet-et is lehet beküldeni), az autók pedig ettől függően közlekednek, esetlegesen karamboloznak és felrobbannak.",
"Az egész érdekessége, hogy egy szerver-kliens architektúrát valósít meg, a szervezés egyszerűbbé tétele végett. Izgalmas kihívás volt a netes kommunikációból fakadó laggot kompenzálni.",
"Az összes képen látható modellt és animációt én készítettem. A scriptelés C# segítségével történt."
]
},
{
"date": "2018 június",
"title": "Színszerkesztő",
"picture": "/static/szinezo.jpg",
"description": "Egy innovatív color grader képekhez.",
"more": [
"Ki lehet választani bizonyos színeket, és a többi színt az előbbiektől lévő távolságának függvényében lehet módosítani, telitettséget, színezettségét változtatni.",
"Egyelőre proof of concept stádiumban van, viszont tervezem befejezni.",
"A színes gombokra való kattintással lehet az opciók közt váltani. Színes gombot a nagy körbe való kattintással lehet létrehozni (mozgatni pedig drag & droppal).",
{ "type": "a", "href": "/szinezo", "text": "schmelczer.hu/szinezo" }
]
},
{
"date": "2017 ősz",
"title": "Platform játék",
"picture": "/static/platform.png",
"description": "Írtam egy 3D-s játékot C-ben az SDL 1.2 segítségével.",
"more": [
"A pályák véletlenszerűen generálódnak, menthetők és rombolhatók is. A játékost repülő ellenségek üldözik.",
"Ez volt a Programozás alapjai I. tárgyhoz készített házifeladatom. Összességében egy élvezhető játék lett.",
{ "type": "a", "href": "/platform", "text": "schmelczer.hu/platform" }
]
},
{
"date": "2016 nyár",
"title": "Fényképek",
"picture": "/static/kepek.jpg",
"description": "Csináltam egy oldalt, ahol a fényképeimet lehet megnézni.",
"link": "schmelczer.hu/kepek"
},
{
"date": "2016 tavasz",
"title": "Zenére világító ledsorok",
"picture": "/static/LED.jpg",
"description": "Egy alkalmazást készítettem, amivel RGB ledsorok színét lehet a zene ritmusára változtatni.",
"more": [
"Ez volt az első nagyobb projektem, ez természetesen a megvalósítás minőségén is érezhető. Ettől független büszke vagyok a végeredményre.",
"Pythonban lett írva, amivel egy webes frontenden keresztül lehet kommunikálni. Továbbá beépítésre került egy zenelejátszó is a programba.",
"A működő rendszerről készítettem egy videót, ami alább tekinthető meg.",
{ "type": "video", "src": "static/led720.mp4" }
]
}
],
"footer": {
"email": "andras.schmelczer@schdesign.hu"
}
}
*/

View file

@ -10,3 +10,17 @@ export const randomFactory = seed => () =>
((2 ** 31 - 1) & (seed = Math.imul(48271, seed))) / 2 ** 31;
export const fixedSeedRandom = randomFactory(42);
export const choose = <T>(
list: Array<T>,
random: () => number = fixedSeedRandom
): T => list[randomInInterval(0, list.length, random)];
export const randomInInterval = (
aClosed: number,
bOpen: number,
random: () => number = fixedSeedRandom
): number => Math.floor((bOpen - aClosed) * random()) + aClosed;
export const sum = (list: ArrayLike<number>): number =>
Array.prototype.reduce.call(list, (a, sum) => a + sum, 0);

View file

@ -9,6 +9,7 @@ export abstract class PageElement {
}
protected setElement(value: HTMLElement) {
this.getElement()?.parentElement?.replaceChild(value, this.getElement());
this.element = value;
}

View file

@ -12,7 +12,7 @@ export class Page extends PageElement {
{ type: PageEventType.eventGeneratorChanged, data: this },
this
);
rootElement.append(...children.map(e => e.getElement()));
rootElement.append(...children.map(e => e.getElement()).filter(e => e));
this.giveEvent({ type: PageEventType.onLoad }, this);
}
}

View file

@ -4,6 +4,6 @@ import "./static/no-change/og-image.jpg";
import "./styles.scss";
import { create } from "./page/index";
import { portfolio } from "./content/en";
import { portfolio } from "./portfolio";
create(portfolio);

View file

@ -1,25 +1,23 @@
import { html } from "../../model/misc";
import "./background.scss";
import { fixedSeedRandom } from "../../framework/helper";
export const generate = (
count: number,
probability: number,
width: number,
color: string,
translateZ: number
color?: () => string,
height?: () => number,
transform?: () => string
): html => `
<section class="background">
${new Array(count)
.fill(0, 0, count)
.map(_ =>
fixedSeedRandom() < probability
? `<div style="width: ${width}px; height: ${width *
(fixedSeedRandom() + 0.1) *
10}px; background-color: ${color}; transform: translateZ(${translateZ}px) rotate(-20deg);"
></div>`
: `<div class="gap"></div>`
)
.join("")}
${
count > 0
? new Array(count)
.fill(0, 0, count)
.map(
_ =>
`<div style="background-color: ${color()}; height: ${height()}px; transform: ${transform()}"></div>`
)
.join("")
: ""
}
</section>
`;

View file

@ -5,19 +5,15 @@
position: absolute;
left: 0;
top: 0;
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
margin-top: -20vh;
width: 400%;
z-index: -1;
transform-style: preserve-3d;
overflow: hidden;
div {
border-radius: 10000px;
margin: 10vh 10vw;
&.gap {
visibility: hidden;
}
position: absolute;
left: 0;
top: 0;
width: 100px;
}
}

View file

@ -1,34 +1,82 @@
import { PageElement } from "../../framework/page-element";
import { generate } from "./background.html";
import { createElement } from "../../framework/helper";
import {
choose,
createElement,
randomFactory,
randomInInterval,
sum
} from "../../framework/helper";
import { PageEvent, PageEventType } from "../../framework/page-event";
export class PageBackground extends PageElement {
public constructor(
private speed: number,
count: number,
width: number,
probability: number,
color: string,
translateZ: number
) {
private colors = ["#fff9e077", "#ffd6d677"];
private blobSize = 150; // with margin
private perspective = 5;
public constructor() {
super();
this.setElement(
createElement(generate(count, probability, width, color, translateZ))
);
this.setElement(createElement(generate(0)));
}
protected handleEvent(event: PageEvent, parent: PageElement) {
if (event.type === PageEventType.onLoad) {
window.addEventListener("resize", this.resize.bind(this, parent));
this.resize(parent);
window.addEventListener("load", this.resize.bind(this, parent));
} else if (event.type === PageEventType.onBodyDimensionsChanged) {
this.resize(parent);
}
}
private resize(parent: PageElement) {
const width = parent.getElement().clientWidth;
const height = parent.getElement().clientHeight;
const siblings: Array<HTMLElement> = Array.prototype.slice
.call(parent.getElement().children)
.filter(e => e !== this.getElement());
const width = document.body.clientWidth;
const height = sum(
siblings.map(c => {
const computedStyle = window.getComputedStyle(c);
return (
c.clientHeight +
parseInt(computedStyle.marginTop) +
parseInt(computedStyle.marginBottom) +
parseInt(computedStyle.borderTopWidth) +
parseInt(computedStyle.borderBottomWidth)
);
})
);
const random = randomFactory(42);
const count = Math.round((width * height) / this.blobSize ** 2);
const randomWithKnownZ = (z: number, bound: number): number => {
const l = (bound * (this.perspective + z)) / this.perspective;
return randomInInterval(-(l / 2 - bound / 2), l / 2 + bound / 2, random);
};
this.setElement(
createElement(
generate(
count,
() => choose(this.colors, random),
() => randomInInterval(150, 750, random),
() => {
const z = randomInInterval(-5, -15, random);
return `
translateX(${randomWithKnownZ(-z, width)}px)
translateY(${randomWithKnownZ(-z, height)}px)
translateZ(${z}px)
rotate(-20deg)
`;
}
)
)
);
this.getElement().style.width = `${width}px`;
this.getElement().style.height = `${height}px`;
}
}

View file

@ -3,7 +3,7 @@ import { html } from "../../model/misc";
import "./footer.scss";
export const generate = ({ email, cv }: Footer, cvName: string): html => `
<footer>
<footer id="page-footer">
<a id="email" href="mailto:${email}">${email}</a>
<a id="cv" href="mailto:${cv}">${cvName}</a>
</footer>

View file

@ -1,8 +1,8 @@
@import "../../style/mixins";
@import "../../style/vars";
footer {
footer#page-footer {
@include card();
@include center-children();
margin: $normal-margin 0;
margin: $normal-margin auto;
}

View file

@ -11,8 +11,7 @@ export const create = ({ config, header, timeline, footer }: Portfolio) => {
new Page(
[
new PageBackground(0.1, 200, 140, 0.4, "#fff9e0aa", -15),
new PageBackground(0.15, 300, 80, 0.3, "#ffd6d6aa", -10),
new PageBackground(),
new PageHeader(header, config.aPictureOf),
new PageTimeline(timeline, config.showMore, config.showLess),
new PageFooter(footer, config.cvName),

View file

@ -1,16 +1,16 @@
import { Portfolio } from "../model/portfolio";
import { Portfolio } from "./model/portfolio";
import me from "../static/media/me-2.jpg";
import forex from "../static/media/forex.gif";
import myNotes from "../static/media/my-notes.jpg";
import processSimulator from "../static/media/process-simulator.jpg";
import processSimulatorInput from "../static/media/process-simulator-input.jpg";
import citySimulation from "../static/media/simulation.jpg";
import color from "../static/media/color.jpg";
import platform from "../static/media/platform.png";
import photos from "../static/media/photos.jpg";
import led from "../static/media/led.jpg";
import ledVideo from "../static/media/led720.mp4";
import me from "./static/media/me-2.jpg";
import forex from "./static/media/forex.gif";
import myNotes from "./static/media/my-notes.jpg";
import processSimulator from "./static/media/process-simulator.jpg";
import processSimulatorInput from "./static/media/process-simulator-input.jpg";
import citySimulation from "./static/media/simulation.jpg";
import color from "./static/media/color.jpg";
import platform from "./static/media/platform.png";
import photos from "./static/media/photos.jpg";
import led from "./static/media/led.jpg";
import ledVideo from "./static/media/led720.mp4";
export const portfolio: Portfolio = {
config: {

View file

@ -3,7 +3,7 @@
* {
margin: 0;
box-sizing: content-box;
box-sizing: border-box;
color: $normal-text-color;
hyphens: auto;
}
@ -31,13 +31,12 @@ body {
& > main {
height: 100%;
overflow-y: auto;
perspective-origin: 0 0;
overflow-x: hidden;
perspective: 5px;
& > * {
width: $body-width;
margin: $normal-margin auto 0 auto;
margin: auto;
}
}

View file

@ -1,34 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Portfolio</title>
<style>
body {
margin: 0;
}
main {
overflow: hidden;
position: relative;
}
.absolute {
position: absolute;
height: 200vh;
width: 100%;
z-index: -1;
background: rebeccapurple;
}
.static {
height: 150vh;
background: rgba(255, 255, 0, 0.5);
}
</style>
</head>
<body>
<main>
<div class="absolute"></div>
<div class="static"></div>
</main>
</body>
</html>