Skip to content

Instantly share code, notes, and snippets.

@jasonszhao
Created July 15, 2019 06:45
Show Gist options
  • Save jasonszhao/84aebccf4b49f89c8f0b003f567f42ea to your computer and use it in GitHub Desktop.
Save jasonszhao/84aebccf4b49f89c8f0b003f567f42ea to your computer and use it in GitHub Desktop.
<head>
<meta charset="utf-8">
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<script src="//cdn.jsdelivr.net/npm/ramda@0.25.0/dist/ramda.min.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/tachyons@4.10.0/css/tachyons.min.css" />
<style>
html,
body {
font-family: sans-serif;
}
</style>
</head>
<div class="f5 normal ma3 black-60 absolute z-max top-0">
<a href="../">..</a> /
<h1 class="f5 normal di">Sierpiński triangle</h1>
</div>
<div id="app" class="flex justify-center ma4"></div>
<script type="text/babel">
const triangle_area = (x1, y1, x2, y2, x3, y3) =>
0.5 * ( x1*(y2-y3) + x2*(y3-y1) + x3*(y1-y2) )
const avg = (a, b) => (a + b) / 2
class Triangle extends React.Component {
constructor(props) {
super(props)
for (const [k, v] of Object.entries(props)) {
this[k] = v
}
}
shouldComponentUpdate() {
return false
}
render() {
const { x1, y1, x2, y2, x3, y3, min_area} = this
// return <polygon
// key={`polygon-${x1},${y1} ${x2},${y2} ${x3},${y3}`}
// points={`${x1},${y1} ${x2},${y2} ${x3},${y3}`}
// fill="black"
// stroke="green"
// />
if (triangle_area(x1, y1, x2, y2, x3, y3) < min_area) {
return <polygon
key={`polygon-${x1},${y1} ${x2},${y2} ${x3},${y3}`}
points={`${x1},${y1} ${x2},${y2} ${x3},${y3}`}
fill="black" />
} else {
return [
<polygon
fill="none"
key={`polygon-${x1},${y1} ${x2},${y2} ${x3},${y3}`} points={`${x1},${y1} ${x2},${y2} ${x3},${y3}`} />,
<Triangle
key={`Triangle1-${x1},${y1} ${x2},${y2} ${x3},${y3}`}
x1={x1} y1={y1}
x2={avg(x1, x2)} y2={avg(y1, y2)}
x3={avg(x1, x3)} y3={avg(y1, y3)}
min_area={min_area} />,
<Triangle
key={`Triangle2-${x1},${y1} ${x2},${y2} ${x3},${y3}`}
x1={avg(x1, x2)} y1={avg(y1, y2)}
x2={x2} y2={y2}
x3={avg(x2, x3)} y3={avg(y2, y3)}
min_area={min_area} />,
<Triangle
key={`Triangle3-${x1},${y1} ${x2},${y2} ${x3},${y3}`}
x1={avg(x1, x3)} y1={avg(y1, y3)}
x2={avg(x2, x3)} y2={avg(y2, y3)}
x3={x3} y3={y3}
min_area={min_area} />,
]
}
}
}
class App extends React.Component {
width = 400
constructor() {
super()
this.state = {
t: 0,
bodies: []
}
this.handleClick = this.handleClick.bind(this)
}
update(time_ms) {
this.setState(state => {
const time = time_ms / 1000
const dt = time - this.state.t
if (dt <= 0) {
return
}
const newState = {
t: time,
bodies: [],
}
for (const b of state.bodies) {
if (!(b.centerx + b.r >= 0
&& b.centerx - b.r <= 100
&& b.centery + b.r >= 0
&& b.centery - b.r <= 100
&& b.r > 0)) {
continue
}
newState.bodies.push({
...b,
centerx : b.centerx + dt * b.centerx_v,
centery : b.centery + dt * b.centery_v,
rot : b.rot + dt * b.rot_v,
r : b.r + dt * b.r_v,
})
}
return newState
})
this.loop()
}
loop() {
window.requestAnimationFrame(this.update.bind(this))
}
componentDidMount() {
this.loop()
}
handleClick(e) {
const new_body = {
r_i: 30*Math.random() + 12,
centerx: (e.clientX - e.target.getBoundingClientRect().x) / this.width * 100,
centery: (e.clientY - e.target.getBoundingClientRect().y) / this.width * 100,
rot_i: Math.random() * 2 * Math.PI,
r_v: -(Math.random() * 10 + 5),
centerx_v: (Math.random() - 0.5) * 16,
centery_v: (Math.random() - 0.5) * 16,
rot_v: (Math.random() - 0.5) * 20 * Math.PI,
key: Math.random().toString(),
keyName: Math.random().toString(),
}
new_body.r = new_body.r_i
new_body.rot = new_body.rot_i
this.setState(s =>
R.over(
R.lensProp('bodies'),
R.append(new_body),
s)
)
}
render() {
return (
<svg viewBox="0 0 100 100" width={this.width} className="ba" onClick={this.handleClick}>
{this.state.bodies.map(b => {
const {r_i, rot_i} = b
return <g
transform={
`rotate(${b.rot-b.rot_i},${b.centerx},${b.centery})
translate(${b.centerx},${b.centery})
scale(${b.r / b.r_i})`}
key={`Body-${b.keyName}`}>
<Triangle
x1={r_i*Math.cos(rot_i)} y1={r_i*Math.sin(rot_i)}
x2={r_i*Math.cos(rot_i + 2/3*Math.PI)} y2={r_i*Math.sin(rot_i + 2/3*Math.PI)}
x3={r_i*Math.cos(rot_i + 4/3*Math.PI)} y3={r_i*Math.sin(rot_i+ 4/3*Math.PI)}
min_area={1}/>
</g>
})}
</svg>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'))
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment