JSFiddle - React, Tailwind, and code Playground

HTML

<canvas id="starmap" width="650" height="650"></canvas>
<div id="star_id">No star selected</div>
<div id="starmap_controls">
    <input type="checkbox" name="toggle_wormholes" id="toggle_wormholes" value="0">Show Wormholes
    <br />
    <input type="checkbox" name="toggle_rotation" id="toggle_rotation" value="0">Rotate
    <br />
    <input type="checkbox" name="toggle_names" id="toggle_names" value="0">Star Names
    <br />
    <input type="checkbox" name="toggle_unreachable" id="toggle_unreachable" value="0">Show Unreachable
    <br />
</div>

CSS

canvas#starmap {
    border:1px solid #333333;
    cursor: crosshair;
    background-color: black;
}
div#star_id {
    position: absolute;
    left: 0;
    padding: 5px;
}
div#starmap_controls {
    position: absolute;
    left: 475px;
    padding: 5px;
}

JavaScript

/*

Very, very loosely based on: http://www.soa-world.de/echelon/2008/07/fourth-prototype.html

Need to add zoom and scrolling.

*/

var PI2 = Math.PI * 2;

var renderer = {
    canvas: null,
    ctx: null,
    canvas_offset_left: 0,
    canvas_offset_top: 0,
    initialize: function (mapname) {
        this.canvas = $(mapname);
        this.ctx = this.canvas.getContext("2d");
        this.canvas_offset_left = Element.viewportOffset(this.canvas).left;
        this.canvas_offset_top = Element.viewportOffset(this.canvas).top;
    },
    clear_canvas: function () {
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    },
    draw_circle: function (x, y, radius, rgb) {
        var ctx = this.ctx;
        ctx.fillStyle = 'rgb(' + rgb + ')';
        ctx.beginPath();
        ctx.arc(x, y, radius, 0, PI2, false);
        ctx.fill();
    },
    draw_line: function (from_x, from_y, to_x, to_y, color) {
        var ctx = this.ctx;
        ctx.strokeStyle = "rgb(" + color + ")";
        ctx.beginPath();
        ctx.moveTo(from_x, from_y);
        ctx.lineTo(to_x, to_y);
        ctx.stroke();
    },
    draw_text: function (text, x, y, size) {
        var ctx = this.ctx;
        ctx.font = size + "px Arial";
        ctx.fillText(text, x, y);
    }
};

function star(x, y, z, name, type, num_wormholes, num_stations, reachable) {
    this.x = x;
    this.y = y;
    this.z = z;
    this.name = name;
    this.type = type;
    this.wormholes = num_wormholes;
    this.stations = num_stations;
    this.reachable = reachable;

    this.projected_x = 0;
    this.projected_y = 0;
    this.projected_z = 0;

    // methods
    this.project_star = project_star;
    this.rotate_x = rotate_x;
    this.rotate_y = rotate_y;
    this.rotate_z = rotate_z;

    function project_star() {
        this.projected_x = (renderer.canvas.width / 2) + (this.x * map.zscale / (this.z + map.zscale));
        this.projected_y = (renderer.canvas.height / 2) + (this.y * map.zscale /...