| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- 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 (!d3) throw "Missing d3 (https://d3js.org/d3.v5.min.js)";
- var DBG = DBG || false;
- var DBG1 = true;
- // <svg height="100" width="100">
- // <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
- // </svg>
- var p5UI__TestNeuron = createReactClass({
- _input: null,
- _output: null,
- getInitialState: function () {
- return {
- inputText: INITIAL_DATA || '',
- receptor: [],
- neuron: [],
- output_width: 300,
- max_receptor_r: 30,
- anim_pos: 0,
- anim_last_letter: null,
- config_read_speed: 100,
- config_charge_receptor_at_input: 1,
- config_max_receptor_charge: 5,
- config_discharge_per_tick: 0.1,
- selectedReceptorIdx: null,
- };
- },
- makeReceptor: function (letter, idx, arr) {
- var totalReceptors = arr.length;
- var cx = Math.ceil(this.state.output_width / (totalReceptors + 1));
- var r = Math.min(Math.ceil(this.state.output_width / (totalReceptors + 10) / 2), this.state.max_receptor_r);
- var xCenter = cx + cx * idx - r;
- return {
- letter: letter,
- charge: 0,
- x: xCenter,
- y: 20,
- r: r,
- }
- },
- dischargeNeuron: function (neuron) {
- return (neuron.charge > 0)
- ? Object.assign({}, neuron, {
- charge: Math.max(0, neuron.charge - this.state.config_discharge_per_tick),
- })
- : neuron
- ;
- },
- handleChangeInput: function (event) {
- this.setState({
- inputText: event.target.value,
- })
- },
- setInputRet: function (reactEl) { this._input = reactEl; },
- setOutputRet: function (reactEl) { this._output = reactEl; },
- // d3.selectAll("circle").transition()
- // .duration(750)
- // .delay(function (d, i) { return i * 10; })
- // .attr("r", function (d) { return Math.sqrt(d * scale); });
- componentDidMount: function () {
- this.startAnimation();
- },
- handleExec: function (event) {
- event.preventDefault();
- DBG1 && console.log('DBG:handleExec...');
- this.startAnimation();
- },
- startAnimation: function (event) {
- var distinct = function (value, idx, self) {
- return ( idx === self.indexOf(value) );
- };
- // var foundLetters = this.state.inputText.split("\n").reduce(function (ret, line) {
- // return ret.concat(
- // line.split('').filter(distinct)
- // ).filter(distinct);
- // }, []);
- var foundLetters = this.state.inputText.split("").filter(distinct);
- DBG1 && console.log('DBG:handleExec:foundLetters', { foundLetters });
- this.setState({
- anim_pos: 0,
- receptor: foundLetters.map(this.makeReceptor),
- neuron: [],
- });
- setTimeout(this.forwardAnim, this.state.config_read_speed)
- },
- getReceptor: function (char) {
- var receptor = this.state.receptor.filter(function (receptor) {
- return (char == receptor.letter);
- });
- if (!receptor.length) throw "BUG: no input receptor found for char '" + char + "'"; // TODO: create on demand?
- return receptor[0];
- },
- getNeuron: function (value) {
- var neuron = this.state.neuron.filter(function (neuron) {
- return (value == neuron.letter);
- });
- return (neuron.length) ? neuron[0] : null;
- },
- makeNueron: function (listNeuron, letter, last_letter) {
- var receptor = this.getReceptor(letter);
- var prevReceptor = this.getReceptor(last_letter);
- var value = '' + letter + last_letter;
- var findNeuron = this.getNeuron(value);
- var charge = (receptor.charge + prevReceptor.charge) / 2;
- if (!findNeuron) {
- return listNeuron.concat([
- {
- value: value,
- charge: charge,
- x: (receptor.x + prevReceptor.x) / 2,
- y: 20 + 20 * value.length,
- rx: 10 * value.length,
- ry: 10,
- source1_x: receptor.x,
- source1_y: receptor.y,
- source2_x: prevReceptor.x,
- source2_y: prevReceptor.y,
- }
- ])
- } else {
- return listNeuron.map(function (neuron) {
- (neuron.value === value)
- ? Object.assign({}, neuron, { charge: neuron.charge + (receptor.charge + prevReceptor.charge) / 2 })
- : neuron
- ;
- })
- }
- },
- forwardAnim: function () {
- if (this.state.anim_pos + 1 >= this.state.inputText.length) {
- DBG1 && console.log("DBG:anim STOP", { inputLength: this.state.inputText.length, anim_pos: this.state.anim_pos });
- return;
- }
- var anim_pos = this.state.anim_pos + 1;
- var char = this.state.inputText.charAt(anim_pos)
- DBG1 && console.log("DBG:anim", { anim_pos, char, len: this.state.inputText.length });
-
- // 1. charge receptor with letter `char`
- var neuron = this.state.neuron;
- var _chargeReceptor = this.state.config_charge_receptor_at_input;
- var toChangeReceptor = this.getReceptor(char)
- DBG1 && console.log("DBG:anim", { anim_pos, char, len: this.state.inputText.length, toChangeReceptor });
- toChangeReceptor.charge += _chargeReceptor;
- var receptor = this.state.receptor.map(function (receptor) {
- return (char !== receptor.letter) ? receptor : toChangeReceptor;
- })
- // 2. check if any receptor is over charged
- if (toChangeReceptor.charge > this.state.config_max_receptor_charge) {
- if (null !== this.state.anim_last_letter && this.state.anim_last_letter !== toChangeReceptor.letter) {
- DBG1 && console.log("DBG:check overcharged", { toChangeReceptor, last_letter: this.state.anim_last_letter });
- neuron = this.makeNueron(neuron, toChangeReceptor.letter, this.state.anim_last_letter);
- // discharge receptors to 0
- var toDischarge = [toChangeReceptor.letter, this.state.anim_last_letter];
- receptor = receptor.map(function (receptor) {
- return (-1 !== toDischarge.indexOf(receptor.letter))
- ? Object.assign({}, receptor, { charge: 0 })
- : receptor
- ;
- })
- }
- }
- // 3. discharge all receptors and nodes by 0.1 (config_discharge_per_tick)
- receptor = receptor.map(this.dischargeNeuron)
- neuron = neuron.map(this.dischargeNeuron)
- // 4. create neuron if needed
- this.setState({
- anim_last_letter: char,
- anim_pos: anim_pos,
- receptor: receptor,
- neuron: neuron,
- });
- setTimeout(this.forwardAnim, this.state.config_read_speed)
- },
- selectReceptor: function (receptorIdx) {
- this.setState({ selectedReceptorIdx: receptorIdx })
- },
- handleClickReceptor: function (event) {
- var data_receptor_idx = event.target.getAttribute('data_receptor_idx')
- DBG1 && console.log('DBG:handleClickReceptor', { data_receptor_idx, target: event.target });
- this.selectReceptor(data_receptor_idx)
- },
- renderConnections: function (neuron, idx) {
- return h('g', {}, [
- h('line', {
- x1: neuron.source1_x, y1: neuron.source1_y,
- x2: neuron.x, y2: neuron.y,
- style: {
- stroke: "#46b8da",
- strokeWidth: "2"
- },
- }),
- h('line', {
- x1: neuron.source2_x, y1: neuron.source2_y,
- x2: neuron.x, y2: neuron.y,
- style: {
- stroke: "#46b8da",
- strokeWidth: "2"
- },
- }),
- ]);
- },
- renderNeuron: function (neuron, idx) {
- var chargePr = (100 * neuron.charge) / this.state.config_max_receptor_charge;
- var fontColor = (chargePr < 50) ? "#000" : "#fff";
- return h('g', {}, [
- h('ellipse', {
- cx: neuron.x, cy: neuron.y, rx: neuron.rx, ry: neuron.ry, 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.x, y: neuron.y + 1, fill: fontColor,
- dominantBaseline: "middle", textAnchor: "middle",
- style: { fontSize: "10px", cursor: "pointer" },
- // data_neuron_idx: idx,
- // onClick: this.handleClickNeuron,
- }, this.viewNeuronValue(neuron.value)),
- ]);
- },
- 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) {
- // var totalReceptors = this.state.receptor.length;
- // var cx = Math.ceil(this.state.output_width / ( totalReceptors + 1 ));
- // var r = Math.min(Math.ceil(this.state.output_width / ( totalReceptors + 10 ) / 2), this.state.max_receptor_r);
- // DBG && console.log('DBG:renderReceptor', { receptor, idx, totalReceptors, r });
- // var xCenter = cx + cx * idx - r;
- var chargePr = (100 * receptor.charge) / this.state.config_max_receptor_charge;
- var fontColor = (chargePr < 50) ? "#000" : "#fff";
- // this.state.config_max_receptor_charge = 100%
- // receptor.charge = x% (max 100)
- return h('g', {}, [
- h('circle', {
- cx: receptor.x, cy: receptor.y, r: receptor.r, stroke: "#46b8da", strokeWidth: 1,
- // fill: "#5bc0de"
- // (receptor.charge > this.state.config_max_receptor_charge)
- fill: (chargePr > 100) ? "#f00" : "hsl(194, 67%, " + (100 - chargePr) + "%)",
- data_receptor_idx: idx,
- onClick: this.handleClickReceptor,
- style: { cursor: "pointer" },
- }, [
- h('title', {}, this.viewReceptorTitle(receptor.letter)),
- ]),
- h('text', {
- x: receptor.x, y: receptor.y + 1, fill: fontColor,
- dominantBaseline: "middle", textAnchor: "middle",
- style: { fontSize: "10px", cursor: "pointer" },
- data_receptor_idx: idx,
- onClick: this.handleClickReceptor,
- }, this.viewReceptorLetter(receptor.letter)),
- ]);
- },
- 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.state.receptor[this.state.selectedReceptorIdx];
- return h('div', {}, [
- "Receptor: '" + this.viewReceptorTitle(receptor.letter) + "' charge('" + receptor.charge.toFixed(2) + "')",
- ]);
- },
- renderAllReceptorInfo: function () {
- return h('div', {}, this.state.receptor.map(this.renderAllReceptorInfo_item));
- },
- renderAllReceptorInfo_item: function (receptor) {
- return h('div', {}, ["Receptor: '" + this.viewReceptorTitle(receptor.letter) + "' charge('" + receptor.charge.toFixed(2) + "')"]);
- },
- renderAllNeuronInfo: function () {
- return h('div', {}, this.state.neuron.map(this.renderAllNeuronInfo_item));
- },
- renderAllNeuronInfo_item: function (neuron) {
- return h('div', {}, ["Neuron: '" + neuron.value + "' charge('" + neuron.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 () {
- 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', {}, "Read speed:"),
- h('input', {
- className: "form-control input-sm",
- type: "number",
- value: this.state.config_read_speed,
- name: "config_read_speed",
- 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', {}, "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,
- }),
- ]),
- ]);
- },
- handleChangeConfig: function (event) {
- var value = event.target.value;
- var name = event.target.getAttribute('name');
- var state = this.state;
- state[name] = value;
- this.setState(state);
- },
- render: function () {
- return h('div', {}, [
- h('table', { className: "table table-border" }, [
- h('tbody', {}, [
- h('tr', {}, [
- h('td', { style: { width: this.state.output_width + 20 } }, [
- h('svg', { ref: this.setOutputRet, height: 300, width: this.state.output_width, style: { border: "1px solid #eee" } }, [
- this.state.neuron.map(this.renderConnections),
- this.state.receptor.map(this.renderReceptor),
- this.state.neuron.map(this.renderNeuron),
- ]),
- ]),
- h('td', { style: { verticalAlign: "top" } }, [
- this.renderReceptorInfo(),
- ]),
- h('td', { style: { verticalAlign: "top" } }, [
- this.renderAllReceptorInfo(),
- this.renderAllNeuronInfo(),
- ]),
- ]),
- ]),
- ]),
- h('button', { className: "btn btn-primary", onClick: this.handleExec }, "Uruchom"),
- h('table', { className: "table table-border" }, [
- h('tbody', {}, [
- h('tr', {}, [
- h('td', { style: { width: "50%" } }, [
- this.renderInput(),
- ]),
- h('td', { style: { width: "50%" } }, [
- this.renderConfig(),
- ]),
- ]),
- ]),
- ]),
- h('div', {}, [
- "TODO: receptory...",
- ]),
- ]);
- }
- });
- ReactDOM.render(h(p5UI__TestNeuron
- ), document.getElementById(HTML_ID))
|