Skip to content

Instantly share code, notes, and snippets.

@iris-i
Created January 8, 2018 13:56
Show Gist options
  • Save iris-i/1502e965cd87e7fb625fd39aeeb08954 to your computer and use it in GitHub Desktop.
Save iris-i/1502e965cd87e7fb625fd39aeeb08954 to your computer and use it in GitHub Desktop.
React Marquee Component using HTML Canvas & RequestAnimationFrame
import React from 'react';
import ReactDOM from 'react-dom';
class Marquee extends React.Component {
constructor(props){
super(props);
this.state = {
textwidth: 0,
containerwidth: 0,
rate: 1,
xloc: 0
}
this.getElementWidth = this.getElementWidth.bind(this);
this.getElementHeight = this.getElementHeight.bind(this);
this.startScroll = this.startScroll.bind(this);
this.stopScroll = this.stopScroll.bind(this);
this.drawText = this.drawText.bind(this);
this.animatePosition = this.animatePosition.bind(this);
this.createHiDPICanvas = this.createHiDPICanvas.bind(this);
this.pixelRatio = this.pixelRatio.bind(this);
}
componentDidMount() {
let tickerWidth = this.getElementWidth('tickerText');
let containerWidth = this.getElementWidth('tickerWrapper');
this.setState({
textwidth: tickerWidth,
containerwidth: containerWidth
});
window.requestAnimationFrame(this.startScroll);
}
componentWillUnmount() {
this.stopScroll();
}
getElementWidth(refId) {
let coords = ReactDOM.findDOMNode(this.refs[refId]).getBoundingClientRect();
return coords.width;
}
getElementHeight(refId) {
let coords = ReactDOM.findDOMNode(this.refs[refId]).getBoundingClientRect();
return coords.height;
}
startScroll() {
this._frameId = window.requestAnimationFrame( this.startScroll );
let canvas = ReactDOM.findDOMNode(this.refs['canvas1']);
return this.drawText(canvas, this.props.text, this.props.rate);
}
stopScroll() {
window.cancelAnimationFrame( this._frameId );
}
drawText(canvas, text, rate) {
let windowWidth = window.innerWidth;
let containerWidth = this.getElementWidth('tickerWrapper');
let w = this.getElementWidth('tickerText');
let h = this.getElementHeight('tickerWrapper');
let xloc = this.animatePosition(w, containerWidth, rate);
let yloc = windowWidth >= 1920 ? 35 : 30;
canvas = this.createHiDPICanvas(containerWidth, h, canvas);
let context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
context.font = '2.52vw Roboto';
context.fillStyle = 'white';
context.textBaseline = 'middle';
context.fillText(text, xloc, yloc);
}
animatePosition(textWidth, containerWidth, rate) {
let xloc = this.state.xloc;
if(textWidth + xloc < 0) {
xloc = containerWidth;
} else {
xloc -= rate;
}
this.setState({
xloc: xloc
});
return xloc;
}
pixelRatio (canvas) {
let ctx = canvas.getContext("2d");
let dpr = window.devicePixelRatio || 1;
let bsr = ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1;
return dpr / bsr;
};
createHiDPICanvas (w, h, canvas) {
let ratio = this.pixelRatio(canvas);
canvas.width = w * ratio;
canvas.height = h * ratio;
//canvas.style.width = w + "px";
//canvas.style.height = h + "px";
canvas.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0);
return canvas;
}
render() {
const {text, rate} = this.props;
return (
<div>
<canvas id = "canvas1" ref = "canvas1" className = "canvas" />
<div className = "ticker__wrapper" ref = 'tickerWrapper'>
<h3 className = "ticker__text" ref = 'tickerText'> {text} </h3>
</div>
</div>
);
}
}
export default Marquee;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment