diff --git a/.gitignore b/.gitignore
index 9051880..4cf9442 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,4 @@ node_modules
bundle.js
bundle.js.map
npm-debug.log
-
+dist
diff --git a/package.json b/package.json
index 8349736..4fad743 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,8 @@
"description": "Meander Fractal Generator",
"scripts": {
"start": "webpack serve",
- "cli": "webpack serve --mode development --open"
+ "cli": "webpack serve --mode development --open",
+ "build":"webpack build"
},
"devDependencies": {
"@babel/core": "^7.21.4",
diff --git a/src/app.tsx b/src/app.tsx
index 599a076..c769828 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -16,6 +16,7 @@ import { noteLengths, Knobs } from './knobs'
import GlobalTimer from "./util/GlobalTimer"
import { EventBus, MidiTracker } from "./util/eventBus"
+import { lerp, clamp, floorClamp, parabolic, impulse } from './util/smoothingFunctions'
const globalTimer = new GlobalTimer()
const eventBus = new EventBus()
@@ -88,20 +89,9 @@ const spawnTimer = (
eventBus.subscribe("nameEvent", (func, num) => {
if(typeof func === "function"){
func()
- } else {
- console.log("Why not func")
- debugger;
}
});
-const lerp = (a, b, t) => a + (b-a) * t
-const clamp = (val, max) => val > max ? max : val
-const floorClamp = (val, min) => val < min ? min : val
-const parabolic = (x,k) => Math.pow( 4.0*x*(1.0-x), k );
-// www.iquilezles.org/www/articles/functions/functions.htm
-const impulse = ( howSteep, x ) => {
- let h = howSteep*x;
- return h* Math.exp(1.0 - h);
-}
+
// These values may be for the BSP and not universal
const MIDI_STOP_MSG = 252
@@ -279,101 +269,101 @@ const App = (props) => {
const depthLFO = new LFO(-500, 200, 20)
+ // Redraws the canvas with the browser framerate
// window.requestAnimationFrame(function(){
// });
- // Redraws the canvas with the browser framerate
const mainLoop = () => {
updateTimers(globalTimer.getSecondsElapsed())
// console.log("myLFO", myLFO.getSin());
- // if(
- // motifModOptions.filter( (option) => { return option.optionName === "noAnimation"})[0].value == false
- // ){
- // const configMod = [
- // myLFO3.getSin() / 2,
- // myLFO3.getSin() / 3,
- // myLFO3.getSin() / 4,
- // myLFO3.getSin() / 5,
- // myLFO3.getSin() / 2,
- // myLFO3.getSin() / 3,
- // myLFO3.getSin() / 4,
- // myLFO3.getSin() / 5,
- // ]
- // dispatch({
- // type: UPDATE_ALL_MOTIFS,
- // payload: [
- // myLFO3.getSin() + configMod[0],
- // myLFO3.getSin() + configMod[1],
- // myLFO3.getSin() + configMod[2],
- // myLFO3.getSin() + configMod[3],
- // myLFO3.getSin() + configMod[4],
- // myLFO3.getSin() + configMod[5],
- // myLFO3.getSin() + configMod[6],
- // myLFO3.getSin() + configMod[7],
- // ]
- // })
- // dispatch({
- // type: UPDATE_CONFIG,
- // payload:{
- // option:
- // { optionName: 'sideLength' , min: 2 , max:1200 , value: 300 , type: 'range' },
- // value: myLFO4.getSin() / 4
- // }
- // })
- // // dispatch({
- // // type: UPDATE_CONFIG,
- // // payload:{
- // // option:
- // // { optionName: 'lineWidth' , min: 0 , max:400 , value: 10 , type: 'range' },
- // // value: myLFO4.getSin() / 2
- // // }
- // // })
+ // if(
+ // motifModOptions.filter( (option) => { return option.optionName === "animate"})[0].value == false
+ // ){
+ // const configMod = [
+ // myLFO3.getSin() / 2,
+ // myLFO3.getSin() / 3,
+ // myLFO3.getSin() / 4,
+ // myLFO3.getSin() / 5,
+ // myLFO3.getSin() / 2,
+ // myLFO3.getSin() / 3,
+ // myLFO3.getSin() / 4,
+ // myLFO3.getSin() / 5,
+ // ]
+ // dispatch({
+ // type: UPDATE_ALL_MOTIFS,
+ // payload: [
+ // myLFO3.getSin() + configMod[0],
+ // myLFO3.getSin() + configMod[1],
+ // myLFO3.getSin() + configMod[2],
+ // myLFO3.getSin() + configMod[3],
+ // myLFO3.getSin() + configMod[4],
+ // myLFO3.getSin() + configMod[5],
+ // myLFO3.getSin() + configMod[6],
+ // myLFO3.getSin() + configMod[7],
+ // ]
+ // })
+ // dispatch({
+ // type: UPDATE_CONFIG,
+ // payload:{
+ // option:
+ // { optionName: 'sideLength' , min: 2 , max:1200 , value: 300 , type: 'range' },
+ // value: myLFO4.getSin() / 4
+ // }
+ // })
+ // // dispatch({
+ // // type: UPDATE_CONFIG,
+ // // payload:{
+ // // option:
+ // // { optionName: 'lineWidth' , min: 0 , max:400 , value: 10 , type: 'range' },
+ // // value: myLFO4.getSin() / 2
+ // // }
+ // // })
- // dispatch({
- // type: UPDATE_CONFIG,
- // payload:{
- // option:
- // { optionName: 'red' , min: 0 , max:255 , value: 300 , type: 'range' },
- // value: colorLFORed.getSin()
- // }
- // })
- // dispatch({
- // type: UPDATE_CONFIG,
- // payload:{
- // option:
- // { optionName: 'green' , min: 0 , max:255 , value: 300 , type: 'range' },
- // value: colorLFOGreen.getSin(),
- // }
- // })
- // dispatch({
- // type: UPDATE_CONFIG,
- // payload:{
- // option:
- // { optionName: 'blue' , min: 0 , max:255 , value: 300 , type: 'range' },
- // value: colorLFOBlue.getSin(),
- // }
- // })
- // dispatch({
- // type: UPDATE_CONFIG,
- // payload:{
- // option: {
- // max: 20000,
- // min: 2,
- // optionName: "numSegments",
- // type: "range",
- // value: 1057,
- // },
- // value: myLFO2.getSin()
- // }
- // })
- // dispatch({
- // type: UPDATE_CONFIG,
- // payload:{
- // option: { optionName: 'depth' , min: -1000 , max:2000 , value: 1 , type: 'range' },
- // value: depthLFO.getSin()
- // }
- // })
- // }
+ // dispatch({
+ // type: UPDATE_CONFIG,
+ // payload:{
+ // option:
+ // { optionName: 'red' , min: 0 , max:255 , value: 300 , type: 'range' },
+ // value: colorLFORed.getSin()
+ // }
+ // })
+ // dispatch({
+ // type: UPDATE_CONFIG,
+ // payload:{
+ // option:
+ // { optionName: 'green' , min: 0 , max:255 , value: 300 , type: 'range' },
+ // value: colorLFOGreen.getSin(),
+ // }
+ // })
+ // dispatch({
+ // type: UPDATE_CONFIG,
+ // payload:{
+ // option:
+ // { optionName: 'blue' , min: 0 , max:255 , value: 300 , type: 'range' },
+ // value: colorLFOBlue.getSin(),
+ // }
+ // })
+ // dispatch({
+ // type: UPDATE_CONFIG,
+ // payload:{
+ // option: {
+ // max: 20000,
+ // min: 2,
+ // optionName: "numSegments",
+ // type: "range",
+ // value: 1057,
+ // },
+ // value: myLFO2.getSin()
+ // }
+ // })
+ // dispatch({
+ // type: UPDATE_CONFIG,
+ // payload:{
+ // option: { optionName: 'depth' , min: -1000 , max:2000 , value: 1 , type: 'range' },
+ // value: depthLFO.getSin()
+ // }
+ // })
+ // }
}
var elapsed = 0
diff --git a/src/components/ConfigComponent.tsx b/src/components/ConfigComponent.tsx
index 1a25742..40b4e4b 100644
--- a/src/components/ConfigComponent.tsx
+++ b/src/components/ConfigComponent.tsx
@@ -25,9 +25,12 @@ const Config = (props) => {
const dispatch = useDispatch()
const generateInputs = () => {
- return motifModOptions.map( ( option:any ,i:number ) => (
-
- ))
+ return motifModOptions.map( ( option:any ,i:number ) => {
+ console.log("Optchin", option)
+ return (
+
+ )
+ })
}
const generateMotifInputs = () => {
return range(8).map( (option:any, i:number ) =>{
diff --git a/src/service/meander.ts b/src/service/meander.ts
index e2858fc..74fcb07 100644
--- a/src/service/meander.ts
+++ b/src/service/meander.ts
@@ -72,25 +72,16 @@ export default class MeanderCanvas extends Canvas {
this.draw();
}
init(){
- // this.ctx.canvas.width = window.innerWidth;
- // this.ctx.canvas.height = window.innerHeight;
this.ctx.save()
- // console.log("i nit", this.config)
if(this.config.clearScreen){
this.ctx.fillRect (0,0,this.canvas.width, this.canvas.height)
}
- // this.ctx.translate( this.canvas.width /2 , this.canvas.height/2 )
- // this.ctx.save()
this.ctx.fillStyle = "black";
this.ctx.translate( this.canvas.width /2 , this.canvas.height/2 )
this.ctx.scale(0.15,0.15);
this.ctx.transform(1,0,0,1,0,0)
- // this.ctx.fillStyle = "black"
- // this.ctx.fillRect( 0, 0 , this.canvas.width , this.canvas.height)
-
-
// this.canvas.addEventListener('click', (evt:any) => {
// this.lastX = evt.offsetX || (evt.pageX - this.canvas.offsetLeft);
@@ -108,8 +99,6 @@ export default class MeanderCanvas extends Canvas {
}
draw(){
-
-
let savedPos = this.generateSpacing(this.config.sides).map((n:any,i:any, c:any) => {
let x = this.config.sideLength * Math.sin(n + this.config.baseRotation)
let y = this.config.sideLength * Math.cos(n + this.config.baseRotation)
@@ -130,7 +119,7 @@ export default class MeanderCanvas extends Canvas {
let numSegments = (this.config.fitToSide) ? numberOfSegments : this.config.numSegments
source =
- ( this.config.noAnimation )
+ ( !this.config.animate )
? Rx.Observable.from(range( numSegments ))
: Rx.Observable.interval(1).take(numSegments)
diff --git a/src/sliders.tsx b/src/sliders.tsx
index 7420277..0d4ba37 100644
--- a/src/sliders.tsx
+++ b/src/sliders.tsx
@@ -3,6 +3,7 @@ import { useState } from 'react';
import { useDispatch } from 'react-redux';
import { UPDATE_CONFIG, UPDATE_MOTIF } from './store/actions/canvasActions';
+// This slider is for the motif options
const useSlider = (type, min, max, defaultState, step, label, id, index) => {
const [state, setSlide] = useState(defaultState);
const dispatch = useDispatch()
@@ -25,24 +26,41 @@ const useSlider = (type, min, max, defaultState, step, label, id, index) => {
}
return props
}
-const useConfigSlider = (type, min, max, defaultState, step, label, id, index, option, onUpdate) => {
+const useConfigCheckbox = (type, min, max, defaultState, step, label, id, index, option, onUpdate) => {
const [state, setSlide] = useState(defaultState);
const dispatch = useDispatch()
-
const handleChange = e => {
let value
- if(type == "checkbox"){
+ value = e.target.checked
- value = e.target.checked
- } else {
- value = e.target.value
- }
+ setSlide(value);
+ dispatch({
+ type: UPDATE_CONFIG,
+ payload: { option: option, checked: e.target.checked }
+ })
+ }
+ const props = {
+ type,
+ id,
+ min,
+ max,
+ step,
+ checked: state,
+ onChange: handleChange
+ }
+ return props
+}
+const useConfigSlider = (type, min, max, defaultState, step, label, id, index, option, onUpdate) => {
+ const [state, setSlide] = useState(defaultState);
+ const dispatch = useDispatch()
+ const handleChange = e => {
+ let value
+ value = e.target.value
setSlide(value);
dispatch({
type: UPDATE_CONFIG,
payload: { option: option, value }
})
- // onUpdate()
}
const props = {
type,
@@ -56,11 +74,23 @@ const useConfigSlider = (type, min, max, defaultState, step, label, id, index, o
return props
}
export function ConfigSlider(props){
- const sliderProps = useConfigSlider(
+ const sliderProps = props.option.type !== 'checkbox' ? useConfigSlider(
+ props.option.type,
+ props.option.min,
+ props.option.max,
+ props.option.value,
+ 1,
+ props.option.label,
+ props.option.id,
+ props.option.index,
+ props.option,
+ props.renderCanvas,
+ )
+ : useConfigCheckbox(
props.option.type,
props.option.min,
props.option.max,
- props.option.value,
+ props.option.checked,
1,
props.option.label,
props.option.id,
@@ -68,13 +98,25 @@ export function ConfigSlider(props){
props.option,
props.renderCanvas,
);
- return (
-
-
-
-
-
- )
+ const _sliderProps = {...sliderProps, ...{checked: props.option.checked == true }}
+ if(props.option.type !== 'checkbox'){
+ return (
+
+
+
+
+
+ )
+ } else {
+ return (
+
+
+
+
+
+ )
+
+ }
}
export function MotifSlider(props){
diff --git a/src/store/reducers/canvasReducer.ts b/src/store/reducers/canvasReducer.ts
index a804aab..ebc19ec 100644
--- a/src/store/reducers/canvasReducer.ts
+++ b/src/store/reducers/canvasReducer.ts
@@ -19,35 +19,36 @@ const motif:MotifDefinition = [
]
// Default options
const config:MotifModOptions =
- [{ optionName: 'depth' , min: -400 , max:2000 , value: 1 , type: 'range' },
- { optionName: 'sides' , min: 2 , max:25 , value: 7 , type: 'range' },
- { optionName: 'lineWidth' , min: 0 , max:400 , value: 10 , type: 'range' },
- { optionName: 'sideLength' , min: 2 , max:1200 , value: 300 , type: 'range' },
- { optionName: 'baseRotation', min: 0 , max:90 , value: 0 , type: 'range' },
- { optionName: 'numSegments' , min: 2 , max:20000 , value: 30 , type: 'range' },
- { optionName: 'drawEvery' , min: 1 , max:100 , value: 1 , type: 'range' },
- { optionName: 'flip' , min: 0 , max:1 , value: false , type: 'checkbox' },
- { optionName: 'noAnimation' , min: 1 , max:9 , value: true , type: 'checkbox' },
- { optionName: 'fitToSide' , min: 0 , max:1 , value: false , type: 'checkbox' },
- { optionName: 'clearScreen' , min: 0 , max:1 , value: true , type: 'checkbox' },
- { optionName: 'red' , min: 0 , max:255 , value: 127 , type: 'range' },
- { optionName: 'green' , min: 0 , max:255 , value: 10 , type: 'range' },
- { optionName: 'blue' , min: 0 , max:255 , value: 50 , type: 'range' },
+ [{ optionName: 'depth' , min: -400 , max:2000 , value: 1 , type: 'range' },
+ { optionName: 'sides' , min: 2 , max:25 , value: 7 , type: 'range' },
+ { optionName: 'lineWidth' , min: 0 , max:400 , value: 10 , type: 'range' },
+ { optionName: 'sideLength' , min: 2 , max:1200 , value: 300 , type: 'range' },
+ { optionName: 'baseRotation', min: 0 , max:90 , value: 0 , type: 'range' },
+ { optionName: 'numSegments' , min: 2 , max:20000 , value: 30 , type: 'range' },
+ { optionName: 'drawEvery' , min: 1 , max:100 , value: 1 , type: 'range' },
+ { optionName: 'flip' , min: 0 , max:1 , checked: false , type: 'checkbox' },
+ { optionName: 'animate' , min: 1 , max:9 , checked: true , type: 'checkbox' },
+ { optionName: 'fitToSide' , min: 0 , max:1 , checked: false , type: 'checkbox' },
+ { optionName: 'clearScreen' , min: 0 , max:1 , checked: false , type: 'checkbox' },
+ { optionName: 'red' , min: 0 , max:255 , value: 127 , type: 'range' },
+ { optionName: 'green' , min: 0 , max:255 , value: 10 , type: 'range' },
+ { optionName: 'blue' , min: 0 , max:255 , value: 50 , type: 'range' },
]
export const defaultCanvasState:MotifOptionsReducerState = { motifAngles:motif, motifModOptions:config }
const updateOptionInMeanderConfig =
- ( state, payload ) => {
+ ( state, payload ) => {
return state.motifModOptions.map( configOption => {
// If its the changed option
if( configOption.optionName === payload.option.optionName ) {
// Get value from slider or checkbox
- configOption.value = ( payload.option.type === 'range' )
- ? parseInt(payload.value)
- : payload.value;
+ if(payload.option.type === 'range'){
+ configOption.value = parseInt(payload.value)
+ }
+ configOption.checked = payload.checked
}
- return configOption;
+ return configOption
})
}
const updateAllConfig =
diff --git a/src/types.ts b/src/types.ts
index 813f460..ffcb682 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -2,10 +2,18 @@ export interface MotifModOption {
optionName: string,
min: number,
max: number,
- value: number | boolean,
+ value?: number | boolean,
+ checked?: boolean,
type: string
}
-export type MotifModOptions = Array
+export interface MotifCheckboxOption {
+ optionName: string,
+ min: number,
+ max: number,
+ checked: boolean,
+ type: string
+}
+export type MotifModOptions = Array
export type MotifDefinition = number[]
export type MotifOptionsReducerState = {
diff --git a/src/util/eventBus.js b/src/util/eventBus.js
index 36a6839..b3673ce 100644
--- a/src/util/eventBus.js
+++ b/src/util/eventBus.js
@@ -1,4 +1,7 @@
// https://lwebapp.com/en/post/event-bus
+
+// each event is really a tick, we add events onto the tick
+// and iterate through all of the events on the tick
export class EventBus {
constructor() {
// initialize event list
@@ -8,10 +11,8 @@ export class EventBus {
}
// publish event
publish(eventName, ...args) {
- // console.log("publishing", eventName)
// Get all the callback functions of the current event
const callbackObject = this.eventObject[eventName];
- // console.log("Event object", this.eventObject)
if (!callbackObject) return console.warn(eventName + " not found!");
// execute each callback function
diff --git a/src/util/smoothingFunctions.js b/src/util/smoothingFunctions.js
new file mode 100644
index 0000000..cfc4023
--- /dev/null
+++ b/src/util/smoothingFunctions.js
@@ -0,0 +1,17 @@
+const lerp = (a, b, t) => a + (b-a) * t
+const clamp = (val, max) => val > max ? max : val
+const floorClamp = (val, min) => val < min ? min : val
+const parabolic = (x,k) => Math.pow( 4.0*x*(1.0-x), k );
+// www.iquilezles.org/www/articles/functions/functions.htm
+const impulse = ( howSteep, x ) => {
+ let h = howSteep*x;
+ return h* Math.exp(1.0 - h);
+}
+
+export {
+ lerp,
+ clamp,
+ floorClamp,
+ parabolic,
+ impulse,
+}
\ No newline at end of file
diff --git a/src/util/types.ts b/src/util/types.ts
index 08e45e3..adee838 100644
--- a/src/util/types.ts
+++ b/src/util/types.ts
@@ -11,7 +11,7 @@ export type CantorConfig = {
}
export type MeanderConfig = {
- noAnimation : boolean,
+ animate : boolean,
flip : boolean,
fitToSide : boolean,
sides : number,
diff --git a/src/util/util.ts b/src/util/util.ts
index f69beb6..fb099f5 100644
--- a/src/util/util.ts
+++ b/src/util/util.ts
@@ -21,7 +21,11 @@ export const hasKey = key => obj => obj[key]
export const parseFloatByKey = key => obj => Object.assign({}, obj, { [key] :parseFloat(obj[key])})
export const addOption = (acc:any, cur:any) => {
- acc[cur.optionName] = cur.value
+ if(cur.type == 'checkbox'){
+ acc[cur.optionName] = cur.checked
+ } else {
+ acc[cur.optionName] = cur.value
+ }
return acc
}
export const parseMeanderConfigToMeanderCanvasOptions =