Created
February 19, 2017 00:11
-
-
Save kaosat-dev/7af575680e7a96f2044ae8eebbd37a84 to your computer and use it in GitHub Desktop.
regl + cyclejs (onionify) test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { run } from '@cycle/xstream-run'; | |
| import { button, div, input, | |
| makeDOMDriver, h } from '@cycle/dom'; | |
| import xs from 'xstream'; | |
| import isolate from '@cycle/isolate'; | |
| import onionify from 'cycle-onionify'; | |
| import R from 'ramda'; | |
| import {pick, mix} from 'cycle-onionify' | |
| import regl from 'regl' | |
| function domEvent(sources, selector, event){ | |
| return sources.DOM.select(selector).events(event) | |
| } | |
| function makeStateAndReducers$ (actions$, actionFns, sources) { | |
| const {init} = actionFns | |
| const init$ = xs.of(init) | |
| const elements = Object.keys(actions$).map(function (actionName$) { | |
| const name = actionName$.replace('Action$', '') | |
| const actFn = actionFns[name] | |
| const act$ = actions$[actionName$] | |
| .map(action => state => actFn(state, action)) | |
| return act$ | |
| }) | |
| const reducer$ = xs.merge(init$, ...elements) | |
| const state$ = sources.onion.state$ | |
| return {state$, reducer$} | |
| } | |
| function mergeReducers(init, components){ | |
| return xs.merge( | |
| xs.of(init), ...components.map(x=>x.onion)) | |
| } | |
| function makeDefaultReducer(defaultstate={}){ | |
| return function defaultReducer(prevState) { | |
| if (typeof prevState === 'undefined') { | |
| return defaultstate // Parent didn't provide state for the child, so initialize it. | |
| } else { | |
| return prevState // Let's just use the state given from the parent. | |
| } | |
| } | |
| } | |
| function Counter(sources) { | |
| const init = () => ({ count: 0, toggled: true, text:'yup, some text' }) | |
| const inc = (state, input) => ({...state, count: state.count + 1 }) | |
| const dec = (state, input) => ({...state, count: state.count - 1 }) | |
| const setText = (state, input) => ({...state, text: input }) | |
| const toggle = (state, input) => ({...state, toggled: !state.toggled }) | |
| const view = state => div([ | |
| div(state.count.toString()), | |
| div('Toggled: '+state.toggled), | |
| button('.toggle','toggle'), | |
| state.toggled ? div('.toggleable', [ | |
| button('.inc', '+'), | |
| button('.dec', '-'), | |
| input('.input',{attrs: {type: 'text', value:state.text}}) | |
| ]) : null | |
| ]) | |
| const _domEvent = domEvent.bind(null, sources) | |
| const incAction$ = _domEvent('.inc', 'click') | |
| const decAction$ = _domEvent('.dec', 'click') | |
| const setTextAction$ = xs.merge( | |
| _domEvent('.input', 'input'), | |
| _domEvent('.input', 'change') | |
| ) | |
| .map(e=>e.target.value) | |
| const toggleAction$ = _domEvent('.toggle', 'click') | |
| const {state$, reducer$} = makeStateAndReducers$({incAction$, decAction$, setTextAction$, toggleAction$}, {init, inc, dec, setText, toggle}, sources) | |
| return { | |
| DOM: state$.map(view), | |
| onion: reducer$ | |
| } | |
| } | |
| function GLComponent(sources){ | |
| const init = makeDefaultReducer({v1:0}) | |
| let _regl | |
| let render | |
| let canvas | |
| let initDone | |
| function prepareRender(regl){ | |
| regl.clear({ | |
| color: [0, 0, 0, 1], | |
| depth: 1 | |
| }) | |
| const draw = regl({ | |
| frag: ` | |
| precision mediump float; | |
| uniform vec4 color; | |
| void main() { | |
| gl_FragColor = color; | |
| }`, | |
| vert: ` | |
| precision mediump float; | |
| attribute vec2 position; | |
| uniform float angle; | |
| uniform vec2 offset; | |
| void main() { | |
| gl_Position = vec4( | |
| cos(angle) * position.x + sin(angle) * position.y + offset.x, | |
| -sin(angle) * position.x + cos(angle) * position.y + offset.y, 0, 1); | |
| }`, | |
| attributes: { | |
| position: [ | |
| 0.5, 0, | |
| 0, 0.5, | |
| 1, 1] | |
| }, | |
| uniforms: { | |
| // the batchId parameter gives the index of the command | |
| color: ({tick}, props, batchId) => [ | |
| Math.sin(0.02 * ((0.1 + Math.sin(batchId)) * tick + 3.0 * batchId)), | |
| Math.cos(0.02 * (0.02 * tick + 0.1 * batchId)), | |
| Math.sin(0.02 * ((0.3 + Math.cos(2.0 * batchId)) * tick + 0.8 * batchId)), | |
| 1 | |
| ], | |
| angle: ({tick}) => 0.01 * tick, | |
| offset: regl.prop('offset') | |
| }, | |
| depth: { | |
| enable: false | |
| }, | |
| count: 3 | |
| }) | |
| return draw | |
| } | |
| const initialize = function initialize (vnode) { | |
| console.log('initialize') | |
| canvas = vnode.elm | |
| _regl = regl({ | |
| canvas, | |
| }) | |
| render = prepareRender(_regl) | |
| initDone = true | |
| } | |
| const view = state => h('div.gl', [ | |
| div('stuff'), | |
| h('canvas#drawArea', { | |
| props: {width: 100, height: 100}, | |
| style:{left:`${state.left}px`, position:'absolute'}, | |
| hook: { | |
| insert: initialize | |
| } | |
| }) | |
| ]) | |
| const {state$, reducer$} = makeStateAndReducers$({}, {init}, sources) | |
| state$.addListener({next: | |
| function(state){ | |
| if(initDone){ | |
| //console.log('state',state) | |
| _regl.clear({ | |
| color: [0, 0, 0, 1] | |
| }) | |
| render({ offset: [-1, -state.v1] }) | |
| } | |
| } | |
| }) | |
| return { | |
| DOM: state$.map(view), | |
| onion: reducer$ | |
| } | |
| } | |
| function main(sources){ | |
| const init = () => ({1: {}, 2:{},gl2:{left:20}, gl:{left:100, v1:0} }) | |
| const counter1 = isolate(Counter, 1)(sources) | |
| const counter2 = isolate(Counter, 2)(sources) | |
| const counter3 = isolate(Counter, 'gna')(sources) | |
| const gl = isolate(GLComponent,'gl')(sources) | |
| const gl2 = isolate(GLComponent,'gl2')(sources) | |
| const state$ = sources.onion.state$ | |
| const reducer$ = xs.merge( | |
| mergeReducers(init, [counter1, counter2, counter3, gl, gl2]), | |
| xs.periodic(3000).map(i => function reducer(state) { | |
| return {...state, gl2:{v1:i/100.0},gl: {v1:i/200.0}} | |
| }) | |
| ) | |
| const vdom$ = xs.combine(state$, counter1.DOM, counter2.DOM, counter3.DOM, gl.DOM, gl2.DOM) | |
| .map(([ state, counter1, counter2, counter3, gl, gl2 ]) => div([ | |
| div(JSON.stringify(state, null, 4)), | |
| counter1, | |
| counter2, | |
| counter3, | |
| gl, | |
| gl2 | |
| ])) | |
| return { | |
| DOM: vdom$, | |
| onion: reducer$ | |
| } | |
| } | |
| const wrappedMain = onionify(main) | |
| run(wrappedMain, { | |
| DOM: makeDOMDriver('#app') | |
| }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment