Created
November 2, 2015 04:58
-
-
Save oosby/6a87ad0d39cdab040e05 to your computer and use it in GitHub Desktop.
React canvas widget for plotting simple points
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Graph = React.createClass({ | |
displayName: 'graphWidget', | |
getDefaultProps() { | |
return { | |
backgroundColor: 'aliceblue', | |
canvasHeight: 200, | |
canvasWidth: 200, | |
clickThreshold: 10, | |
colorMatrix: { | |
2: 'lime', | |
4: 'gold', | |
6: 'orange', | |
8: 'red' | |
}, | |
lineWidth: 2, | |
pointRadius: 4, | |
points: [2,6,12,4,9] | |
}; | |
}, | |
getInitialState() { | |
return { | |
coordList: this.getCoordList(), | |
ctx: null, | |
currentCoords: null | |
}; | |
}, | |
componentDidMount() { | |
this.setState({ | |
ctx: this.refs.canvas.getContext("2d") | |
}, function() { | |
this.drawBgShape(); | |
this.drawGraphLines(); | |
this.drawPoints(); | |
}); | |
}, | |
canvasStyle: {}, | |
clearCanvas() { | |
const {canvasHeight, canvasWidth} = this.props; | |
const {ctx} = this.state; | |
if (ctx) { | |
ctx.clearRect(0,0, canvasWidth, canvasHeight); | |
} | |
}, | |
getColor(val) { | |
const {colorMatrix} = this.props; | |
const keys = Object.keys(colorMatrix); | |
var output = null; | |
keys.some( (key, idx, arr) => { | |
if (+val === +key) { | |
output = colorMatrix[key]; | |
return true; | |
} | |
if (+val < +key && +val > arr[idx + 1]) { | |
output = colorMatrix[key]; | |
return true; | |
} | |
if (+val > key) { | |
output = colorMatrix[keys[keys.length-1]]; | |
} | |
}); | |
return output; | |
}, | |
getCoordList() { | |
const {points, canvasHeight, canvasWidth, pointRadius} = this.props; | |
const innerWidth = canvasWidth - (pointRadius * 4); | |
const innerHeight = canvasHeight - (pointRadius * 8); | |
const max = Math.max(...points); | |
const yRatio = innerHeight / max; | |
const xIncrement = innerWidth / (points.length-1) | |
var output = []; | |
points.map( (req, idx) => { | |
output.push({ | |
x: (xIncrement * idx) + (pointRadius * 2), | |
y: canvasHeight - (req * yRatio), | |
point: req | |
}); | |
}); | |
return output; | |
}, | |
getGradient(startCoords, endCoords, startColor, endColor) { | |
const {ctx} = this.state; | |
var output = null; | |
if (ctx) { | |
if (startColor && endColor) { | |
output = ctx.createLinearGradient(startCoords.x, startCoords.y, endCoords.x, endCoords.y); | |
output.addColorStop(0, startColor); | |
output.addColorStop(.4, startColor); | |
output.addColorStop(1, endColor); | |
} | |
} | |
return output; | |
}, | |
drawBgShape() { | |
const {ctx, coordList} = this.state; | |
const {backgroundColor, canvasHeight, pointRadius} = this.props; | |
const innerHeight = canvasHeight - (pointRadius * 8); | |
var currentCoords = {}; | |
if (!ctx) {return false;} | |
this.clearCanvas(ctx); | |
ctx.fillStyle = backgroundColor; | |
ctx.strokeStyle = 'transparent'; | |
ctx.beginPath(); | |
ctx.moveTo(coordList[0].x, innerHeight); | |
coordList.map(list => { | |
ctx.lineTo(list.x, list.y); | |
ctx.stroke(); | |
currentCoords = list; | |
}); | |
ctx.lineTo(currentCoords.x, innerHeight); | |
ctx.fill(); | |
}, | |
drawGraphLines() { | |
const {coordList, ctx} = this.state; | |
const {canvasWidth} = this.props; | |
if (!ctx) {return false;} | |
coordList.map((list, idx, arr) => { | |
if (idx === 0) { | |
this.drawLine(list,list); | |
} else if (idx === (arr.length-1)) { | |
this.drawLine(arr[idx-1],list); | |
} else { | |
const endColor = this.getColor(list.point); | |
const startColor = this.getColor(arr[idx-1].point); | |
this.drawLine(arr[idx-1],list, startColor, endColor); | |
} | |
}); | |
}, | |
drawLine(startCoords, endCoords, startColor, endColor) { | |
const {ctx} = this.state; | |
const {lineWidth} = this.props; | |
var grad; | |
if (!ctx) {return false;} | |
if (startColor && endColor) { | |
grad = this.getGradient(startCoords, endCoords, startColor, endColor); | |
} | |
ctx.beginPath(); | |
ctx.strokeStyle = grad; | |
ctx.lineWidth = lineWidth; | |
ctx.moveTo(startCoords.x, startCoords.y); | |
ctx.lineTo(endCoords.x, endCoords.y); | |
ctx.stroke(); | |
ctx.closePath(); | |
}, | |
drawPoints() { | |
const {pointRadius} = this.props; | |
const {currentCoords, coordList, ctx} = this.state; | |
if (!ctx) {return false;} | |
coordList.map((list, idx) =>{ | |
const color = this.getColor(list.point); | |
ctx.beginPath(); | |
ctx.arc(list.x, list.y, pointRadius, 0, Math.PI * 2); | |
ctx.fillStyle = color; | |
ctx.fill(); | |
ctx.closePath(); | |
ctx.font = "18px Helvetica"; | |
ctx.fillStyle = '#333'; | |
ctx.textAlign = 'center'; | |
ctx.fillText(list.point, list.x, (list.y - (pointRadius*2))); | |
}); | |
}, | |
handleClick(e) { | |
const {clickThreshold} = this.props; | |
const {coordList} = this.state; | |
coordList.some(coord => { | |
if (e.clientX <= (coord.x + clickThreshold) && | |
e.clientX >= (coord.x - clickThreshold) && | |
e.clientY <= (coord.y + clickThreshold) && | |
e.clientY >= (coord.y - clickThreshold)) { | |
alert(coord); | |
return true; | |
} | |
}) | |
}, | |
render() { | |
const {canvasWidth, canvasHeight} = this.props; | |
return ( | |
<canvas onClick={this.handleClick} ref="canvas" style={this.canvasStyle} id="graph" width={canvasWidth} height={canvasHeight}></canvas> | |
); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment