>
}
}
class PathVisualization extends React.Component {
// Component draws paths for path-dependent stopping decisions
constructor(props) {
super(props),
this.buttonStyle = this.buttonStyle.bind(this);
this.drawLines = this.drawLines.bind(this);
}
componentDidMount(){
// Draw lines between paths
const path = this.props.pathsToPlot
for (let col=1; col < path.length; col++) {
// Must loop over all nodes to get rows for alignment below
let prevCol = col - 1
let prevId = path[prevCol]
let currentId = path[col]
const previousId = "button_" + this.props.pathNum + "_" + prevId
const thisId = "button_" + this.props.pathNum + "_" + currentId
if (currentId == this.props.currentNode) {
document.getElementById(thisId).style.background = "darkblue"
}
this.drawLines(previousId, thisId)
}
}
buttonStyle(thisCol, maxLayer, thisRow, maxRow){
let style = {
background: "white",
width: "20px",
height: "20px",
borderRadius: "50%",
border: "0.5px solid black",
display: "block",
position: 'absolute',
}
const colSpacing = 100 / (maxLayer + 1) // Percentage distance between nodes
const rowSpacing = 70 / maxRow // Due to the height of the balls, we do not stretch to 100% height
let left = (thisCol+1) * colSpacing
let top = (thisRow+1) * rowSpacing
style.left = left.toString() + '%';
style.top = top.toString() + '%';
return style
}
drawTriangle() {
let buttonArray = [] // Push buttons here
const path = this.props.pathsToPlot
const layer = path.length // Column in ball triangle
// Determine rows of nodes for plotting
const reachableNodes = this.props.reachableNodes
let plotDict = {0:[0]}
let minRow = 0
let maxRow = 0
for (let tmpNum = 1; tmpNum < layer; tmpNum++) {
let prevNum = tmpNum-1
let previousLayer = reachableNodes[prevNum]
let prevColumns = plotDict[prevNum]
let currentLayer = reachableNodes[tmpNum]
plotDict[tmpNum] = []
for (let layerElem = 0; layerElem < currentLayer.length; layerElem++ ){
let elem = currentLayer[layerElem]
let up = previousLayer.indexOf(elem - tmpNum)
let down = previousLayer.indexOf(elem - tmpNum - 1)
if (up != -1){
let rowIndex = prevColumns[up] - 1
if (plotDict[tmpNum].indexOf(rowIndex) == -1) {
plotDict[tmpNum].push(rowIndex)
}
minRow = Math.min(rowIndex, minRow)
maxRow = Math.max(rowIndex, maxRow)
} else if (down != -1) {
let rowIndex = prevColumns[down] + 1
if (plotDict[tmpNum].indexOf(rowIndex) == -1) {
plotDict[tmpNum].push(rowIndex)
}
minRow = Math.min(rowIndex, minRow)
maxRow = Math.max(rowIndex, maxRow)
}
}
}
const numRows = maxRow - minRow + 1
for (let col=0; col < layer; col++){
let numBalls = reachableNodes[col].length // Number of balls per column
for (let ballInCol=0; ballInCol < numBalls; ballInCol ++){
let currentRow = plotDict[col][ballInCol] - minRow
let nodeId = reachableNodes[col][ballInCol]
buttonArray.push(
)
}
}
return buttonArray
}
drawLines(id1, id2) {
let start = document.getElementById(id1)
let end = document.getElementById(id2)
// add blue border around elems
start.style.border = "2px solid #2E8BC0"
end.style.border = "2px solid #2E8BC0"
let x_start = parseInt(window.getComputedStyle(start).left, 10)+21
let y_start = parseInt(window.getComputedStyle(start).top, 10)
let x_end = parseInt(window.getComputedStyle(end).left, 10)
let y_end = parseInt(window.getComputedStyle(end).top, 10)
let color = "black"
if (y_start > y_end) {
//Up move
y_start = y_start + 4
y_end = y_end + 10
color = "#0f5132"
} else {
// Down mode
y_start = y_start + 10
y_end = y_end + 4
//y_start = parseInt(window.getComputedStyle(start).top, 10) + 12.5
color = "#842029"
}
var newLine = document.createElementNS('http://www.w3.org/2000/svg','line');
//newLine.setAttribute('id',"line_"+move);
newLine.setAttribute('x1',x_start );
newLine.setAttribute('y1',y_start);
newLine.setAttribute('x2',x_end);
newLine.setAttribute('y2',y_end);
newLine.setAttribute("stroke", color)
newLine.setAttribute("stroke-width", 2)
$("#lineSVG_"+this.props.pathNum).append(newLine);
}
render () {
return (
<>
{this.drawTriangle()}
>
)
}
}
class RandNodeChoice extends React.Component {
constructor(props) {
super(props),
this.state={
currentValue: "",
},
this.rangeInput = this.rangeInput.bind(this);
this.numbersOnly = this.numbersOnly.bind(this);
this.deleteTimer = this.deleteTimer.bind(this);
this.componentDidMount = this.componentDidMount.bind(this);
}
timer; // Timer for rounding
submitTimer; // Timer for automatic submission
componentDidMount() {
if (this.props.isClicked) {
document.getElementById("amountInput").value = 100 - this.props.continuation
document.getElementById("amountRange").value = 100 - this.props.continuation
this.setState({currentValue: 100 - this.props.continuation})
//document.getElementById("amountRange").value = 100 - this.props.continuation
}
}
componentWillUnmount() {
if (this.submitTimer){
clearTimeout(this.submitTimer);
}
}
rangeInput(inputVal) {
document.getElementById("amountInput").value = inputVal
this.setState({currentValue: inputVal})
if (this.submitTimer){
clearTimeout(this.submitTimer);
}
if (! this.props.walkingTask) {
this.submitTimer = setTimeout(
() => {this.props.submitMe(100 - this.state.currentValue)},
5000
)
}
}
numbersOnly(inputVal) {
let regex = new RegExp("^[0-9][0-9]?$|^100$")
if (regex.test(inputVal) || inputVal.length == 0) {
let numValue = parseInt(inputVal)
// Need delay before rounding
if (this.timer) {
clearTimeout(this.timer);
}
this.timer = setTimeout( () => {
let usedValue = ""
if ( inputVal.length > 0) {
usedValue = Math.round(numValue/10) * 10
}
document.getElementById("amountInput").value = usedValue
document.getElementById("amountRange").value = usedValue
this.setState({currentValue: usedValue})
},500)
if (! this.props.walkingTask) {
this.submitTimer = setTimeout(
() => {this.props.submitMe(100 - this.state.currentValue)},
5000
)
}
} else {
document.getElementById("amountInput").value=
((this.state.currentValue !== "") ? this.state.currentValue : "")
document.getElementById("amountRange").value=
((this.state.currentValue !== "") ? this.state.currentValue : "")
}
}
deleteTimer(){
if (this.submitTimer){
clearTimeout(this.submitTimer);
}
}
render () {
return (
{this.props.header}
At this ball, please stop risk-taking with probability
this.rangeInput(e.target.value)} // using onclick allows for direct click on default
/>
this.numbersOnly(e.target.value)}
style={{marginLeft:"10%"}}/>%.