superellipse visualization on canvas |x/a|^n + |y/b|^n = 1 https://en.wikipedia.org/wiki/Superellipse
A Pen by Andreas Borgen on CodePen.
| main#app | |
| h1 Superellipse | |
| a(href="https://en.wikipedia.org/wiki/Superellipse") | |
| img(src="https://wikimedia.org/api/rest_v1/media/math/render/svg/2b21da32fe407ff5714620b26c50343d21afed15") | |
| section#settings.inputs(@input="recalc") | |
| label | |
| span a | |
| input(type="range" v-model.number="config.a" min="10" max="400") | |
| output {{config.a}} | |
| label | |
| span b | |
| input(type="range" v-model.number="config.b" min="10" max="400") | |
| output {{config.b}} | |
| label | |
| span n | |
| input(type="range" v-model.number="nBase" min="0.2" max="2" step=".01") | |
| output {{ config.n.toFixed(2) }} | |
| p | |
| label | |
| span detail | |
| input(type="range" v-model.number="config.detail" min="2" max="15") | |
| output {{ config.detail }} | |
| canvas(:width="config.a * 2" :height="config.b * 2") :( |
| console.clear(); | |
| (function() { | |
| "use strict"; | |
| const pi_ = Math.PI / 2; | |
| class Superellipse { | |
| static plot(config) { | |
| function sgn(w) { | |
| if(w === 0) { return 0; } | |
| return (w > 0) ? 1 : -1; | |
| } | |
| const { a, b, n, detail: steps } = config, | |
| n2 = 2/n, | |
| coords = []; | |
| //First, calculate the coordinates for a quarter squircle: | |
| //https://en.wikipedia.org/wiki/Superellipse#Mathematical_properties | |
| // x(t) = |cos t|^(2/n) * a*sgn(cos t) | |
| // y(t) = |sin t|^(2/n) * b*sgn(sin t) | |
| for(let i = 0; i <= steps; i++) { | |
| const t = i * (pi_/steps), | |
| cos = Math.cos(t), | |
| sin = Math.sin(t); | |
| const x = Math.pow(Math.abs(cos), n2) * a*sgn(cos), | |
| y = Math.pow(Math.abs(sin), n2) * b*sgn(sin); | |
| coords.push([x, y]); | |
| } | |
| //Then, clone those coordinates to plot a full squircle: | |
| for(let i = steps-1; i >= 0; i--) { | |
| const c = coords[i]; | |
| coords.push([-c[0], c[1]]) | |
| } | |
| for(let i = steps*2 - 1; i > 0; i--) { | |
| const c = coords[i]; | |
| coords.push([c[0], -c[1]]) | |
| } | |
| //console.log(coords); | |
| return coords; | |
| } | |
| } | |
| //https://en.wikipedia.org/wiki/Superellipse | |
| //|x/a|^n + |y/b|^n = 1 | |
| const config = { | |
| a: 300, | |
| b: 200, | |
| n: 2.5, | |
| detail: 6, | |
| }; | |
| let canvas, ctx; | |
| new Vue({ | |
| el: '#app', | |
| mounted: update, | |
| data: { | |
| config: config, | |
| nBase: 1.44, | |
| }, | |
| watch: { | |
| nBase(val) { | |
| //Trial and error to change the shape smoothly: | |
| this.config.n = (val < 1) ? Math.pow(val, 1.25) | |
| : Math.pow(val, Math.pow(val, 2.5)); | |
| }, | |
| }, | |
| methods: { | |
| recalc() { | |
| Vue.nextTick(update); | |
| }, | |
| }, | |
| }); | |
| function update() { | |
| if(!canvas) { | |
| canvas = document.querySelector('canvas'); | |
| ctx = canvas.getContext("2d"); | |
| } | |
| const plot = Superellipse.plot(config); | |
| draw(plot); | |
| } | |
| function draw(plot) { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| ctx.lineWidth = 1; | |
| ctx.strokeStyle = "dodgerblue"; | |
| ctx.fillStyle = "honeydew"; | |
| ctx.translate(config.a, config.b); | |
| ctx.beginPath(); | |
| plot.forEach(p => { | |
| ctx.lineTo(p[0], p[1]); | |
| }); | |
| ctx.closePath(); | |
| ctx.stroke(); | |
| ctx.fill(); | |
| ctx.setTransform(1, 0, 0, 1, 0, 0); | |
| } | |
| })(); |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.js"></script> |
| .inputs { | |
| display: table; | |
| label { | |
| display: table-row; | |
| > * { | |
| display: table-cell; | |
| vertical-align: middle; | |
| } | |
| span { | |
| padding-right: .5em; | |
| } | |
| input[type="number"], input[type="range"] { | |
| ~ output { | |
| text-align: right; | |
| min-width: 3em; | |
| } | |
| } | |
| } | |
| } | |
| main { | |
| margin: .5em; | |
| font-family: Georgia, sans-serif; | |
| } | |
| section { | |
| margin: 1em 0; | |
| } | |
| #settings input[type="range"] { | |
| width: 300px; | |
| } | |
| canvas { | |
| display: block; | |
| //border: 1px solid gainsboro; | |
| box-shadow: 0 0 4px 0 silver; | |
| } |
superellipse visualization on canvas |x/a|^n + |y/b|^n = 1 https://en.wikipedia.org/wiki/Superellipse
A Pen by Andreas Borgen on CodePen.