var React = window.p5VendorJs.React; var createReactClass = window.p5VendorJs.createReactClass; var h = window.p5VendorJs.React.createElement; var ReactDOM = window.p5VendorJs.ReactDOM; // var AsyncTypeahead = window.p5VendorJs.AsyncTypeahead; // var swal = window.swal; if (!HTML_ID) throw "Missing HTML_ID"; if (!MAKE_STORE_FUNCTION_NAME) throw "Missing MAKE_STORE_FUNCTION_NAME"; // if (!d3) throw "Missing d3 (https://d3js.org/d3.v5.min.js)"; var DBG = DBG || false; var DBG1 = true; // Receptor is special Neuron which reads input (letters in this case) // Receptor.ui: { cx, cy, r } // circle // Neuron: { charge, label, draw, source } // Neuron.ui: { cx, cy, rx, ry } // eclipse // Neuron.source: [ { neuron: Neuron | Receptor, atCharge }, ... ] // Receptor.neighbours: [] list of other receptors with max(receptors.charge) // makeNeuron cases: // stream: AAAAA and only A has charge then create Neuron over A and discharge and lower max charge // stream: AAAAA and receptor B has charge then create Neuron between A and B and discharge (closer to receptor with higher charge) var DEFAULT_CONFIG = { ui_output_width: 1000, ui_output_height: 300, ui_max_receptor_r: 12, ui_space_y: 30, config_anim_speed: 200, config_read_speed_multiplier: 4, config_charge_receptor_at_input: 1, config_max_receptor_charge: 1, config_max_neuron_charge: 1.5, config_discharge_per_tick: 0.1, config_discharge_max_in_new_neuron_from_one: 1, // 0.7 config_strategy_overcharge: "LEAVE_ALMOST_MAX", // "REMOVE_CHARGE" | "LEAVE_HALF_CHARGE" | "LEAVE_ALMOST_MAX" } // var DEFAULT_NEURON = { // value: '', // charge: 0, // maxCharge: DEFAULT_CONFIG.config_max_neuron_charge, // uiShape: "circle", // ui: { cx: 0, cy: 0 }, // source: [], // next: [], // } function LOG__render(listLogEntries) { // console.log("DBG", listLogEntries) return h('details', { open: false, style: { margin: "12px 0", border: "1px solid #aaa", borderRadius: "6px", padding: "12px", backgroundColor: "#eee", } }, [ h('summary', { style: { cursor: "pointer" } }, "Log"), h('div', { style: { border: "1px solid #eee", backgroundColor: "#fff" } }, [ h('table', { className: "table table-condensed table-bordered table-hover" }, [ h('thead', {}, LOG__renderTheadLog(listLogEntries)), h('tbody', {}, LOG__renderTbodyLog(listLogEntries)), ]), ]), ]); } function LOG__renderTheadLog(listLogEntries) { if (!listLogEntries.length) return null; var lastLog = listLogEntries[listLogEntries.length - 1] return [ h('tr', {}, [h('th', {}, "Lp.")] .concat( lastLog.map(function (nodeInfo) { return h('th', { style: { color: (nodeInfo.type === 'receptor') ? "orange" : "blue" }, }, "'" + nodeInfo.value + "'"); }) ) ) ]; } function LOG__renderTbodyLog(listLogEntries) { if (!listLogEntries.length) return null; return listLogEntries.map(function (log, lpLog) { return h('tr', {}, [h('th', { style: { color: "#ddd" } }, '' + (lpLog + 1) + '.')] .concat( log.map(LOG__renderCellNodeChargeLog) ) ) }) } function LOG__renderCellNodeChargeLog(nodeInfo) { if (null === nodeInfo) return null; return h('td', { style: { color: (nodeInfo.charge > 0.1) ? "#000" : "#aaa", backgroundColor: (nodeInfo.charge > 0) ? ((nodeInfo.type === 'receptor') ? "#fa0" : "#00d0ff") : "none", }, }, nodeInfo.charge.toFixed(2)); } var NeuronView = createReactClass({ _inputNode: null, _outputNode: null, _receptor: [], _neuron: [], _store: null, _log: [], getInitialState: function () { return Object.assign({}, DEFAULT_CONFIG, this.getStateFromStore(), { inputText: this.props.initialData || '', // TODO: INITIAL_DATA animLastLetter: null, selectedReceptorIdx: null, }); }, componentDidMount: function () { this._unsubscribe = this.props.store.subscribe(this.storeUpdated) this.props.store.dispatch({ type: 'INIT', inputText: this.state.inputText, config: this.state }) }, componentWillUnmount: function () { if (this._unsubscribe) this._unsubscribe() }, storeUpdated: function () { DBG && console.log('DBG:NeuronView:storeUpdated'); this._log.push(this.props.store.getNodesChargeState()) this.setState(this.getStateFromStore()) }, getStateFromStore: function () { var state = this.props.store.getState(); return { doAnim: state.doAnim, animPos: state.animPos, inputReadPos: state.inputReadPos, uiOutputHeight: state.uiOutputHeight, }; }, handleChangeInput: function (event) { this.setState({ inputText: event.target.value, }) }, setInputRet: function (reactEl) { this._inputNode = reactEl; }, setOutputRet: function (reactEl) { this._outputNode = reactEl; }, handleReset: function (event) { event.preventDefault(); DBG && console.log('DBG:NeuronView:handleReset...'); this._log = [] this.props.store.dispatch({ type: 'INIT', inputText: this.state.inputText, config: this.state }) }, handlePause: function (event) { event.preventDefault(); this.props.store.dispatch({ type: 'PAUSE' }) }, handlePlay: function (event) { event.preventDefault(); this.props.store.dispatch({ type: 'PLAY' }) }, getReceptor: function (char) { var receptor = this._receptor.filter(function (receptor) { return (char == receptor.value); }); if (!receptor.length) throw "BUG: no input receptor found for char '" + char + "'"; // TODO: create on demand? return receptor[0]; }, selectReceptor: function (receptorIdx) { this.setState({ selectedReceptorIdx: receptorIdx }) }, handleClickReceptor: function (event) { var data_receptor_idx = event.target.getAttribute('data_receptor_idx') DBG && console.log('DBG:NeuronView:handleClickReceptor', { data_receptor_idx, target: event.target }); this.selectReceptor(data_receptor_idx) }, // renderConnections: function (neuron, idx) { // DBG && console.log('DBG:NeuronView:renderConnections', { neuron, p1: neuron.source[0].ui, p2: (neuron.source.length > 1) ? neuron.source[1].ui : null }); // return h('g', {}, [ // h('line', { // x1: neuron.source[0].ui.cx, y1: neuron.source[0].ui.cy, // x2: neuron.ui.cx, y2: neuron.ui.cy, // style: { // stroke: "#46b8da", // strokeWidth: "2" // }, // }), // (neuron.source.length > 1) // ? h('line', { // x1: neuron.source[1].ui.cx, y1: neuron.source[1].ui.cy, // x2: neuron.ui.cx, y2: neuron.ui.cy, // style: { // stroke: "#46b8da", // strokeWidth: "2" // }, // }) // : null, // ]); // }, renderConnection: function (conn, idx) { var uiPos = this.getConnectionUIPos(conn) DBG && console.log('DBG:NeuronView:renderConnection', { conn, uiPos }); return h('g', { p5_node_id: "conn-idx-" + idx }, [ h('line', Object.assign({}, uiPos, { style: { stroke: "#46b8da", strokeWidth: "2" }, })), ]); // fromIdx: 0 // fromType: "receptor" // timesCreated: 1 // toIdx: 2 }, getConnectionUIPos: function (conn) { // @return { x1, y1, x2, y2 } // fromIdx: 0 // fromType: "receptor" // timesCreated: 1 // toIdx: 2 switch (conn.fromType) { case 'receptor': return this.getConnectionUIPosFromReceptor(conn.fromIdx, conn.toIdx); case 'neuron': return this.getConnectionUIPosFromNeuron(conn.fromIdx, conn.toIdx); default: { DBG && console.warn("Not implemented render charge type '" + conn.fromType + "'", { conn }) return null; } } }, getConnectionUIPosFromReceptor: function (fromIdx, toIdx) { // @return { x1, y1, x2, y2 } var sourceNode = this.props.store.getReceptor(fromIdx) var destNode = this.props.store.getNeuron(toIdx) DBG && console.log('DBG:NeuronView:getConnectionUIPosFromReceptor', { fromIdx, toIdx, sourceNode: sourceNode, destNode: destNode }); if (!sourceNode || !destNode) { DBG && console.warn("Missing source or dest node at renderConnection", { fromIdx, toIdx }) return null; } return { x1: sourceNode.ui.cx, y1: sourceNode.ui.cy, x2: destNode.ui.cx, y2: destNode.ui.cy, }; }, getConnectionUIPosFromNeuron: function (fromIdx, toIdx) { // @return { x1, y1, x2, y2 } var sourceNode = this.props.store.getNeuron(fromIdx) var destNode = this.props.store.getNeuron(toIdx) DBG && console.log('DBG:NeuronView:getConnectionUIPosFromNeuron', { fromIdx, toIdx, sourceNode: sourceNode, destNode: destNode }); if (!sourceNode || !destNode) { DBG && console.warn("Missing source or dest node at getConnectionUIPosFromNeuron", { fromIdx, toIdx }) return null; } return { x1: sourceNode.ui.cx, y1: sourceNode.ui.cy, x2: destNode.ui.cx, y2: destNode.ui.cy, }; }, renderCharge: function (charge, idx) { DBG && console.log("DBG:NeuronView:renderCharge", { charge, idx }) // charge: 1 // nodeIdx: 9 // nodeType: "connection" switch (charge.nodeType) { case 'receptor': return this.renderChargeOnReceptor(charge.nodeIdx, charge.charge, idx); case 'neuron': return this.renderChargeOnNeuron(charge.nodeIdx, charge.charge, idx); case 'connection': return this.renderChargeOnConnection(charge.nodeIdx, charge.charge, idx); case 'dbl_conn': return this.renderChargeOnDoubleConnection(charge.nodeIdx, charge.charge, idx); default: { DBG && console.warn("Not implemented render charge type '" + charge.nodeType + "'", { charge, idx }) return null; } } }, renderChargeOnReceptor: function (idx, charge, chargeIdx) { var sourceNode = this.props.store.getReceptor(idx) if (!sourceNode) { DBG && console.warn("Missing source node at renderChargeOnReceptor", { charge, idx }) return null; } var uiNodePos = sourceNode.ui var uiPos = { cx: uiNodePos.cx, cy: uiNodePos.cy, } DBG && console.log("DBG:NeuronView:renderChargeOnReceptor", { uiNodePos, uiPos }) return h('g', { p5_node_id: "charge-idx-" + chargeIdx, p5_node_type: "charge-on-receptor" }, [ h('circle', Object.assign({}, uiPos, { r: sourceNode.ui.r + 3, stroke: "#00d0ff", fill: "none", strokeWidth: "3px", })) ]); }, renderChargeOnNeuron: function (idx, charge, chargeIdx) { var sourceNode = this.props.store.getNeuron(idx) if (!sourceNode) { DBG && console.warn("Missing source node at renderChargeOnNeuron", { charge, idx }) return null; } var uiNodePos = sourceNode.ui var uiPos = { cx: uiNodePos.cx, cy: uiNodePos.cy, } DBG && console.log("DBG:NeuronView:renderChargeOnNeuron", { uiNodePos, uiPos }) return h('g', { p5_node_id: "charge-idx-" + chargeIdx, p5_node_type: "charge-on-neuron" }, [ h('circle', Object.assign({}, uiPos, { r: sourceNode.ui.ry + 3, stroke: "#00d0ff", fill: "none", strokeWidth: "3px", })) ]); }, renderChargeOnConnection: function (idx, charge, chargeIdx) { var sourceNode = this.props.store.getConnection(idx) if (!sourceNode) { DBG && console.warn("Missing source node at renderChargeOnConnection", { charge, idx }) return null; } var uiConnPos = this.getConnectionUIPos(sourceNode) // @return { x1, y1, x2, y2 } var uiPos = { cx: Math.min(uiConnPos.x1, uiConnPos.x2) + Math.abs((uiConnPos.x1 - uiConnPos.x2) / 2), cy: Math.min(uiConnPos.y1, uiConnPos.y2) + Math.abs((uiConnPos.y1 - uiConnPos.y2) / 2), } DBG && console.log("DBG:NeuronView:renderChargeOnConnection", { uiConnPos, uiPos }) // sourceNode: { fromType: 'receptor', fromIdx: overcharged.idx, toIdx: idxNewNeuron, timesCreated: 1 } return h('g', { p5_node_id: "charge-idx-" + chargeIdx, p5_node_type: "charge-on-conn" }, [ h('circle', Object.assign({}, uiPos, { r: 5, stroke: "#00d0ff", fill: "#fbfbfb", strokeWidth: "3px", })) ]); }, renderChargeOnDoubleConnection: function (idx, charge, chargeIdx) { var connNode = this.props.store.getDoubleConnection(idx) var chargeNode = this.props.store.getCharge(chargeIdx) var connFromNode = this.props.store.getConnection(connNode.connIdx[0]) var connToNode = this.props.store.getConnection(connNode.connIdx[1]) DBG1 && console.warn("TODO:NeuronView:renderChargeOnDoubleConnection", { idx, charge, chargeIdx, connNode, chargeNode }) return h(React.Fragment, {}, [ this.renderChargeOnConnection(connNode.connIdx[0], chargeNode.fromCharge, '' + chargeIdx + '-from'), this.renderChargeOnConnection(connNode.connIdx[1], chargeNode.toCharge, '' + chargeIdx + '-to'), ]); // if (!sourceNode) { // DBG && console.warn("Missing source node at renderChargeOnConnection", { charge, idx }) // return null; // } // var uiConnPos = this.getConnectionUIPos(sourceNode) // @return { x1, y1, x2, y2 } // var uiPos = { // cx: Math.min(uiConnPos.x1, uiConnPos.x2) + Math.abs((uiConnPos.x1 - uiConnPos.x2) / 2), // cy: Math.min(uiConnPos.y1, uiConnPos.y2) + Math.abs((uiConnPos.y1 - uiConnPos.y2) / 2), // } // DBG && console.log("DBG:NeuronView:renderChargeOnConnection", { uiConnPos, uiPos }) // // sourceNode: { fromType: 'receptor', fromIdx: overcharged.idx, toIdx: idxNewNeuron, timesCreated: 1 } // return h('g', { p5_node_id: "charge-idx-" + chargeIdx, p5_node_type: "charge-on-conn" }, [ // h('circle', Object.assign({}, uiPos, { // r: 5, // stroke: "#00d0ff", // fill: "#fbfbfb", // strokeWidth: "3px", // })) // ]); }, renderNeuron: function (neuron, idx) { var chargeValue = this.props.store.getNeuronCharge(idx) // var chargePr = (100 * chargeValue) / this.state.config_max_neuron_charge; var chargePr = (100 * chargeValue) / neuron.maxCharge; var fontColor = (chargePr < 30) ? "#000" : "#fff"; return h('g', { p5_node_id: "neuron-idx-" + idx, p5_max_charge: neuron.maxCharge }, [ h(neuron.uiShape, Object.assign({}, neuron.ui, { stroke: "#46b8da", strokeWidth: 1, fill: (chargePr > 100) ? "#f00" : "hsl(194, 67%, " + (100 - chargePr) + "%)", // data_neuron_idx: idx, // onClick: this.handleClickNeuron, style: { cursor: "pointer" }, }), [ h('title', {}, this.viewNeuronTitle(neuron.value)), ]), h('text', { x: neuron.ui.cx, y: neuron.ui.cy + 1, fill: fontColor, dominantBaseline: "middle", textAnchor: "middle", style: { fontSize: "10px", cursor: "pointer" }, // data_neuron_idx: idx, // onClick: this.handleClickNeuron, }, chargeValue.toFixed(1)), ]); }, viewNeuronValue: function (value) { return value .replace(new RegExp("\n", "g"), "\\n") .replace(new RegExp("\t", "g"), "\\t") .replace(new RegExp(" ", "g"), "_") ; }, viewNeuronTitle: function (value) { return this.viewNeuronValue(value); }, renderReceptor: function (receptor, idx) { // orange: hsl(40, 100%, 50%) --> hsl(0, 100%, 50%) -> red (overcharged) // var totalReceptors = this.state.receptor.length; // var cx = Math.ceil(this.state.ui_output_width / ( totalReceptors + 1 )); // var r = Math.min(Math.ceil(this.state.ui_output_width / ( totalReceptors + 10 ) / 2), this.state.ui_max_receptor_r); // DBG && console.log('DBG:NeuronView:renderReceptor', { receptor, idx, totalReceptors, r }); // var xCenter = cx + cx * idx - r; var charge = this.props.store.getReceptorCharge(idx) // receptor.charge var chargePr = (100 * charge) / this.state.config_max_receptor_charge // var shapeColor = (chargePr > 100) ? "#f00" : "hsl(194, 67%, " + (100 - chargePr) + "%)"; // blue -> dark blue -> red var shapeColor = (chargePr > 100) ? "#f00" : "hsl(" + (40 - chargePr * 2 / 5).toFixed() + ", 100%, 50%)" // orange -> dark orange -> red var fontColor = "#fff" // (chargePr < 50) ? "#000" : "#fff"; // this.state.config_max_receptor_charge = 100% // charge = x% (max 100) return h('g', { p5_node_id: "receptor-idx-" + idx }, [ h(receptor.uiShape, Object.assign({}, receptor.ui, { stroke: "#46b8da", strokeWidth: 1, fill: shapeColor, data_receptor_idx: idx, onClick: this.handleClickReceptor, style: { cursor: "pointer" }, }), [ h('title', {}, this.viewReceptorTitle(receptor.value)), ]), h('text', { x: receptor.ui.cx, y: receptor.ui.cy + 1, fill: fontColor, dominantBaseline: "middle", textAnchor: "middle", style: { fontSize: "10px", cursor: "pointer" }, data_receptor_idx: idx, onClick: this.handleClickReceptor, }, charge.toFixed(1)), h('text', { x: receptor.ui.cx, y: receptor.ui.cy - 20, fill: "#000", dominantBaseline: "middle", textAnchor: "middle", style: { fontSize: "10px", cursor: "pointer" }, data_receptor_idx: idx, onClick: this.handleClickReceptor, }, this.viewReceptorLetter(receptor.value)), ]); }, viewReceptorLetter: function (letter) { switch (letter) { case "\t": return "\\t"; case " ": return "_"; case "\n": return "\\n"; default: return letter; } }, viewReceptorTitle: function (letter) { switch (letter) { case "\t": return "tab"; case " ": return "space"; case "\n": return "new line"; default: return letter; } }, renderReceptorInfo: function () { if (null === this.state.selectedReceptorIdx) return null; var receptor = this._receptor[this.state.selectedReceptorIdx]; return h('div', {}, [ "Receptor: '" + this.viewReceptorTitle(receptor.value) + "' charge('" + receptor.charge.toFixed(2) + "')", ]); }, renderAllReceptorInfo: function () { var state = this.props.store.getState() return h('div', {}, state.receptor.map(this.renderAllReceptorInfo_item)); }, renderAllReceptorInfo_item: function (receptor, idx) { var charge = this.props.store.getReceptorCharge(idx) return h('div', {}, ["Receptor: '" + this.viewReceptorTitle(receptor.value) + "' charge('" + charge.toFixed(2) + "')"]); }, renderAllNeuronInfo: function () { var state = this.props.store.getState() return h('div', {}, state.neuron.map(this.renderAllNeuronInfo_item)); }, renderAllNeuronInfo_item: function (neuron, idx) { var charge = this.props.store.getNeuronCharge(idx) return h('div', {}, ["Neuron: '" + neuron.value + "' charge('" + charge.toFixed(2) + "')"]); }, renderInput: function () { return h('details', { open: true, style: { margin: "12px 0", border: "1px solid #aaa", borderRadius: "6px", padding: "12px", backgroundColor: "#eee", } }, [ h('summary', { style: { cursor: "pointer" } }, "Input"), h('textarea', { ref: this.setInputRet, onChange: this.handleChangeInput, value: this.state.inputText, rows: 10, style: { width: "100%", padding: "12px", marginTop: "6px", backgroundColor: "#fff", }, }), ]); }, renderConfig: function () { DBG && console.log("DBG:NeuronView:renderConfig", { state: this.state }) return h('details', { open: true, style: { margin: "12px 0", border: "1px solid #aaa", borderRadius: "6px", padding: "12px", backgroundColor: "#eee", } }, [ h('summary', { style: { cursor: "pointer" } }, "Config"), h('div', { style: { padding: "12px", backgroundColor: "#fff", } }, [ h('div', {}, "Anim speed:"), h('input', { className: "form-control input-sm", type: "number", value: this.state.config_anim_speed, name: "config_anim_speed", onChange: this.handleChangeConfig, }), h('div', { style: { marginTop: "12px" } }), h('div', {}, "Read speed (anim speed multiplier):"), h('input', { className: "form-control input-sm", type: "number", value: this.state.config_read_speed_multiplier, name: "config_read_speed_multiplier", onChange: this.handleChangeConfig, }), h('div', { style: { marginTop: "12px" } }), h('div', {}, "Charge receptor at input:"), h('input', { className: "form-control input-sm", type: "number", value: this.state.config_charge_receptor_at_input, name: "config_charge_receptor_at_input", onChange: this.handleChangeConfig, }), h('div', { style: { marginTop: "12px" } }), h('div', {}, "Max receptor charge:"), h('input', { className: "form-control input-sm", type: "number", value: this.state.config_max_receptor_charge, name: "config_max_receptor_charge", onChange: this.handleChangeConfig, }), h('div', { style: { marginTop: "12px" } }), h('div', {}, "Max neuron charge:"), h('input', { className: "form-control input-sm", type: "number", value: this.state.config_max_neuron_charge, name: "config_max_neuron_charge", onChange: this.handleChangeConfig, }), h('div', { style: { marginTop: "12px" } }), h('div', {}, "Discharge per tick:"), h('input', { className: "form-control input-sm", type: "number", step: "0.1", value: this.state.config_discharge_per_tick, name: "config_discharge_per_tick", onChange: this.handleChangeConfig, }), h('div', { style: { marginTop: "12px" } }), // config_strategy_overcharge: "LEAVE_HALF_CHARGE", // "REMOVE_CHARGE" | "LEAVE_HALF_CHARGE" | "LEAVE_ALMOST_MAX" h('div', {}, "Overcharge strategy:"), h('select', { className: "form-control input-sm", type: "number", step: "0.1", value: this.state.config_strategy_overcharge, name: "config_strategy_overcharge", onChange: this.handleChangeConfig, }, ["REMOVE_CHARGE", "LEAVE_HALF_CHARGE", "LEAVE_ALMOST_MAX"].map(function (strategy) { return h('option', { value: strategy }, strategy); })), ]), ]); }, handleChangeConfig: function (event) { var value = event.target.value; var name = event.target.getAttribute('name'); var state = this.state; state[name] = value; this.setState(state); }, renderLog: function () { return LOG__render(this._log) }, handleRefreshLog: function () { if (!this._log.length) return; var lastLog = this._log[this._log.length - 1] console.table( [ lastLog.receptor.map(function (node) { return "R:'" + node.value + "'"; }) .concat( lastLog.neuron.map(function (node) { return "N:'" + node.value + "'"; }) ) ].concat( this._log.map(function (log) { return log.receptor.map(function (node) { return node.charge }) .concat( log.neuron.map(function (node) { return node.charge }) ) }) ) ) }, render: function () { DBG1 && console.log("DBG:NeuronView:render", { state: this.state, receptor: [].concat(this.props.store.getListReceptor()), neuron: [].concat(this.props.store.getListNeuron()), connection: [].concat(this.props.store.getListConnection()), charge: [].concat(this.props.store.getListCharge()), }); var state = this.props.store.getState() return h('div', {}, [ h('table', { className: "table", p5_node_id: "p5-neuron-output-table" }, [ h('tbody', {}, [ h('tr', {}, [ h('td', { style: { width: this.state.ui_output_width + 20 } }, [ h('svg', { ref: this.setOutputRet, height: this.state.uiOutputHeight, width: this.state.ui_output_width, style: { border: "1px solid #eee" } }, [ state.connection.map(this.renderConnection), state.receptor.map(this.renderReceptor), state.neuron.map(this.renderNeuron), state.charge.map(this.renderCharge), ]), h('div', { style: { padding: "6px", border: "1px solid #eee", } }, [ h('b', {}, "Input: "), h('span', {}, this.state.inputText.substr(0, this.state.inputReadPos)), h('span', { style: { color: "#ddd" } }, this.state.inputText.substr(this.state.inputReadPos)), ]), ]), h('td', { style: { verticalAlign: "top" } }, [ // this.renderReceptorInfo(), this.renderAllReceptorInfo(), this.renderAllNeuronInfo(), ]), ]), ]), ]), h('div', {}, [ h('button', { className: "btn btn-primary", onClick: this.handleReset }, "Uruchom"), " ", " (animPos:" + this.state.animPos + ") ", " ", state.doAnim ? h('button', { className: "btn btn-default", onClick: this.handlePause }, [h('i', { className: "glyphicon glyphicon-pause" }), "Stop"]) : h('button', { className: "btn btn-default", onClick: this.handlePlay }, [h('i', { className: "glyphicon glyphicon-play" }), "Start"]) , h('button', { className: "btn btn-default", onClick: this.handleRefreshLog }, [h('i', { className: "glyphicon glyphicon-refresh" }), " ", "Log"]) ]), this.renderLog(), h('table', { className: "table" }, [ h('tbody', {}, [ h('tr', {}, [ h('td', { style: { width: "50%" } }, [ this.renderInput(), ]), h('td', { style: { width: "50%" } }, [ this.renderConfig(), ]), ]), ]), ]), h('div', {}, [ "TODO: receptory...", ]), ]); } }); // export default NeuronView ReactDOM.render(h(NeuronView, { store: global[MAKE_STORE_FUNCTION_NAME](), initialData: INITIAL_DATA || "", }), document.getElementById(HTML_ID))