JSFiddle - React, Tailwind, and code Playground

by rich_harris

HTML

<main></main>

<script id='template' type='text/html'>
  <label><input type='range' min=1 max=100 value='{{major}}'>major: {{major}}</label>
  <label><input type='range' min=0 max=1 step='0.01' value='{{minor}}'>minor: {{minor}}</label>
  <label><input type='range' min=1 max=50 value='{{numPoints}}'>numPoints: {{numPoints}}</label>
  
  <p>{{pathData}}</p>
  
  <svg width='500' height='500'>
	  <g transform='scale(5) translate(50,50)'>
    	<Star numPoints='{{numPoints}}' minor='{{minor}}' major='{{major}}'/>
    </g>
  </svg>
</script>

CSS

body {
    font-family: 'Helvetica Neue', arial, sans-serif;
    font-weight: 200;
    color: #353535;
}

h1, h2, h3, h4, h5, h6 {
    font-weight: 200;
}

label {
  display: block;
}

.error {
    color: #d00;
    font-family: monospace;
}

Babel + JSX

Ractive.components.Star = Ractive.extend({
  template: `<path d='M{{points.join("L")}}Z'/>`,
  css: `path { fill: #eee; stroke: black; }`,

  computed: {
    outerPoints () {
      const radius = this.get( 'major' );
      const numPoints = this.get( 'numPoints' );
      
      let points = [];
      
      for ( let i = 0; i < numPoints; i += 1 ) {
        var angle = i * Math.PI * 2 / numPoints;
        var x = Math.sin( angle ) * radius;
        var y = -Math.cos( angle ) * radius;
        
        points.push( `${x.toFixed(2)},${y.toFixed(2)}` );
      }
      
      return points;
    },
    
    innerPoints () {
      const radius = this.get( 'minor' ) * this.get( 'major' );
      const numPoints = this.get( 'numPoints' );
      
      let points = [];
      
      for ( let i = 0; i < numPoints; i += 1 ) {
        var angle = ( i + 0.5 ) * Math.PI * 2 / numPoints;
        var x = Math.sin( angle ) * radius;
        var y = -Math.cos( angle ) * radius;
        
        points.push( `${x.toFixed(2)},${y.toFixed(2)}` );
      }
      
      return points;
    },
    
    points () {
      const outerPoints = this.get( 'outerPoints' );
      const innerPoints = this.get( 'innerPoints' );
      
      let merged = [];
      outerPoints.forEach( ( outer, i ) => {
        merged.push( outer, innerPoints[i] );
      });
      
      merged.push( outerPoints[0] );
      
      return merged;
    }
  }
});

var ractive = new Ractive({
  el: 'main',
  template: '#template',
  data: {
    minor: 0.4,
    major: 5,
    numPoints: 5,
    
    pathData: ''
  }
});

ractive.findComponent( 'Star' ).observe( 'points', points => {
  ractive.set( 'pathData', `M${points.join('L')}Z` );
});