<div id="app"></div>
.input-range-rv {
  vertical-align: middle;
  background-color: transparent;
  padding-top: 8px;
  padding-top: 0.5rem;
  padding-bottom: 8px;
  padding-bottom: 0.5rem;
  color: inherit;
  background-color: transparent;
  -webkit-appearance: none;
}

.input-range-rv::-webkit-slider-thumb {
  position: relative;
  width: 8px;
  width: 0.5rem;
  height: 20px;
  height: 1.25rem;
  cursor: pointer;
  margin-top: -8px;
  margin-top: -0.5rem;
  border-radius: 3px;
  background-color: #333;
  -webkit-appearance: none;
}

/* Touch screen friendly pseudo element */
.input-range-rv::-webkit-slider-thumb:before {
  content: '';
  display: block;
  position: absolute;
  top: -8px;
  top: -0.5rem;
  left: -14px;
  left: -0.875rem;
  width: 36px;
  width: 2.25rem;
  height: 36px;
  height: 2.25rem;
  opacity: 0;
}

.input-range-rv::-moz-range-thumb {
  width: 8px;
  width: 0.5rem;
  height: 20px;
  height: 1.25rem;
  cursor: pointer;
  border-radius: 3px;
  border-color: transparent;
  border-width: 0;
  background-color: #333;
}

.input-range-rv::-webkit-slider-runnable-track {
  height: 4px;
  height: 0.25rem;
  cursor: pointer;
  border-radius: 3px;
  background-color: rgba(0, 0, 0, 0.25);
}

.input-range-rv::-moz-range-track {
  height: 4px;
  height: 0.25rem;
  cursor: pointer;
  border-radius: 3px;
  background-color: rgba(0, 0, 0, 0.25);
}

.input-range-rv:focus {
  outline: none;
}
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 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 ReuleauxPolygon = ({ reuleauxPolygonD, polygonD, className }) => (
  <g>
    <defs>
      <pattern
        id="diagonal-stripe"
        patternUnits="userSpaceOnUse"
        width="10"
        height="10"
      >
        <rect width="10" height="10" stroke="none" fill="#fff" />
        <path
          d="M-1,1 l2,-2 M0,10 l10,-10 M9,11 l2,-2"
          stroke="#333"
          strokeWidth="1"
        />
      </pattern>
    </defs>
    <path fill="url(#diagonal-stripe)" d={reuleauxPolygonD} />
    <path stroke="#0f0" strokeWidth="4" d={polygonD} />
    <path fill="none" strokeWidth="4" d={reuleauxPolygonD} />
  </g>
);

const ReuleauxPolygonConstruction = ({ sideCount = 3, className }) => {
  const { r, pts, polygon, reuleaux } = reuleauxPolygonConstruction(
    [270, 270],
    90,
    sideCount,
  );

  return (
    <div className={className}>
      <svg
        viewBox="0 0 540 540"
        className="w-100"
        fill="none"
        stroke="#333"
        strokeLinejoin="round"
        strokeLinecap="round"
        strokeWidth="2"
      >
        {pts.map(p => (
          <circle key={p.join(',')} stroke="#ccc" cx={p[0]} cy={p[1]} r={r} />
        ))}
        <ReuleauxPolygon reuleauxPolygonD={reuleaux} polygonD={polygon} />
        {pts.map(p => (
          <circle key={p.join(',')} stroke="none" fill="#f0f" cx={p[0]} cy={p[1]} r={4} />
        ))}
      </svg>
    </div>
  );
};

class App extends React.Component {
  state = {
    values: {
      'side-count': 3,
    },
    controls: [
      {
        name: 'side-count',
        label: 'Side Count',
        type: RangeControl,
        min: 3,
        max: 11,
        step: 2,
      },
    ],
  };

  update = (name, value) => {
    this.setState(state => ({
      values: {
        ...state.values,
        [name]: +value,
      },
    }));
  };

  render() {
    const { controls, values } = this.state;

    return (
      <div className="code dark-gray mw6 center ph3 vh-100 flex items-center justify-center">
        <div className="w-100">
          <ReuleauxPolygonConstruction
            className="mh3 mb3"
            sideCount={values['side-count']}
          />
          <Controls
            controls={controls}
            values={values}
            update={this.update}
            className=""
          />
        </div>
      </div>
    );
  }
}

render(<App />, document.querySelector('#app'));

/**
 * Polygon Math
 */
function pts(sideCount, radius) {
  const angle = 360 / sideCount;
  const vertexIndices = range(sideCount);
  const offsetDeg = 90 - (180 - angle) / 2;
  const offset = degreesToRadians(offsetDeg);

  return vertexIndices.map(index => {
    return {
      theta: offset + degreesToRadians(angle * index),
      r: radius,
    };
  });
}

function range(count) {
  return Array.from(Array(count).keys());
}

function degreesToRadians(angleInDegrees) {
  return Math.PI * angleInDegrees / 180;
}

function polygon([cx, cy], sideCount, radius) {
  return pts(sideCount, radius).map(({ r, theta }) => [
    cx + r * Math.cos(theta),
    cy + r * Math.sin(theta),
  ]);
}

function dist([x1, y1], [x2, y2]) {
  return ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5;
}

function reuleauxPolygonConstruction([cx, cy], radius, sideCount) {
  const pts = polygon([cx, cy], sideCount, radius);
  const l = dist(pts[0], pts[2]);
  const [o, ...rest] = pts;

  return {
    r: l,
    pts,
    polygon: ['M', o[0], o[1], ...rest.map(p => `L ${p[0]} ${p[1]}`), 'Z'].join(
      ' ',
    ),
    reuleaux: [
      'M',
      o[0],
      o[1],
      ...rest.map(p => `A ${l} ${l} 0 0 1 ${p[0]} ${p[1]}`),
      `A ${l} ${l} 0 0 1 ${o[0]} ${o[1]}`,
      'Z',
    ].join(' '),
  };
}
View Compiled

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/tachyons/4.9.1/tachyons.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.development.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.development.js