UNPKG

principles-ui-components

Version:

Supporting UI controller for Tizen TV web application, which developed base on React Framework.

246 lines (223 loc) 8.88 kB
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { is, Map } from 'immutable'; import CommonAPI from './CommonAPI'; export default class ScrollText extends Component { constructor(props) { super(props); this.state = { textAniName: '', textAniDuration: '', textAniDelay: '', }; this.animationDone = this.animationDone.bind(this); } componentWillMount() { const { children, fontSize, fontFamily, width, textGap } = this.props; this.textWidth = CommonAPI.getTextWidth(children, fontSize, fontFamily); this.aniName = `Text${this.textWidth}${textGap}`; if (this.textWidth > width) { const movePx = this.textWidth + textGap; this.style = document.createElement('style'); this.style.type = 'text/css'; const keyFrames = `@keyframes ${this.aniName}1 { 0% {transform: translateX(0px) translateZ(100px);} 100% {transform: translateX(-${movePx}px) translateZ(100px);} } @keyframes ${this.aniName}2 { 0% {transform: translateX(0px) translateZ(100px);} 100% {transform: translateX(-${movePx}px) translateZ(100px);} } `; this.style.innerHTML = keyFrames; document.getElementsByTagName('head')[0].appendChild(this.style); } } componentDidMount() { this.text.addEventListener('animationend', this.animationDone, false); if (this.state.textAniName === '') { if (this.props.scroll) { const { width } = this.props; if (this.textWidth > width) { this.onMount(); } } } } componentWillReceiveProps(nextProps) { const { children, fontSize, fontFamily } = nextProps; if (nextProps.children !== this.props.children || nextProps.fontSize !== this.props.fontSize || nextProps.textGap !== this.props.textGap || nextProps.width !== this.props.width || nextProps.fontFamily !== this.props.fontFamily) { this.textWidth = CommonAPI.getTextWidth(children, fontSize, fontFamily); this.aniName = `Text${this.textWidth}${nextProps.textGap}`; if (this.textWidth > nextProps.width) { const movePx = this.textWidth + nextProps.textGap; this.removeStyleFromHeader(); this.style = document.createElement('style'); this.style.type = 'text/css'; const keyFrames = `@keyframes ${this.aniName}1 { 0% {transform: translateX(0px) translateZ(100px);} 100% {transform: translateX(-${movePx}px) translateZ(100px);} } @keyframes ${this.aniName}2 { 0% {transform: translateX(0px) translateZ(100px);} 100% {transform: translateX(-${movePx}px) translateZ(100px);} } `; this.style.innerHTML = keyFrames; document.getElementsByTagName('head')[0].appendChild(this.style); } } if (!nextProps.scroll) { this.setState({ textAniName: '', textAniDuration: '', textAniDelay: '', }); } } shouldComponentUpdate(nextProps, nextState) { return (JSON.stringify(nextProps) !== JSON.stringify(this.props)) || (JSON.stringify(nextState) !== JSON.stringify(this.state)); } componentDidUpdate() { if (this.state.textAniName === '') { if (this.props.scroll) { const { width } = this.props; if (this.textWidth > width) { this.onMount(); } } } } componentWillUnmount() { this.removeStyleFromHeader(); this.text.removeEventListener('animationend', this.animationDone, false); } onMount() { this.setState({ textAniName: `${this.aniName}1`, textAniDuration: `${(this.textWidth + this.props.textGap) / 50}s`, textAniDelay: '1s', }); } removeStyleFromHeader() { if (this.style) { document.getElementsByTagName('head')[0].removeChild(this.style); this.style = null; } } animationDone(e) { e.preventDefault(); const target = e.target; if (target === e.currentTarget) { if (e.type === 'animationend') { let textAni = this.state.textAniName; if (textAni === `${this.aniName}1`) { textAni = `${this.aniName}2`; } else { textAni = `${this.aniName}1`; } this.setState({ textAniName: textAni }); } } } render() { const { scroll, children, left, top, width, height, lineHeight, fontSize, fontFamily, color, textAlign, verticalAlign } = this.props; const { textAniName, textAniDuration, textAniDelay } = this.state; const style = { position: 'absolute', overflow: 'hidden', left, top, width, height, lineHeight, textAlign, verticalAlign, fontSize, fontFamily, color, }; if (scroll && this.textWidth > width) { style.textOverflow = ''; const aniStyle = { position: 'absolute', left: 0, top: 0, width: (2 * this.textWidth) + this.props.textGap, }; aniStyle.animationName = textAniName; aniStyle.animationDuration = textAniDuration; aniStyle.animationDelay = textAniDelay; aniStyle.animationTimingFunction = 'linear'; const text1Style = { position: 'absolute', left: 0, top: 0, animationTimingFunction: 'linear', animationFillMode: 'both', }; const text2Style = { position: 'absolute', left: this.textWidth + this.props.textGap, top: 0, animationTimingFunction: 'linear', animationFillMode: 'both', }; return (<div style={style}> <div style={aniStyle} ref={(text) => { this.text = text; }}> <div style={text1Style} ref='text1'>{children}</div> <div style={text2Style} ref='text2' aria-hidden='true'>{children}</div> </div> </div>); } const text3Style = { position: 'absolute', left: 0, top: 0, width, height, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', }; return (<div style={style} ref={(text) => { this.text = text; }}> <div style={text3Style} ref='text3'>{children}</div> </div>); } } ScrollText.defaultProps = { left: 0, top: 0, width: 195, height: 40, lineHeight: '40px', textAlign: 'left', verticalAlign: 'middle', scroll: true, fontSize: 26, fontFamily: 'SamsungOneGui_600', textGap: 60, color: '#000000', }; ScrollText.propTypes = { left: PropTypes.number, top: PropTypes.number, width: PropTypes.number.isRequired, height: PropTypes.number.isRequired, lineHeight: PropTypes.string, textAlign: PropTypes.oneOf(['left', 'center', 'right']), verticalAlign: PropTypes.oneOf(['top', 'middle', 'bottom']), scroll: PropTypes.bool.isRequired, fontSize: PropTypes.number.isRequired, fontFamily: PropTypes.string.isRequired, textGap: PropTypes.number.isRequired, color: PropTypes.string, };