{"id":6617,"date":"2020-10-23T14:43:14","date_gmt":"2020-10-23T14:43:14","guid":{"rendered":"https:\/\/www.garysieling.com\/blog\/?p=6617"},"modified":"2020-10-23T14:43:14","modified_gmt":"2020-10-23T14:43:14","slug":"generate-an-svg-sunburst-from-javascript","status":"publish","type":"post","link":"https:\/\/www.garysieling.com\/blog\/generate-an-svg-sunburst-from-javascript\/","title":{"rendered":"Generate an SVG sunburst from JavaScript"},"content":{"rendered":"\n<p>I want to generate a sunburst to use with a laser-cutting service, like below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1141\" height=\"1030\" src=\"https:\/\/www.garysieling.com\/blog\/wp-content\/uploads\/2020\/10\/download-3-1141x1030.png\" alt=\"\" class=\"wp-image-6618\" srcset=\"https:\/\/www.garysieling.com\/blog\/wp-content\/uploads\/2020\/10\/download-3-1141x1030.png 1141w, https:\/\/www.garysieling.com\/blog\/wp-content\/uploads\/2020\/10\/download-3-300x271.png 300w, https:\/\/www.garysieling.com\/blog\/wp-content\/uploads\/2020\/10\/download-3-768x693.png 768w, https:\/\/www.garysieling.com\/blog\/wp-content\/uploads\/2020\/10\/download-3.png 1482w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>This has a couple of important features:<\/p>\n\n\n\n<ul><li>It&#8217;s a single path, for the laser to use<\/li><li>The rays on the sun can intersect a bounding box, including the corners<\/li><li>This will produce two interlocking parts (e.g. for printmaking, these can be inked separately, and combined) <\/li><\/ul>\n\n\n\n<p>The code is below &#8211; this works with Paper.js:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var postyle = { fillColor:'grey', strokeColor: 'black'}\n\nconst size = 200;\nconst rect = [0, 0, [ size, size]];\nconst ratio = 0.25;\nconst radius = size * ratio;\nconst spokes = 48;\nconst pi = 3.14;\n\nconst center = [0, 0]\n\nvar path = new paper.Path();\npath.strokeColor = \"#000\";\npath.closed = true;\n\nfunction ip(a) {\n    return [\n        radius * Math.cos(a),\n        radius * Math.sin(a)\n    ];\n}\n\nfunction intersect(x1, y1, x2, y2, mixX, minY, maxX, maxY) {\n    var point = rectangleIntersect(maxX - x1, maxY - y1, x2 - x1, y2 - y1);\n    return point &amp;&amp; { x: point.x + x1, y: point.y + y1 };\n}\n\nfunction rectangleIntersect(w, h, x, y) {\n    var sx = x > 0 ? 1 : -1;\n    var sy = y > 0 ? 1 : -1;\n\n    x *= sx;\n    y *= sy;\n\n    if (x &lt; w &amp;&amp; y &lt; h) return null;\n\n    var m = x * h;\n    var n = y * w;\n\n    if (m &lt; n) w = m \/ y;\n    if (m > n) h = n \/ x;\n\n    return [ Math.round( sx * w ), Math.round(sy * h ) ];\n}\n\nfunction outer(a) {\n    return rectangleIntersect(\n        size,\n        size,\n        100000 * Math.cos(a) + size\/2,\n        100000 * Math.sin(a) + size\/2,\n    );\n}\n\nfunction maybeCorner(p1, p2, a1) {\n    const corners = [\n        [1 * size, -1 * size],\n        [1 * size, 1 * size],\n        [-1 * size, 1 * size],\n        [-1 * size, -1 * size], \n    ];\n    \n    if (p1[0] != p2[0] &amp;&amp; \n        p1[1] != p2[1]) {\n        const idx = Math.round(2*a1\/pi) % 4;\n        return corners[idx];\n    }\n}\n\nfor (let i = 0; i &lt; spokes; i++) {\n    const a1 = pi \/ spokes * (2 * i);\n    const a2 = pi \/ spokes * (2 * i + 1);\n    \n    const inner1 = ip(a1);\n    const inner2 = ip(a2);\n    const outer1 = outer(a1);\n    const outer2 = outer(a2);\n    \n    const points = [\n        inner1, \n        outer1,\n        maybeCorner(outer1, outer2, a1),\n        outer2,\n        inner2].filter(\n        (p) => !!p        \n    );\n        \n    points.map(\n        ([x, y]) => {\n            path.add(new paper.Point(x + center[0], y + center[1]));\n        });\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I want to generate a sunburst to use with a laser-cutting service, like below: This has a couple of important features: It&#8217;s a single path, for the laser to use The rays on the sun can intersect a bounding box, including the corners This will produce two interlocking parts (e.g. for printmaking, these can be &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.garysieling.com\/blog\/generate-an-svg-sunburst-from-javascript\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Generate an SVG sunburst from JavaScript&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[1],"tags":[],"aioseo_notices":[],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/posts\/6617"}],"collection":[{"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/comments?post=6617"}],"version-history":[{"count":1,"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/posts\/6617\/revisions"}],"predecessor-version":[{"id":6619,"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/posts\/6617\/revisions\/6619"}],"wp:attachment":[{"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/media?parent=6617"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/categories?post=6617"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.garysieling.com\/blog\/wp-json\/wp\/v2\/tags?post=6617"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}