Instantly share code, notes, and snippets.

Embed
What would you like to do?
Making of 20 Years 20 Titles
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { mediaBreakpointUp } from 'assets/Helpers.js'
export class SwoopyArrow extends Component {
render () {
const {
index,
x,
y,
width,
height,
margin,
padding,
wrap,
text,
orientation,
transform,
transformMobile,
color,
className,
arrowSize,
fontSize,
lineHeight
} = this.props
const invert = color.match('#000')
? '#FFF'
: '#000'
const [v, h] = orientation.split(' ')
let scale = { x: 1, y: 1 }
const words = text.split(' ')
const lines = words.reduce((lines, word) => {
if (lines[lines.length - 1].length + word.length > wrap) {
lines.push(`${word} `)
} else {
lines[lines.length - 1] += `${word} `
}
return lines
}, ['']).map(e => e.trim())
let textAnchor
let rotation = -5
switch (h) {
case 'left':
scale.x = -1
textAnchor = 'end'
break
case 'center':
textAnchor = 'middle'
rotation = 0
break
case 'right':
textAnchor = 'start'
break
default:
break
}
let textHeight = lines.length * fontSize * lineHeight
switch (v) {
case 'top':
scale.y = -1
break
case 'bottom':
textHeight = padding * -1
break
default:
break
}
if (mediaBreakpointUp('md')) {
return (
<g
className={className}
transform={`translate(${x}, ${y})`}
>
<g transform={transform}>
<text
transform={`translate(${width * scale.x}, ${(height + textHeight + padding + margin) * scale.y})`}
style={{ fontSize, fill: color }}
>
{lines.map((line, i) =>
<tspan
key={i}
x={0}
dy={fontSize * lineHeight}
textAnchor={textAnchor}
>
{line}
</tspan>
)}
</text>
<g
transform={`translate(0, ${margin * scale.y}) scale(${scale.x}, ${scale.y})`}
fill='none'
stroke={color}
strokeWidth='1'
strokeLinecap='round'
strokeLinejoin='round'
>
<polyline
transform={`translate(${arrowSize * -1}) rotate(${rotation})`}
points={`0, ${arrowSize * 2} ${arrowSize}, 0 ${arrowSize * 2}, ${arrowSize * 2}`}
/>
<path d={`M0, 0
C${0.05 * width}, ${0.2 * height}
${0.5 * width}, ${0.7 * height}
${width}, ${height}`}
/>
</g>
</g>
</g>
)
}
/* mobile */
return (
<g
className={`${className}--mobile`}
transform={`translate(${x}, ${y})`}
>
<g
transform={transformMobile || transform}
>
<circle
cx={0}
cy={margin * scale.y}
r={fontSize * 0.9}
fill={color}
/>
<text
x={0}
y={margin * scale.y + 4}
textAnchor='middle'
fontWeight={400}
fill={invert}
fontSize={fontSize}
style={{ lineHeight: 1 }}
>
{index}
</text>
</g>
</g>
)
}
}
SwoopyArrow.defaultProps = {
index: 1,
width: 10,
height: 40,
margin: 10,
padding: 10,
orientation: 'top right',
transform: '',
transformMobile: '',
text: 'This is the upper left corner',
wrap: 30,
color: '#000000',
className: 'SwoopyArrow',
arrowSize: 3,
fontSize: 12,
lineHeight: 1.2
}
SwoopyArrow.propTypes = {
index: PropTypes.number,
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
width: PropTypes.number,
height: PropTypes.number,
margin: PropTypes.number,
padding: PropTypes.number,
orientation: PropTypes.oneOf([
'top left',
'top center',
'top right',
'bottom left',
'bottom center',
'bottom right'
]),
transform: PropTypes.string,
transformMobile: PropTypes.string,
text: PropTypes.string,
wrap: PropTypes.number,
color: PropTypes.string,
className: PropTypes.string,
arrowSize: PropTypes.number,
fontSize: PropTypes.number,
lineHeight: PropTypes.number
}
export class MobileAnnotation extends Component {
render () {
const {
color
} = this.props
const invert = color.match('#000')
? '#FFF'
: '#000'
return (
<p
className={this.props.className}
style={{
display: mediaBreakpointUp('md') ? 'none' : 'flex',
width: '100%',
position: 'relative',
justifyContent: 'space-between'
}}
>
<span style={{
fontWeight: 400,
display: 'inline-block',
borderRadius: '50%',
width: 20,
height: 20,
whiteSpace: 'nowrap',
fontSize: 13,
lineHeight: 1.65,
background: color,
color: invert,
textAlign: 'center'
}}>
{this.props.index}
</span>
<span style={{
display: 'inline-block',
padding: '3px 5px 8px 0',
width: 'calc(100% - 28px)'
}}>
{this.props.text}
</span>
</p>
)
}
}
MobileAnnotation.defaultProps = {
index: 1,
text: 'This is the upper left corner',
className: 'MobileAnnotation',
color: '#000'
}
MobileAnnotation.propTypes = {
index: PropTypes.number,
text: PropTypes.string,
className: PropTypes.string,
color: PropTypes.string
}
/* react */
import React, {Component} from 'react'
/* libraries */
import PropTypes from 'prop-types'
import Measure from 'react-measure'
import { mediaBreakpointUp, isObject } from 'assets/Helpers.js'
export class ChartWrapper extends Component {
constructor (props) {
super(props)
this.state = {
dimensions: {
width: 0,
height: 0
}
}
}
componentDidMount () {
this.forceUpdate()
}
componentWillReceiveProps (nextProps, nextContext) {
if (nextContext.router.route.match.params.locale !== this.context.router.route.match.params.locale) {
this.forceUpdate()
}
}
render () {
const {
children,
fullHeight,
relativeHeight,
minWidth
} = this.props
let { aspectRatio } = this.props
let dimensions = {}
dimensions.width = this.state.dimensions.width
if (isObject(aspectRatio)) {
aspectRatio = Object.keys(aspectRatio)
.sort((a, b) => {
const order = ['xs', 'sm', 'md', 'lg', 'xl']
return order.indexOf(a) - order.indexOf(b)
}).reduce((result, bp) => {
if (mediaBreakpointUp(bp)) {
result = aspectRatio[bp]
}
return result
}, 0)
}
if (!relativeHeight) {
dimensions.height = fullHeight
? this.state.dimensions.height
: this.state.dimensions.width * aspectRatio
}
var childrenWithProps = React.Children.map(children, child =>
React.cloneElement(child, { dimensions }))
return (
<Measure
bounds
onResize={(contentRect) => {
this.setState({ dimensions: contentRect.bounds })
}}
>
{({ measureRef }) =>
<div
className='federer-chartWrapper'
ref={measureRef}
style={{height: relativeHeight ? 'auto' : '100%', minWidth}}
>
{dimensions.width > 0 && childrenWithProps}
</div>
}
</Measure>
)
}
}
ChartWrapper.defaultProps = {
relativeHeight: false,
fullHeight: false,
aspectRatio: 0.66
}
ChartWrapper.propTypes = {
relativeHeight: PropTypes.bool,
fullHeight: PropTypes.bool,
aspectRatio: PropTypes.oneOfType([
PropTypes.number,
PropTypes.object
]),
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
]),
minWidth: PropTypes.number
}
ChartWrapper.contextTypes = {
t: PropTypes.func,
router: PropTypes.object.isRequired
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment