Neuron.php.NeuronView.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. var createReactClass = window.p5VendorJs.createReactClass;
  2. var h = window.p5VendorJs.React.createElement;
  3. var ReactDOM = window.p5VendorJs.ReactDOM;
  4. // var AsyncTypeahead = window.p5VendorJs.AsyncTypeahead;
  5. // var swal = window.swal;
  6. if (!HTML_ID) throw "Missing HTML_ID";
  7. if (!MAKE_STORE_FUNCTION_NAME) throw "Missing MAKE_STORE_FUNCTION_NAME";
  8. // if (!d3) throw "Missing d3 (https://d3js.org/d3.v5.min.js)";
  9. var DBG = DBG || false;
  10. var DBG1 = true;
  11. // Receptor is special Neuron which reads input (letters in this case)
  12. // Receptor.ui: { cx, cy, r } // circle
  13. // Neuron: { charge, label, draw, source }
  14. // Neuron.ui: { cx, cy, rx, ry } // eclipse
  15. // Neuron.source: [ { neuron: Neuron | Receptor, atCharge }, ... ]
  16. // Receptor.neighbours: [] list of other receptors with max(receptors.charge)
  17. // makeNeuron cases:
  18. // stream: AAAAA and only A has charge then create Neuron over A and discharge and lower max charge
  19. // stream: AAAAA and receptor B has charge then create Neuron between A and B and discharge (closer to receptor with higher charge)
  20. var DEFAULT_CONFIG = {
  21. ui_output_width: 1000,
  22. ui_output_height: 300,
  23. ui_max_receptor_r: 12,
  24. ui_space_y: 30,
  25. config_anim_speed: 500,
  26. config_read_speed_multiplier: 4,
  27. config_charge_receptor_at_input: 1,
  28. config_max_receptor_charge: 1,
  29. config_max_neuron_charge: 1.5,
  30. config_discharge_per_tick: 0.1,
  31. config_discharge_max_in_new_neuron_from_one: 1, // 0.7
  32. config_strategy_overcharge: "LEAVE_ALMOST_MAX", // "REMOVE_CHARGE" | "LEAVE_HALF_CHARGE" | "LEAVE_ALMOST_MAX"
  33. }
  34. var DEFAULT_NEURON = {
  35. value: '',
  36. charge: 0,
  37. maxCharge: DEFAULT_CONFIG.config_max_neuron_charge,
  38. uiShape: "circle",
  39. ui: { cx: 0, cy: 0 },
  40. source: [],
  41. next: [],
  42. }
  43. function LOG__render(listLogEntries) {
  44. // console.log("DBG", listLogEntries)
  45. return h('details', { open: false, style: { margin: "12px 0", border: "1px solid #aaa", borderRadius: "6px", padding: "12px", backgroundColor: "#eee", } }, [
  46. h('summary', { style: { cursor: "pointer" } }, "Log"),
  47. h('div', { style: { border: "1px solid #eee", backgroundColor: "#fff" } }, [
  48. h('table', { className: "table table-condensed table-bordered table-hover" }, [
  49. h('thead', {}, LOG__renderTheadLog(listLogEntries)),
  50. h('tbody', {}, LOG__renderTbodyLog(listLogEntries)),
  51. ]),
  52. ]),
  53. ]);
  54. }
  55. function LOG__renderTheadLog(listLogEntries) {
  56. if (!listLogEntries.length) return null;
  57. var lastLog = listLogEntries[listLogEntries.length - 1]
  58. return [
  59. h('tr', {},
  60. [h('th', {}, "Lp.")]
  61. .concat(
  62. lastLog.map(function (nodeInfo) {
  63. return h('th', {
  64. style: { color: (nodeInfo.type === 'receptor') ? "orange" : "blue" },
  65. }, "'" + nodeInfo.value + "'");
  66. })
  67. )
  68. )
  69. ];
  70. }
  71. function LOG__renderTbodyLog(listLogEntries) {
  72. if (!listLogEntries.length) return null;
  73. return listLogEntries.map(function (log, lpLog) {
  74. return h('tr', {},
  75. [h('th', { style: { color: "#ddd" } }, '' + (lpLog + 1) + '.')]
  76. .concat(
  77. log.map(LOG__renderCellNodeChargeLog)
  78. )
  79. )
  80. })
  81. }
  82. function LOG__renderCellNodeChargeLog(nodeInfo) {
  83. if (null === nodeInfo) return null;
  84. return h('td', {
  85. style: {
  86. color: (nodeInfo.charge > 0.1) ? "#000" : "#aaa",
  87. backgroundColor: (nodeInfo.charge > 0) ? ((nodeInfo.type === 'receptor') ? "#fa0" : "#00d0ff") : "none",
  88. },
  89. }, nodeInfo.charge.toFixed(2));
  90. }
  91. var NeuronView = createReactClass({
  92. _inputNode: null,
  93. _outputNode: null,
  94. _receptor: [],
  95. _neuron: [],
  96. _store: null,
  97. _log: [],
  98. getInitialState: function () {
  99. return Object.assign({}, DEFAULT_CONFIG, this.getStateFromStore(), {
  100. inputText: this.props.initialData || '', // TODO: INITIAL_DATA
  101. animLastLetter: null,
  102. selectedReceptorIdx: null,
  103. });
  104. },
  105. componentDidMount: function () {
  106. this._unsubscribe = this.props.store.subscribe(this.storeUpdated)
  107. this.props.store.dispatch({ type: 'INIT', inputText: this.state.inputText, config: this.state })
  108. },
  109. componentWillUnmount: function () {
  110. if (this._unsubscribe) this._unsubscribe()
  111. },
  112. storeUpdated: function () {
  113. DBG && console.log('DBG:NeuronView:storeUpdated');
  114. this._log.push(this.props.store.getNodesChargeState())
  115. this.setState(this.getStateFromStore())
  116. },
  117. getStateFromStore: function () {
  118. var state = this.props.store.getState();
  119. return {
  120. doAnim: state.doAnim,
  121. animPos: state.animPos,
  122. inputReadPos: state.inputReadPos,
  123. uiOutputHeight: state.uiOutputHeight,
  124. };
  125. },
  126. handleChangeInput: function (event) {
  127. this.setState({
  128. inputText: event.target.value,
  129. })
  130. },
  131. setInputRet: function (reactEl) { this._inputNode = reactEl; },
  132. setOutputRet: function (reactEl) { this._outputNode = reactEl; },
  133. handleReset: function (event) {
  134. event.preventDefault();
  135. DBG && console.log('DBG:NeuronView:handleReset...');
  136. this.props.store.dispatch({ type: 'INIT', inputText: this.state.inputText, config: this.state })
  137. },
  138. handlePause: function (event) {
  139. event.preventDefault();
  140. this.props.store.dispatch({ type: 'PAUSE' })
  141. },
  142. handlePlay: function (event) {
  143. event.preventDefault();
  144. this.props.store.dispatch({ type: 'PLAY' })
  145. },
  146. getReceptor: function (char) {
  147. var receptor = this._receptor.filter(function (receptor) {
  148. return (char == receptor.value);
  149. });
  150. if (!receptor.length) throw "BUG: no input receptor found for char '" + char + "'"; // TODO: create on demand?
  151. return receptor[0];
  152. },
  153. selectReceptor: function (receptorIdx) {
  154. this.setState({ selectedReceptorIdx: receptorIdx })
  155. },
  156. handleClickReceptor: function (event) {
  157. var data_receptor_idx = event.target.getAttribute('data_receptor_idx')
  158. DBG && console.log('DBG:NeuronView:handleClickReceptor', { data_receptor_idx, target: event.target });
  159. this.selectReceptor(data_receptor_idx)
  160. },
  161. // renderConnections: function (neuron, idx) {
  162. // DBG && console.log('DBG:NeuronView:renderConnections', { neuron, p1: neuron.source[0].ui, p2: (neuron.source.length > 1) ? neuron.source[1].ui : null });
  163. // return h('g', {}, [
  164. // h('line', {
  165. // x1: neuron.source[0].ui.cx, y1: neuron.source[0].ui.cy,
  166. // x2: neuron.ui.cx, y2: neuron.ui.cy,
  167. // style: {
  168. // stroke: "#46b8da",
  169. // strokeWidth: "2"
  170. // },
  171. // }),
  172. // (neuron.source.length > 1)
  173. // ? h('line', {
  174. // x1: neuron.source[1].ui.cx, y1: neuron.source[1].ui.cy,
  175. // x2: neuron.ui.cx, y2: neuron.ui.cy,
  176. // style: {
  177. // stroke: "#46b8da",
  178. // strokeWidth: "2"
  179. // },
  180. // })
  181. // : null,
  182. // ]);
  183. // },
  184. renderConnection: function (conn, idx) {
  185. var uiPos = this.getConnectionUIPos(conn)
  186. DBG && console.log('DBG:NeuronView:renderConnection', { conn, uiPos });
  187. return h('g', { p5_node_id: "conn-idx-" + idx }, [
  188. h('line', Object.assign({}, uiPos, {
  189. style: {
  190. stroke: "#46b8da",
  191. strokeWidth: "2"
  192. },
  193. })),
  194. ]);
  195. // fromIdx: 0
  196. // fromType: "receptor"
  197. // timesCreated: 1
  198. // toIdx: 2
  199. },
  200. getConnectionUIPos: function (conn) { // @return { x1, y1, x2, y2 }
  201. // fromIdx: 0
  202. // fromType: "receptor"
  203. // timesCreated: 1
  204. // toIdx: 2
  205. switch (conn.fromType) {
  206. case 'receptor': return this.getConnectionUIPosFromReceptor(conn.fromIdx, conn.toIdx);
  207. case 'neuron': return this.getConnectionUIPosFromNeuron(conn.fromIdx, conn.toIdx);
  208. default: {
  209. DBG && console.warn("Not implemented render charge type '" + conn.fromType + "'", { conn })
  210. return null;
  211. }
  212. }
  213. },
  214. getConnectionUIPosFromReceptor: function (fromIdx, toIdx) { // @return { x1, y1, x2, y2 }
  215. var sourceNode = this.props.store.getReceptor(fromIdx)
  216. var destNode = this.props.store.getNeuron(toIdx)
  217. DBG && console.log('DBG:NeuronView:getConnectionUIPosFromReceptor', { fromIdx, toIdx, sourceNode: sourceNode, destNode: destNode });
  218. if (!sourceNode || !destNode) {
  219. DBG && console.warn("Missing source or dest node at renderConnection", { fromIdx, toIdx })
  220. return null;
  221. }
  222. return {
  223. x1: sourceNode.ui.cx, y1: sourceNode.ui.cy,
  224. x2: destNode.ui.cx, y2: destNode.ui.cy,
  225. };
  226. },
  227. getConnectionUIPosFromNeuron: function (fromIdx, toIdx) { // @return { x1, y1, x2, y2 }
  228. var sourceNode = this.props.store.getNeuron(fromIdx)
  229. var destNode = this.props.store.getNeuron(toIdx)
  230. DBG && console.log('DBG:NeuronView:getConnectionUIPosFromNeuron', { fromIdx, toIdx, sourceNode: sourceNode, destNode: destNode });
  231. if (!sourceNode || !destNode) {
  232. DBG && console.warn("Missing source or dest node at getConnectionUIPosFromNeuron", { fromIdx, toIdx })
  233. return null;
  234. }
  235. return {
  236. x1: sourceNode.ui.cx, y1: sourceNode.ui.cy,
  237. x2: destNode.ui.cx, y2: destNode.ui.cy,
  238. };
  239. },
  240. renderCharge: function (charge, idx) {
  241. DBG && console.log("DBG:NeuronView:renderCharge", { charge, idx })
  242. // charge: 1
  243. // nodeIdx: 9
  244. // nodeType: "connection"
  245. switch (charge.nodeType) {
  246. case 'receptor': return this.renderChargeOnReceptor(charge.nodeIdx, charge.charge, idx);
  247. case 'neuron': return this.renderChargeOnNeuron(charge.nodeIdx, charge.charge, idx);
  248. case 'connection': return this.renderChargeOnConnection(charge.nodeIdx, charge.charge, idx);
  249. default: {
  250. DBG && console.warn("Not implemented render charge type '" + charge.nodeType + "'", { charge, idx })
  251. return null;
  252. }
  253. }
  254. },
  255. renderChargeOnReceptor: function (idx, charge, chargeIdx) {
  256. var sourceNode = this.props.store.getReceptor(idx)
  257. if (!sourceNode) {
  258. DBG && console.warn("Missing source node at renderChargeOnReceptor", { charge, idx })
  259. return null;
  260. }
  261. var uiNodePos = sourceNode.ui
  262. var uiPos = {
  263. cx: uiNodePos.cx,
  264. cy: uiNodePos.cy,
  265. }
  266. DBG && console.log("DBG:NeuronView:renderChargeOnReceptor", { uiNodePos, uiPos })
  267. return h('g', { p5_node_id: "charge-idx-" + chargeIdx, p5_node_type: "charge-on-receptor" }, [
  268. h('circle', Object.assign({}, uiPos, {
  269. r: sourceNode.ui.r + 3,
  270. stroke: "#00d0ff",
  271. fill: "none",
  272. strokeWidth: "3px",
  273. }))
  274. ]);
  275. },
  276. renderChargeOnNeuron: function (idx, charge, chargeIdx) {
  277. var sourceNode = this.props.store.getNeuron(idx)
  278. if (!sourceNode) {
  279. DBG && console.warn("Missing source node at renderChargeOnNeuron", { charge, idx })
  280. return null;
  281. }
  282. var uiNodePos = sourceNode.ui
  283. var uiPos = {
  284. cx: uiNodePos.cx,
  285. cy: uiNodePos.cy,
  286. }
  287. DBG && console.log("DBG:NeuronView:renderChargeOnNeuron", { uiNodePos, uiPos })
  288. return h('g', { p5_node_id: "charge-idx-" + chargeIdx, p5_node_type: "charge-on-neuron" }, [
  289. h('circle', Object.assign({}, uiPos, {
  290. r: sourceNode.ui.ry + 3,
  291. stroke: "#00d0ff",
  292. fill: "none",
  293. strokeWidth: "3px",
  294. }))
  295. ]);
  296. },
  297. renderChargeOnConnection: function (idx, charge, chargeIdx) {
  298. var sourceNode = this.props.store.getConnection(idx)
  299. if (!sourceNode) {
  300. DBG && console.warn("Missing source node at renderChargeOnConnection", { charge, idx })
  301. return null;
  302. }
  303. var uiConnPos = this.getConnectionUIPos(sourceNode) // @return { x1, y1, x2, y2 }
  304. var uiPos = {
  305. cx: Math.min(uiConnPos.x1, uiConnPos.x2) + Math.abs((uiConnPos.x1 - uiConnPos.x2) / 2),
  306. cy: Math.min(uiConnPos.y1, uiConnPos.y2) + Math.abs((uiConnPos.y1 - uiConnPos.y2) / 2),
  307. }
  308. DBG && console.log("DBG:NeuronView:renderChargeOnConnection", { uiConnPos, uiPos })
  309. // sourceNode: { fromType: 'receptor', fromIdx: overcharged.idx, toIdx: idxNewNeuron, timesCreated: 1 }
  310. return h('g', { p5_node_id: "charge-idx-" + chargeIdx, p5_node_type: "charge-on-conn" }, [
  311. h('circle', Object.assign({}, uiPos, {
  312. r: 5,
  313. stroke: "#00d0ff",
  314. fill: "#fbfbfb",
  315. strokeWidth: "3px",
  316. }))
  317. ]);
  318. },
  319. renderNeuron: function (neuron, idx) {
  320. var chargeValue = this.props.store.getNeuronCharge(idx)
  321. // var chargePr = (100 * chargeValue) / this.state.config_max_neuron_charge;
  322. var chargePr = (100 * chargeValue) / neuron.maxCharge;
  323. var fontColor = (chargePr < 30) ? "#000" : "#fff";
  324. return h('g', { p5_node_id: "neuron-idx-" + idx, p5_max_charge: neuron.maxCharge }, [
  325. h(neuron.uiShape, Object.assign({}, neuron.ui, {
  326. stroke: "#46b8da", strokeWidth: 1,
  327. fill: (chargePr > 100) ? "#f00" : "hsl(194, 67%, " + (100 - chargePr) + "%)",
  328. // data_neuron_idx: idx,
  329. // onClick: this.handleClickNeuron,
  330. style: { cursor: "pointer" },
  331. }), [
  332. h('title', {}, this.viewNeuronTitle(neuron.value)),
  333. ]),
  334. h('text', {
  335. x: neuron.ui.cx, y: neuron.ui.cy + 1, fill: fontColor,
  336. dominantBaseline: "middle", textAnchor: "middle",
  337. style: { fontSize: "10px", cursor: "pointer" },
  338. // data_neuron_idx: idx,
  339. // onClick: this.handleClickNeuron,
  340. }, chargeValue.toFixed(1)),
  341. ]);
  342. },
  343. viewNeuronValue: function (value) {
  344. return value
  345. .replace(new RegExp("\n", "g"), "\\n")
  346. .replace(new RegExp("\t", "g"), "\\t")
  347. .replace(new RegExp(" ", "g"), "_")
  348. ;
  349. },
  350. viewNeuronTitle: function (value) {
  351. return this.viewNeuronValue(value);
  352. },
  353. renderReceptor: function (receptor, idx) {
  354. // orange: hsl(40, 100%, 50%) --> hsl(0, 100%, 50%) -> red (overcharged)
  355. // var totalReceptors = this.state.receptor.length;
  356. // var cx = Math.ceil(this.state.ui_output_width / ( totalReceptors + 1 ));
  357. // var r = Math.min(Math.ceil(this.state.ui_output_width / ( totalReceptors + 10 ) / 2), this.state.ui_max_receptor_r);
  358. // DBG && console.log('DBG:NeuronView:renderReceptor', { receptor, idx, totalReceptors, r });
  359. // var xCenter = cx + cx * idx - r;
  360. var charge = this.props.store.getReceptorCharge(idx) // receptor.charge
  361. var chargePr = (100 * charge) / this.state.config_max_receptor_charge
  362. // var shapeColor = (chargePr > 100) ? "#f00" : "hsl(194, 67%, " + (100 - chargePr) + "%)"; // blue -> dark blue -> red
  363. var shapeColor = (chargePr > 100) ? "#f00" : "hsl(" + (40 - chargePr * 2 / 5).toFixed() + ", 100%, 50%)" // orange -> dark orange -> red
  364. var fontColor = "#fff" // (chargePr < 50) ? "#000" : "#fff";
  365. // this.state.config_max_receptor_charge = 100%
  366. // charge = x% (max 100)
  367. return h('g', { p5_node_id: "receptor-idx-" + idx }, [
  368. h(receptor.uiShape, Object.assign({}, receptor.ui, {
  369. stroke: "#46b8da", strokeWidth: 1,
  370. fill: shapeColor,
  371. data_receptor_idx: idx,
  372. onClick: this.handleClickReceptor,
  373. style: { cursor: "pointer" },
  374. }), [
  375. h('title', {}, this.viewReceptorTitle(receptor.value)),
  376. ]),
  377. h('text', {
  378. x: receptor.ui.cx, y: receptor.ui.cy + 1, fill: fontColor,
  379. dominantBaseline: "middle", textAnchor: "middle",
  380. style: { fontSize: "10px", cursor: "pointer" },
  381. data_receptor_idx: idx,
  382. onClick: this.handleClickReceptor,
  383. }, charge.toFixed(1)),
  384. h('text', {
  385. x: receptor.ui.cx, y: receptor.ui.cy - 20, fill: "#000",
  386. dominantBaseline: "middle", textAnchor: "middle",
  387. style: { fontSize: "10px", cursor: "pointer" },
  388. data_receptor_idx: idx,
  389. onClick: this.handleClickReceptor,
  390. }, this.viewReceptorLetter(receptor.value)),
  391. ]);
  392. },
  393. viewReceptorLetter: function (letter) {
  394. switch (letter) {
  395. case "\t": return "\\t";
  396. case " ": return "_";
  397. case "\n": return "\\n";
  398. default: return letter;
  399. }
  400. },
  401. viewReceptorTitle: function (letter) {
  402. switch (letter) {
  403. case "\t": return "tab";
  404. case " ": return "space";
  405. case "\n": return "new line";
  406. default: return letter;
  407. }
  408. },
  409. renderReceptorInfo: function () {
  410. if (null === this.state.selectedReceptorIdx) return null;
  411. var receptor = this._receptor[this.state.selectedReceptorIdx];
  412. return h('div', {}, [
  413. "Receptor: '" + this.viewReceptorTitle(receptor.value) + "' charge('" + receptor.charge.toFixed(2) + "')",
  414. ]);
  415. },
  416. renderAllReceptorInfo: function () {
  417. var state = this.props.store.getState()
  418. return h('div', {}, state.receptor.map(this.renderAllReceptorInfo_item));
  419. },
  420. renderAllReceptorInfo_item: function (receptor, idx) {
  421. var charge = this.props.store.getReceptorCharge(idx)
  422. return h('div', {}, ["Receptor: '" + this.viewReceptorTitle(receptor.value) + "' charge('" + charge.toFixed(2) + "')"]);
  423. },
  424. renderAllNeuronInfo: function () {
  425. var state = this.props.store.getState()
  426. return h('div', {}, state.neuron.map(this.renderAllNeuronInfo_item));
  427. },
  428. renderAllNeuronInfo_item: function (neuron, idx) {
  429. var charge = this.props.store.getNeuronCharge(idx)
  430. return h('div', {}, ["Neuron: '" + neuron.value + "' charge('" + charge.toFixed(2) + "')"]);
  431. },
  432. renderInput: function () {
  433. return h('details', { open: true, style: { margin: "12px 0", border: "1px solid #aaa", borderRadius: "6px", padding: "12px", backgroundColor: "#eee", } }, [
  434. h('summary', { style: { cursor: "pointer" } }, "Input"),
  435. h('textarea', {
  436. ref: this.setInputRet,
  437. onChange: this.handleChangeInput,
  438. value: this.state.inputText,
  439. rows: 10,
  440. style: {
  441. width: "100%",
  442. padding: "12px",
  443. marginTop: "6px",
  444. backgroundColor: "#fff",
  445. },
  446. }),
  447. ]);
  448. },
  449. renderConfig: function () {
  450. DBG && console.log("DBG:NeuronView:renderConfig", { state: this.state })
  451. return h('details', { open: true, style: { margin: "12px 0", border: "1px solid #aaa", borderRadius: "6px", padding: "12px", backgroundColor: "#eee", } }, [
  452. h('summary', { style: { cursor: "pointer" } }, "Config"),
  453. h('div', { style: { padding: "12px", backgroundColor: "#fff", } }, [
  454. h('div', {}, "Anim speed:"),
  455. h('input', {
  456. className: "form-control input-sm",
  457. type: "number",
  458. value: this.state.config_anim_speed,
  459. name: "config_anim_speed",
  460. onChange: this.handleChangeConfig,
  461. }),
  462. h('div', { style: { marginTop: "12px" } }),
  463. h('div', {}, "Read speed (anim speed multiplier):"),
  464. h('input', {
  465. className: "form-control input-sm",
  466. type: "number",
  467. value: this.state.config_read_speed_multiplier,
  468. name: "config_read_speed_multiplier",
  469. onChange: this.handleChangeConfig,
  470. }),
  471. h('div', { style: { marginTop: "12px" } }),
  472. h('div', {}, "Charge receptor at input:"),
  473. h('input', {
  474. className: "form-control input-sm",
  475. type: "number",
  476. value: this.state.config_charge_receptor_at_input,
  477. name: "config_charge_receptor_at_input",
  478. onChange: this.handleChangeConfig,
  479. }),
  480. h('div', { style: { marginTop: "12px" } }),
  481. h('div', {}, "Max receptor charge:"),
  482. h('input', {
  483. className: "form-control input-sm",
  484. type: "number",
  485. value: this.state.config_max_receptor_charge,
  486. name: "config_max_receptor_charge",
  487. onChange: this.handleChangeConfig,
  488. }),
  489. h('div', { style: { marginTop: "12px" } }),
  490. h('div', {}, "Max neuron charge:"),
  491. h('input', {
  492. className: "form-control input-sm",
  493. type: "number",
  494. value: this.state.config_max_neuron_charge,
  495. name: "config_max_neuron_charge",
  496. onChange: this.handleChangeConfig,
  497. }),
  498. h('div', { style: { marginTop: "12px" } }),
  499. h('div', {}, "Discharge per tick:"),
  500. h('input', {
  501. className: "form-control input-sm",
  502. type: "number",
  503. step: "0.1",
  504. value: this.state.config_discharge_per_tick,
  505. name: "config_discharge_per_tick",
  506. onChange: this.handleChangeConfig,
  507. }),
  508. h('div', { style: { marginTop: "12px" } }),
  509. // config_strategy_overcharge: "LEAVE_HALF_CHARGE", // "REMOVE_CHARGE" | "LEAVE_HALF_CHARGE" | "LEAVE_ALMOST_MAX"
  510. h('div', {}, "Overcharge strategy:"),
  511. h('select', {
  512. className: "form-control input-sm",
  513. type: "number",
  514. step: "0.1",
  515. value: this.state.config_strategy_overcharge,
  516. name: "config_strategy_overcharge",
  517. onChange: this.handleChangeConfig,
  518. }, ["REMOVE_CHARGE", "LEAVE_HALF_CHARGE", "LEAVE_ALMOST_MAX"].map(function (strategy) {
  519. return h('option', { value: strategy }, strategy);
  520. })),
  521. ]),
  522. ]);
  523. },
  524. handleChangeConfig: function (event) {
  525. var value = event.target.value;
  526. var name = event.target.getAttribute('name');
  527. var state = this.state;
  528. state[name] = value;
  529. this.setState(state);
  530. },
  531. renderLog: function () {
  532. return LOG__render(this._log)
  533. },
  534. handleRefreshLog: function () {
  535. if (!this._log.length) return;
  536. var lastLog = this._log[this._log.length - 1]
  537. console.table(
  538. [
  539. lastLog.receptor.map(function (node) { return "R:'" + node.value + "'"; })
  540. .concat(
  541. lastLog.neuron.map(function (node) { return "N:'" + node.value + "'"; })
  542. )
  543. ].concat(
  544. this._log.map(function (log) {
  545. return log.receptor.map(function (node) { return node.charge })
  546. .concat(
  547. log.neuron.map(function (node) { return node.charge })
  548. )
  549. })
  550. )
  551. )
  552. },
  553. render: function () {
  554. DBG1 && console.log("DBG:NeuronView:render", {
  555. state: this.state,
  556. receptor: [].concat(this.props.store.getListReceptor()),
  557. neuron: [].concat(this.props.store.getListNeuron()),
  558. connection: [].concat(this.props.store.getListConnection()),
  559. charge: [].concat(this.props.store.getListCharge()),
  560. });
  561. var state = this.props.store.getState()
  562. return h('div', {}, [
  563. h('table', { className: "table", p5_node_id: "p5-neuron-output-table" }, [
  564. h('tbody', {}, [
  565. h('tr', {}, [
  566. h('td', { style: { width: this.state.ui_output_width + 20 } }, [
  567. h('svg', { ref: this.setOutputRet, height: this.state.uiOutputHeight, width: this.state.ui_output_width, style: { border: "1px solid #eee" } }, [
  568. state.connection.map(this.renderConnection),
  569. state.receptor.map(this.renderReceptor),
  570. state.neuron.map(this.renderNeuron),
  571. state.charge.map(this.renderCharge),
  572. ]),
  573. h('div', {
  574. style: {
  575. padding: "6px",
  576. border: "1px solid #eee",
  577. }
  578. }, [
  579. h('b', {}, "Input: "),
  580. h('span', {}, this.state.inputText.substr(0, this.state.inputReadPos)),
  581. h('span', { style: { color: "#ddd" } }, this.state.inputText.substr(this.state.inputReadPos)),
  582. ]),
  583. ]),
  584. h('td', { style: { verticalAlign: "top" } }, [
  585. // this.renderReceptorInfo(),
  586. this.renderAllReceptorInfo(),
  587. this.renderAllNeuronInfo(),
  588. ]),
  589. ]),
  590. ]),
  591. ]),
  592. h('div', {}, [
  593. h('button', { className: "btn btn-primary", onClick: this.handleReset }, "Uruchom"),
  594. " ",
  595. " (animPos:" + this.state.animPos + ") ",
  596. " ",
  597. state.doAnim
  598. ? h('button', { className: "btn btn-default", onClick: this.handlePause }, [h('i', { className: "glyphicon glyphicon-pause" }), "Stop"])
  599. : h('button', { className: "btn btn-default", onClick: this.handlePlay }, [h('i', { className: "glyphicon glyphicon-play" }), "Start"])
  600. ,
  601. h('button', { className: "btn btn-default", onClick: this.handleRefreshLog }, [h('i', { className: "glyphicon glyphicon-refresh" }), " ", "Log"])
  602. ]),
  603. this.renderLog(),
  604. h('table', { className: "table" }, [
  605. h('tbody', {}, [
  606. h('tr', {}, [
  607. h('td', { style: { width: "50%" } }, [
  608. this.renderInput(),
  609. ]),
  610. h('td', { style: { width: "50%" } }, [
  611. this.renderConfig(),
  612. ]),
  613. ]),
  614. ]),
  615. ]),
  616. h('div', {}, [
  617. "TODO: receptory...",
  618. ]),
  619. ]);
  620. }
  621. });
  622. // export default NeuronView
  623. ReactDOM.render(h(NeuronView, {
  624. store: global[MAKE_STORE_FUNCTION_NAME](),
  625. initialData: INITIAL_DATA || "",
  626. }), document.getElementById(HTML_ID))