Neuron.php.NeuronView.js 24 KB

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