const { render } = ReactDOM;
const RangeControl = ({
name,
label,
value,
update,
className = '',
...props
}) => (
<div className={`mb4 ${className}`}>
<label htmlFor={name} className="f5 b db mb2 dark-gray">
{label} <span className="gray">({value})</span>
</label>
<input
name={name}
type="range"
className="input-range-rv flex-auto dark-gray w-100"
value={value}
onChange={e => update(name, e.target.value)}
{...props}
/>
</div>
);
const BooleanControl = ({
name,
label,
value,
update,
className = '',
...props
}) => (
<div className={`mb4 ${className}`}>
<p className="f5 dark-gray b mt0 mb2">
{label}
</p>
<div>
<label htmlFor={name} className="f5 dark-gray mr3">
<input
type="radio"
name={name}
value={1}
checked={value === 0}
onChange={e => update(name, 0)}
/>{' '}
0
</label>
<label htmlFor={name} className="f5 dark-gray">
<input
type="radio"
name={name}
value={1}
checked={value === 1}
onChange={e => update(name, 1)}
/>{' '}
1
</label>
</div>
</div>
);
const Controls = ({ className, controls, values, update }) => (
<div className={className}>
{controls.map(({ type, ...props }) =>
React.createElement(type, {
value: values[props.name],
key: props.name,
update,
...props,
}),
)}
</div>
);
const Arc = ({
'start-x': x1,
'start-y': y1,
rx,
ry,
'x-axis-rotation': xRot,
'large-arc-flag': largeArc,
'sweep-flag': sweep,
x: x2,
y: y2,
className,
}) => (
<div className={className}>
<svg viewBox="0 0 320 320" className="db w-100">
<defs>
<pattern id="grid" patternUnits="userSpaceOnUse" width="10" height="10">
<path
d="M 10 0 V 10 H -10"
stroke="#0f0" strokeWidth="1" fill="none" />
</pattern>
</defs>
<rect width="320" height="320" fill="url('#grid')"></rect>
<path d="M 320 0 H 0 V 320" fill="none" stroke="#0f0" strokeWidth="1" />
<g stroke="#333333"
fill="none"
strokeLinejoin="round"
strokeWidth="2">
<g stroke="#ccc">
<path
d={`M ${x1} ${y1} A ${rx} ${ry} ${xRot} 0 0 ${x2} ${y2}`}
/>
<path
d={`M ${x1} ${y1} A ${rx} ${ry} ${xRot} 1 1 ${x2} ${y2}`}
/>
<path
d={`M ${x1} ${y1} A ${rx} ${ry} ${xRot} 1 0 ${x2} ${y2}`}
/>
<path
d={`M ${x1} ${y1} A ${rx} ${ry} ${xRot} 0 1 ${x2} ${y2}`}
/>
</g>
<path
d={`M ${x1} ${y1} A ${rx} ${ry} ${xRot} ${largeArc} ${sweep} ${x2} ${y2}`}
/>
<circle cx={x1} cy={y1} r={2} fill="#fff" />
<circle cx={x2} cy={y2} r={2} fill="#fff" />
</g>
</svg>
<p className="mid-gray mt3 mb0 tc pa3 bg-light-gray purple">
{`M ${x1} ${y1} A ${rx} ${ry} ${xRot} ${largeArc} ${sweep} ${x2} ${y2}`}
</p>
</div>
);
class App extends React.Component {
state = {
values: {
'start-x': 120,
'start-y': 200,
rx: 75,
ry: 75,
'x-axis-rotation': -15,
'large-arc-flag': 0,
'sweep-flag': 1,
x: 200,
y: 120,
},
controls: [
{
name: 'large-arc-flag',
label: 'Large Arc Flag',
type: BooleanControl,
},
{
name: 'sweep-flag',
label: 'Sweep Flag',
type: BooleanControl,
},
{
name: 'rx',
label: 'rx',
type: RangeControl,
min: 0,
max: 320,
step: 1,
},
{
name: 'ry',
label: 'ry',
type: RangeControl,
min: 0,
max: 320,
step: 1,
},
{
name: 'x-axis-rotation',
label: 'x-Axis Rotation',
type: RangeControl,
min: 0,
max: 360,
step: 1,
},
{
name: 'start-x',
label: 'Start x',
type: RangeControl,
min: 0,
max: 320,
step: 1,
},
{
name: 'start-y',
label: 'Start y',
type: RangeControl,
min: 0,
max: 320,
step: 1,
},
{
name: 'x',
label: 'End x',
type: RangeControl,
min: 0,
max: 320,
step: 1,
},
{
name: 'y',
label: 'End y',
type: RangeControl,
min: 0,
max: 400,
step: 1,
},
],
};
update = (name, value) => {
this.setState(state => ({
values: {
...state.values,
[name]: value,
},
}));
};
render() {
const { controls, values } = this.state;
return (
<div className="code dark-gray mw8 center mt4 ph3">
<div className="flex flex-wrap mb5">
<Arc className="flex-auto mr0 mr5-ns mb5 mb0-ns" {...values} />
<Controls
controls={controls}
values={values}
update={this.update}
className="w-40-ns"
/>
</div>
</div>
);
}
}
render(<App />, document.querySelector('#app'));
View Compiled