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
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ <h1>Particles</h1>
<button class="menu-timeline-pause" type="button" title="pause"></button>
<input type="checkbox" id="menu-timeline-randomplay" title="random play" />
<label for="menu-timeline-randomplay"></label>
<button class="menu-timeline-settings" type="button" title="settings"></button>
<span class="menu-timeline-lockstate"></span>
</div>
<div class="menu-timeline-scrollable-container">
Expand Down
193 changes: 193 additions & 0 deletions js/ui/random-play.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import EffectConfig from '../effects/effect-config';
import { effectList } from '../effects/index';
import { parseHtml } from './util';

class RandomPlayConfig {
constructor(effects) {
this.effects = effects;
}

static getDefault() {
return new RandomPlayConfig(effectList);
}
}

class TimelineConfigDialog {
constructor() {
this.onSubmit = null;
this.onCancel = null;
const okBtnClass = 'timeline-config-dialog-ok';
const cancelBtnClass = 'timeline-config-dialog-cancel';
const effectListContainerClass = 'timeline-config-randomized-effects';
this.parentNode = document.getElementById('modal-container');
this.element = parseHtml(`
<div class="timeline-config-dialog-backdrop">
<div class="timeline-config-dialog">
<div class="timeline-config-dialog-content">
<h2>Random Play Settings</h2>
<fieldset>
<legend>Randomized effects</legend>
<ul class="${effectListContainerClass}"></ul>
</fieldset>
<button type="button" class="${okBtnClass}">Ok</button>
<button type="button" class="${cancelBtnClass}">Cancel</button>
</div>
</div>
</div>
`);
this.okBtn = this.element.querySelector(`.${okBtnClass}`);
this.cancelBtn = this.element.querySelector(`.${cancelBtnClass}`);
this.effectElements = [];

const effectListContainer = this.element.querySelector(`.${effectListContainerClass}`);
for (let i = 0; i < effectList.length; i++) {
const effect = effectList[i];
const elm = TimelineConfigDialog.createEntryForEffect(effect)
this.effectElements.push(elm);
effectListContainer.appendChild(elm);
}

this.okBtn.addEventListener('click', () => {
this.hide();
const config = this.readConfig();
this.onSubmit(config);
});
this.cancelBtn.addEventListener('click', () => {
this.hide();
this.onCancel();
});
}
static createEntryForEffect(effect) {
const elm = parseHtml(`
<li>
<input type="checkbox" checked>
<a href="#">
${effect.getDisplayName()}
</a>
</li>
`);
return elm;
}

readConfig() {
const effects = [];
for (let i = 0; i < effectList.length; i++) {
const elm = this.effectElements[i].querySelector('input[type="checkbox"]');
if (elm.checked) {
effects.push(effectList[i]);
}
}
return new RandomPlayConfig(effects);
}

show() {
this.parentNode.appendChild(this.element);
}
hide() {
this.parentNode.removeChild(this.element);
}
promptUser() {
return new Promise((res, rej) => {
this.onSubmit = res;
this.onCancel = rej;
this.show();
});
}
}

export class TimelineConfigButton {
constructor(onChange) {
this.onChange = onChange;
this.configDialog = new TimelineConfigDialog(onChange);
this.element = document.querySelector('.menu-timeline-settings');
this.element.addEventListener('click', () => {
this.configDialog.promptUser().then(onChange, () => { /* do nothing */ });
});
}
}

export class RandomplayButton {
constructor(timeline) {
this.menu = timeline.menu;
const clock = this.menu.clock;
this.onClockWrap = null;
this.config = RandomPlayConfig.getDefault();
this.element = document.getElementById('menu-timeline-randomplay');
this.element.addEventListener('click', () => {
if(this.onClockWrap === null) {
this.onClockWrap = () => this.fillRandomTimeline();
clock.addWrapListener(this.onClockWrap);
this.fillRandomTimeline();
timeline.setLocked(true);
clock.setPaused(false);
} else {
clock.removeWrapListener(this.onClockWrap);
this.onClockWrap = null;
timeline.setLocked(false);
}
});
}

setConfig(config) {
this.config = config;
}

fillRandomTimeline() {
const config = this.generateRandomTimeline();
this.menu.applyConfig(config);
this.menu.submit();
}

static trimTimeline(timeline) {
let earliest = Number.POSITIVE_INFINITY;
for (let t = 0; t < timeline.length; t++) {
const track = timeline[t];
for (let e = 0; e < track.length; e++) {
const effect = track[e];
earliest = Math.min(effect.timeBegin, earliest);
}
}
for (let t = 0; t < timeline.length; t++) {
const track = timeline[t];
for (let e = 0; e < track.length; e++) {
const effect = track[e];
effect.timeBegin -= earliest;
}
}
}

generateRandomTimeline() {
console.log(this.config);
const currentConfig = this.menu.submittedConfig;
const config = Object.assign({}, currentConfig);

config.effects = [];
config.duration = 0;

for (let i = 0; i < this.config.effects.length; i++) {
const effect = this.config.effects[i];
if (effect.getId() == "FlickrImageEffect") {
continue;
}

const timeBegin = Math.round(Math.random() * 10000);
const duration = Math.round(Math.random() * 9000 + 1000);

config.effects.push([new EffectConfig(
effect.getId(),
timeBegin,
timeBegin + duration,
1,
effect.getRandomConfig()
)]);

config.duration = Math.max(config.duration, timeBegin + duration);
}
RandomplayButton.trimTimeline(config.effects);

//TODO: does not work...
//config.effects.push([new EffectConfig("FlickrImageEffect", 0, config.duration, 1, { searchTerm: '' })]);

return config;
}
}
106 changes: 5 additions & 101 deletions js/ui/timeline.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import EffectConfigDialog from './effect-config-dialog';
import { parseHtml, clearChildNodes } from './util';
import EffectConfig from '../effects/effect-config';
import { effectList, getColorClassnameForEffect } from '../effects/index';
import { getColorClassnameForEffect } from '../effects/index';
import { RandomplayButton, TimelineConfigButton } from './random-play';

/**
*
Expand Down Expand Up @@ -493,106 +494,6 @@ class PauseButton {
}
}

class RandomplayButton {
constructor(timeline) {
this.timeline = timeline;
this.menu = timeline.menu;
this.clock = this.menu.clock
this.onClockWrap = null;
this.element = document.getElementById('menu-timeline-randomplay');
this.didJustCreateNewTimeline = false;
this.element.addEventListener('click', () => {
if (this.onClockWrap === null) {
this.start();
} else {
this.stop();
}
});
this.menu.addChangeListener(() => {
if (this.didJustCreateNewTimeline) {
this.didJustCreateNewTimeline = false;
} else {
this.stop();
}
});
}
start() {
if (this.onClockWrap === null) {
this.element.checked = true;
this.onClockWrap = () => this.fillRandomTimeline();
this.clock.addWrapListener(this.onClockWrap);
this.fillRandomTimeline();
this.timeline.setLocked(true);
this.clock.setPaused(false);
}
}
stop() {
if (this.onClockWrap !== null) {
this.element.checked = false;
this.clock.removeWrapListener(this.onClockWrap);
this.onClockWrap = null;
this.timeline.setLocked(false);
}
}

fillRandomTimeline() {
const config = RandomplayButton.generateRandomTimeline(this.menu.submittedConfig);
this.didJustCreateNewTimeline = true;
this.menu.applyConfig(config);
this.menu.submit();
}

static trimTimeline(timeline) {
let earliest = Number.POSITIVE_INFINITY;
for (let t = 0; t < timeline.length; t++) {
const track = timeline[t];
for (let e = 0; e < track.length; e++) {
const effect = track[e];
earliest = Math.min(effect.timeBegin, earliest);
}
}
for (let t = 0; t < timeline.length; t++) {
const track = timeline[t];
for (let e = 0; e < track.length; e++) {
const effect = track[e];
effect.timeBegin -= earliest;
}
}
}

static generateRandomTimeline(currentConfig) {
const config = Object.assign({}, currentConfig);

config.effects = [];
config.duration = 0;

for (let i = 0; i < effectList.length; i++) {
if (effectList[i].getId() == "FlickrImageEffect") {
continue;
}

const timeBegin = Math.round(Math.random() * 10000);
const duration = Math.round(Math.random() * 9000 + 1000);

config.effects.push([new EffectConfig(
effectList[i].getId(),
timeBegin,
timeBegin + duration,
1,
effectList[i].getRandomConfig()
)]);

config.duration = Math.max(config.duration, timeBegin + duration);
}
RandomplayButton.trimTimeline(config.effects);

//TODO: does not work...
//config.effects.push([new EffectConfig("FlickrImageEffect", 0, config.duration, 1, { searchTerm: '' })]);

return config;
}
}

class TimeDisplay {
constructor(menu) {
this.element = document.querySelector('.menu-timeline-current-time');
Expand Down Expand Up @@ -633,6 +534,9 @@ export default class Timeline {
this.timeDisplay = new TimeDisplay(menu);
this.pauseButton = new PauseButton(menu.clock);
this.randomplayButton = new RandomplayButton(this);
this.timelineConfigBtn = new TimelineConfigButton((config) => {
this.randomplayButton.setConfig(config);
});
this.positionIndicator = new TimeIndicator(menu, this.timeticks);
this.pxPerSecond = this.timeticks.getOptimalTimetickSpace();
this.timeticks.addScaleChangeListener(() => {
Expand Down
27 changes: 27 additions & 0 deletions sass/_timeline-config-dialog.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@import 'mixins/modal';
@import 'mixins/responsive';
@import 'mixins/icons';

.timeline-config-dialog-backdrop {
@include backdrop;

.timeline-config-dialog {
@include modal;

.timeline-config-randomized-effects {
list-style-type: none;
column-count: 2;
@include screensize(6) {
column-count: 3;
}
text-align: left;
margin: 0;

a {
color: initial;
text-decoration: none;
@include icon($fa-var-cog, true)
}
}
}
}
2 changes: 1 addition & 1 deletion sass/mixins/_modal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

@mixin modal() {
text-align: center;
overflow: scroll;
overflow: auto;
background-color: rgba(255, 255, 255, 0.9);
z-index: 50;

Expand Down
1 change: 1 addition & 0 deletions sass/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ $fa-font-path: "./fonts";
@import 'load-default-img-dialog';
@import 'menu';
@import 'timeline';
@import 'timeline-config-dialog';
@import 'effect-config-dialog';

$main-text-color: #333;
Expand Down