Creating a 'New' spiky label with 24 or above point burst
Asked Answered
S

5

17

I am trying to make a point burst thing like the image below:

enter image description here

Currently, I have tried this using pseudo elements, however, I was only able to generate a 12 point burst and does not reflect that which is displayed within the image.

Is there anyway to create a point burst with only a few elements?

Below is the code I have used to attempt this solution:

div{
    width:100px;
    height:100px;
    background:grey;
    transform:rotate(45deg);
    margin:50px;
}
div:after{
    position:absolute;
    content:"";
    background:grey;
    width:100px;
    height:100px;
    transform:rotate(135deg);
}
div:before{
    position:absolute;
    content:"";
    background:grey;
    width:100px;
    height:100px;
    transform:rotate(250deg);
}
<div></div>
Smukler answered 9/6, 2015 at 10:32 Comment(0)
B
6

Canvas Approach

You can also achieve this using Canvas. The commands for drawing on Canvas are pretty much the same as in SVG. The approach, on a very high level, would be to find points on two circles (one with radius as x and another with a slightly smaller radius) and then connect them together to form a path. When the path is filled, it gives the appearance of a n-point burst.

In the below diagram, the green circle is the bigger circle with radius as x and the blue circle is the smaller inner circle. By plotting points on the circles and connecting them (with lineTo commands), we get the path which is in red. When this path is filled we get the burst appearance. (Note: The inner and outer circles are only for illustration and are not drawn in the actual diagram).

enter image description here


Calculation Logic

  • The X and Y coordinates of each points on the circle can be calculated using the below formula:
    • x = (Radius of circle * Cos(Angle in Radians)) + x coordinate of center
    • y = (Radius of circle * Sin(Angle in Radians)) + y coordinate of center
  • The angle at which the points are plotted on the circle are determined using the below logic:
    • As used in both your and Persijn's answers, the angle is calculated as (360/no. of bursts). 360 is used because it is the total angle within a circle.
    • Angle of the points on the inner circle should be half way between point1 and point2 on the larger circle and hence a delta is added to it. The delta is half of (360/no. of bursts)
  • Angle in Radians = Angle in Degrees * π / 180

window.onload = function() {
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  var defaultBurst = 18;
  var defaultContent = "New";

  function paint(numBurst, text) {
    if (!numBurst) numBurst = defaultBurst;
    if (!text) text = defaultContent;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = 'crimson';
    var angleInRad = Math.PI * (360 / numBurst) / 180;
    var deltaAngleInRad = angleInRad / 2;
    ctx.beginPath();
    ctx.moveTo(75, 150);
    for (i = 0; i <= numBurst; i++) {
      x1 = 75 * Math.cos(angleInRad * i) + 150;
      y1 = 75 * Math.sin(angleInRad * i) + 150;
      x2 = 60 * Math.cos((angleInRad * i) + deltaAngleInRad) + 150;
      y2 = 60 * Math.sin((angleInRad * i) + deltaAngleInRad) + 150;
      ctx.lineTo(x1, y1);
      ctx.lineTo(x2, y2);
    }
    ctx.closePath();
    /* Add shadow only for shape */
    ctx.shadowOffsetX = -5;
    ctx.shadowOffsetY = 5;
    ctx.shadowBlur = 5;
    ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
    ctx.fill();
    ctx.font = "32px Arial";
    ctx.textAlign = "center";
    ctx.fillStyle = "gold";
    /* Nullify shadow for text */
    ctx.shadowOffsetX = 0;
    ctx.shadowOffsetY = 0;
    ctx.fillText(text, 150, 160, 120);
  }
  paint();
  var slider = document.getElementById('burst');
  var textInput = document.getElementById('content');
  slider.addEventListener('change', function() {
    paint(this.value, textInput.value);
  });

  textInput.addEventListener('blur', function() {
    paint(slider.value, this.value);
  });
}
/* For demo only */

.controls {
  float: right;
  padding: 5px;
  margin: 50px 20px;
  line-height: 25px;
  border: 1px solid;
  box-shadow: 1px 1px 0px #222;
}
label,
input {
  display: inline-block;
  vertical-align: middle;
  text-align: left;
}
h3 {
  padding: 10px;
  text-align: center;
}
label {
  width: 100px;
}
input[type='range'],
input[type='text'] {
  width: 100px;
}
body {
  font-family: Calibri;
  background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<canvas id='canvas' height='300px' width='300px'></canvas>
<div class='controls'>
  <h3>Controls</h3>

  <label for="burst">Change Burst:</label>
  <input id="burst" class="slider" type="range" value="18" min="12" max="36" step='2' title="Adjust slider to increase or decrease burst" />
  <br/>
  <label for="content">Text Content:</label>
  <input type="text" id="content" maxlength="5" />
</div>

Advanced Demo

Check out this CodePen for an advanced demo with features like path creation animation, shadows, control over all the features etc.


Usage Advice

If you want a fixed size image somewhere in the page then Canvas is as good as SVG. However, if you would need an image that can be scaled to any size, Canvas is not the right choice because Canvas is raster based and becomes pixelated or blurred when scaled.

If your shape would need a dynamic number of bursts and/or text, Canvas would be more preferable over SVG and CSS because you don't have to perform any DOM manipulations.

Broadway answered 17/6, 2015 at 12:53 Comment(0)
S
16

With svg it is possible with a simple loop. I am using Snap as it makes it simple.

enter image description here

First of all create a circle using snap then using a loop find the points we need from the circle i referenced this question for finding the points. After finding the points simply give the lines these points.By changing the number in the loop and rad value points of any value can be created

24 point burst

var s=Snap('svg');
var circle=s.circle(50,50,30).attr({
    fill:'tomato',
    stroke:'tomato'
})
for (var num = 0; num < 24; num++) {
    var rad1 = num * 15 * (Math.PI / 180);
    var rad2 = (num+1) * 15 * (Math.PI / 180);
    var rad3=(num+.5) * 15 * (Math.PI / 180);
    var x1 = (30 * (Math.cos(rad1)) + 50)
    var y1 = (30 * (Math.sin(rad1)) + 50)
    var x2 = (40 * (Math.cos(rad3)) + 50)
    var y2 = (40 * (Math.sin(rad3)) + 50)
    var x3 = (30 * (Math.cos(rad2)) + 50)
    var y3 = (30 * (Math.sin(rad2)) + 50)
    var line=s.polyline(x1,y1,x2,y2,x3,y3).attr({
        'fill':'tomato'
    })
    }
var text=s.text(35,50,'New').attr({
    fill:'white'
})
div{
  width:100vw;
  height:100vh;
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
<div>
<svg width="100%" height="100%" viewbox="0 0 100 100">
</svg>
  </div>

36 points burst

var s=Snap('svg');
var circle=s.circle(50,50,30).attr({
    fill:'tomato',
    stroke:'tomato'
})
for (var num = 0; num < 36; num++) {
    var rad1 = num * 10 * (Math.PI / 180);
    var rad2 = (num+1) * 10 * (Math.PI / 180);
    var rad3=(num+.5) * 10 * (Math.PI / 180);
    var x1 = (30 * (Math.cos(rad1)) + 50)
    var y1 = (30 * (Math.sin(rad1)) + 50)
    var x2 = (40 * (Math.cos(rad3)) + 50)
    var y2 = (40 * (Math.sin(rad3)) + 50)
    var x3 = (30 * (Math.cos(rad2)) + 50)
    var y3 = (30 * (Math.sin(rad2)) + 50)
    var line=s.polyline(x1,y1,x2,y2,x3,y3).attr({
        'fill':'tomato'
    })
    }
var text=s.text(35,50,'New').attr({
    fill:'white'
})
div{
    width:100vw;
    height:100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
<div>
<svg width="100%" height="100%" viewbox="0 0 100 100">
</svg>
</div>

60 points burst

var s=Snap('svg');
var circle=s.circle(50,50,30).attr({
    fill:'tomato',
    stroke:'tomato'
})
for (var num = 0; num < 60; num++) {
    var rad1 = num * 6 * (Math.PI / 180);
    var rad2 = (num+1) * 6 * (Math.PI / 180);
    var rad3=(num+.5) * 6 * (Math.PI / 180);
    var x1 = (30 * (Math.cos(rad1)) + 50)
    var y1 = (30 * (Math.sin(rad1)) + 50)
    var x2 = (40 * (Math.cos(rad3)) + 50)
    var y2 = (40 * (Math.sin(rad3)) + 50)
    var x3 = (30 * (Math.cos(rad2)) + 50)
    var y3 = (30 * (Math.sin(rad2)) + 50)
    var line=s.polyline(x1,y1,x2,y2,x3,y3).attr({
        'fill':'tomato'
    })
    }
var text=s.text(35,50,'New').attr({
    fill:'white'
})
div{
    width:100vw;
    height:100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
<div>
<svg width="100%" height="100%" viewbox="0 0 100 100">
</svg>
</div>

This can also be animated

var s=Snap('svg');
var circle=s.circle(50,50,30).attr({
    fill:'tomato',
    stroke:'tomato'
})
var g=s.g();
for (var num = 0; num < 60; num++) {
    var rad1 = num * 6 * (Math.PI / 180);
    var rad2 = (num+1) * 6 * (Math.PI / 180);
    var rad3=(num+.5) * 6 * (Math.PI / 180);
    var x1 = (30 * (Math.cos(rad1)) + 50)
    var y1 = (30 * (Math.sin(rad1)) + 50)
    var x2 = (40 * (Math.cos(rad3)) + 50)
    var y2 = (40 * (Math.sin(rad3)) + 50)
    var x3 = (30 * (Math.cos(rad2)) + 50)
    var y3 = (30 * (Math.sin(rad2)) + 50)
    var line=s.polyline(x1,y1,x2,y2,x3,y3).attr({
        'fill':'tomato'
    })
    g.add(line);
    }
var text=s.text(35,50,'New').attr({
    fill:'white'
})
function anim(){
g.animate({
    transform:'rotate(360 50,50)'
},8000,function(){
   g.animate({
    transform:'rotate(0 50,50)'   
   },0,function(){
       anim()
   })
})
}
anim()
div{
    width:100vw;
    height:100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
<div>
<svg width="100%" height="100%" viewbox="0 0 100 100">
</svg>
</div>

Note I have used vw and vh units for responsiveness

This can also be made with a single polyline element

var s=Snap('svg');
var array=[];
for (var num = 0; num < 24; num++) {
    var rad1 = num * 15 * (Math.PI / 180);
    var rad2 = (num+1) * 15 * (Math.PI / 180);
    var rad3=(num+.5) * 15 * (Math.PI / 180);
    var x1 = (30 * (Math.cos(rad1)) + 50);
    var y1 = (30 * (Math.sin(rad1)) + 50);
    var x2 = (40 * (Math.cos(rad3)) + 50);
    var y2 = (40 * (Math.sin(rad3)) + 50);
    var x3 = (30 * (Math.cos(rad2)) + 50);
    var y3 = (30 * (Math.sin(rad2)) + 50);
      array.push(x1+','+y1+' '+x2+','+y2+' '+x3+','+' '+y3);
    }
var line=s.polyline(array).attr({
        'fill':'tomato'
    })
var text=s.text(35,50,'New').attr({
    fill:'white'
})
div{
  width:100vw;
  height:100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
<div>
<svg width="100%" height="100%" viewbox="0 0 100 100">
</svg>
  </div>
Smukler answered 9/6, 2015 at 10:32 Comment(0)
I
14

This is possible with CSS but after 12 points, requires more than one div.

I have previously used the 12 point burst within projects for alerts and for sale promotion style elements.

12 Point Burst

div {
  background: red;
  width: 80px;
  height: 80px;
  position: absolute;
  text-align: center;
  top: 20px;
  left: 20px;
}
div:before,
div:after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  height: 80px;
  width: 80px;
  background: red;
}
div:before {
  -webkit-transform: rotate(30deg);
  -moz-transform: rotate(30deg);
  -ms-transform: rotate(30deg);
  -o-transform: rotate(30deg);
}
div:after {
  -webkit-transform: rotate(60deg);
  -moz-transform: rotate(60deg);
  -ms-transform: rotate(60deg);
  -o-transform: rotate(60deg);
}
<div></div>

24 Point Burst

div {
    background: red;
    width: 80px;
    height: 80px;
    position: absolute;
    text-align: center;
  top: 20px;
  left: 20px;
}
div:before, div:after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    height: 80px;
    width: 80px;
    background: red;
}
div:before {
    -webkit-transform: rotate(30deg);
       -moz-transform: rotate(30deg);
        -ms-transform: rotate(30deg);
         -o-transform: rotate(30deg);
}
div:after {
    -webkit-transform: rotate(60deg);
       -moz-transform: rotate(60deg);
        -ms-transform: rotate(60deg);
         -o-transform: rotate(60deg);
}

div:nth-child(2) {
  transform: rotate(15deg)
}
<div></div>
<div></div>

36 Point Burst

div {
    background: red;
    width: 80px;
    height: 80px;
    position: absolute;
    text-align: center;
  top: 20px;
  left: 20px;
}
div:before, div:after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    height: 80px;
    width: 80px;
    background: red;
}
div:before {
    -webkit-transform: rotate(30deg);
       -moz-transform: rotate(30deg);
        -ms-transform: rotate(30deg);
         -o-transform: rotate(30deg);
}
div:after {
    -webkit-transform: rotate(60deg);
       -moz-transform: rotate(60deg);
        -ms-transform: rotate(60deg);
         -o-transform: rotate(60deg);
}

div:nth-child(2) {
  transform: rotate(10deg)
}
div:nth-child(3) {
  transform: rotate(20deg)
}
<div></div>
<div></div>
<div></div>

48 Point Burst

div {
  background: red;
  width: 80px;
  height: 80px;
  position: absolute;
  text-align: center;
  top: 20px;
  left: 20px;
}
div:before,
div:after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  height: 80px;
  width: 80px;
  background: red;
}
div:before {
  -webkit-transform: rotate(30deg);
  -moz-transform: rotate(30deg);
  -ms-transform: rotate(30deg);
  -o-transform: rotate(30deg);
}
div:after {
  -webkit-transform: rotate(60deg);
  -moz-transform: rotate(60deg);
  -ms-transform: rotate(60deg);
  -o-transform: rotate(60deg);
}
div:nth-child(2) {
  transform: rotate(7.5deg)
}
div:nth-child(3) {
  transform: rotate(15deg)
}
div:nth-child(4) {
  transform: rotate(22.5deg)
}
<div></div>
<div></div>
<div></div>
<div></div>

For anything above 12 points, i would have to seriously suggest using an image or SVG as the above answer shows due to only requiring one element.

Intension answered 9/6, 2015 at 10:52 Comment(0)
W
11

SVG

I used a single spike like shape (The red shape) Put it inside defs so its not shown.
Then reused the spike shape multiple times and rotated it with its rotation origin sett at the very bottom of the shape.
This then creates a circle like shape with sharp edges.

.POW {
  width: 250px;
  height: 250px;
  border: 1px solid black;
}
<svg class="POW" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <polygon id="spike" points="0,0, -10,-25 0,-50 10,-25"></polygon>
  </defs>
  <g class="spikes">
    <use x="50" y="50" xlink:href="#spike" transform="rotate(20 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(40 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(60 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(80 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(100 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(120 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(140 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(160 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(180 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(200 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(220 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(240 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(260 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(280 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(300 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(320 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(340 50 50)" />
    <use x="50" y="50" fill="red" xlink:href="#spike" transform="rotate(360 50 50)" />
  </g>
</svg>

You can easily create any number of spikes with this solution. Just have the appropriate division on the rotation:

24 points

.POW {
  width: 250px;
  height: 250px;
  border: 1px solid black;
}
<svg class="POW" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <polygon id="spike" points="0,0, -10,-25 0,-50 10,-25"></polygon>
  </defs>
  <g class="spikes">
    <use x="50" y="50" xlink:href="#spike" transform="rotate(0 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(15 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(30 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(45 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(60 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(75 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(90 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(105 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(120 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(135 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(150 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(165 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(180 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(195 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(210 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(225 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(240 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(240 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(255 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(270 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(285 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(300 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(315 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(330 50 50)" />
    
    <use x="50" y="50" fill="red" xlink:href="#spike" transform="rotate(345 50 50)" />
  </g>
</svg>

48 points

.POW {
  width: 250px;
  height: 250px;
  border: 1px solid black;
}
<svg class="POW" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <polygon id="spike" points="0,0, -10,-25 0,-50 10,-25"></polygon>
  </defs>
  <g class="spikes">
    <use x="50" y="50" xlink:href="#spike" transform="rotate(7.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(15 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(22.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(30 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(37.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(45 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(52.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(60 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(67.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(75 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(82.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(90 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(97.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(105 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(112.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(120 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(127.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(135 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(142.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(150 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(157.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(165 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(172.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(180 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(187.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(195 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(202.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(210 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(217.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(225 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(232.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(240 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(247.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(255 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(262.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(270 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(277.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(285 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(292.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(300 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(307.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(315 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(322.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(330 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(337.5 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(345 50 50)" />
    <use x="50" y="50" xlink:href="#spike" transform="rotate(352.5 50 50)" />
    <use x="50" y="50" fill="red" xlink:href="#spike" transform="rotate(360 50 50)" />
  </g>
</svg>

The way to calculate the angle is dividing the points with 360.
Like: 360/48 = 7.5 so each angle needs to be 7.5.

  1. 7.5
  2. 15.0
  3. 22.5
  4. 30
  5. 37.5
    etc.
Watt answered 9/6, 2015 at 11:30 Comment(0)
B
6

Canvas Approach

You can also achieve this using Canvas. The commands for drawing on Canvas are pretty much the same as in SVG. The approach, on a very high level, would be to find points on two circles (one with radius as x and another with a slightly smaller radius) and then connect them together to form a path. When the path is filled, it gives the appearance of a n-point burst.

In the below diagram, the green circle is the bigger circle with radius as x and the blue circle is the smaller inner circle. By plotting points on the circles and connecting them (with lineTo commands), we get the path which is in red. When this path is filled we get the burst appearance. (Note: The inner and outer circles are only for illustration and are not drawn in the actual diagram).

enter image description here


Calculation Logic

  • The X and Y coordinates of each points on the circle can be calculated using the below formula:
    • x = (Radius of circle * Cos(Angle in Radians)) + x coordinate of center
    • y = (Radius of circle * Sin(Angle in Radians)) + y coordinate of center
  • The angle at which the points are plotted on the circle are determined using the below logic:
    • As used in both your and Persijn's answers, the angle is calculated as (360/no. of bursts). 360 is used because it is the total angle within a circle.
    • Angle of the points on the inner circle should be half way between point1 and point2 on the larger circle and hence a delta is added to it. The delta is half of (360/no. of bursts)
  • Angle in Radians = Angle in Degrees * π / 180

window.onload = function() {
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  var defaultBurst = 18;
  var defaultContent = "New";

  function paint(numBurst, text) {
    if (!numBurst) numBurst = defaultBurst;
    if (!text) text = defaultContent;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = 'crimson';
    var angleInRad = Math.PI * (360 / numBurst) / 180;
    var deltaAngleInRad = angleInRad / 2;
    ctx.beginPath();
    ctx.moveTo(75, 150);
    for (i = 0; i <= numBurst; i++) {
      x1 = 75 * Math.cos(angleInRad * i) + 150;
      y1 = 75 * Math.sin(angleInRad * i) + 150;
      x2 = 60 * Math.cos((angleInRad * i) + deltaAngleInRad) + 150;
      y2 = 60 * Math.sin((angleInRad * i) + deltaAngleInRad) + 150;
      ctx.lineTo(x1, y1);
      ctx.lineTo(x2, y2);
    }
    ctx.closePath();
    /* Add shadow only for shape */
    ctx.shadowOffsetX = -5;
    ctx.shadowOffsetY = 5;
    ctx.shadowBlur = 5;
    ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
    ctx.fill();
    ctx.font = "32px Arial";
    ctx.textAlign = "center";
    ctx.fillStyle = "gold";
    /* Nullify shadow for text */
    ctx.shadowOffsetX = 0;
    ctx.shadowOffsetY = 0;
    ctx.fillText(text, 150, 160, 120);
  }
  paint();
  var slider = document.getElementById('burst');
  var textInput = document.getElementById('content');
  slider.addEventListener('change', function() {
    paint(this.value, textInput.value);
  });

  textInput.addEventListener('blur', function() {
    paint(slider.value, this.value);
  });
}
/* For demo only */

.controls {
  float: right;
  padding: 5px;
  margin: 50px 20px;
  line-height: 25px;
  border: 1px solid;
  box-shadow: 1px 1px 0px #222;
}
label,
input {
  display: inline-block;
  vertical-align: middle;
  text-align: left;
}
h3 {
  padding: 10px;
  text-align: center;
}
label {
  width: 100px;
}
input[type='range'],
input[type='text'] {
  width: 100px;
}
body {
  font-family: Calibri;
  background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<canvas id='canvas' height='300px' width='300px'></canvas>
<div class='controls'>
  <h3>Controls</h3>

  <label for="burst">Change Burst:</label>
  <input id="burst" class="slider" type="range" value="18" min="12" max="36" step='2' title="Adjust slider to increase or decrease burst" />
  <br/>
  <label for="content">Text Content:</label>
  <input type="text" id="content" maxlength="5" />
</div>

Advanced Demo

Check out this CodePen for an advanced demo with features like path creation animation, shadows, control over all the features etc.


Usage Advice

If you want a fixed size image somewhere in the page then Canvas is as good as SVG. However, if you would need an image that can be scaled to any size, Canvas is not the right choice because Canvas is raster based and becomes pixelated or blurred when scaled.

If your shape would need a dynamic number of bursts and/or text, Canvas would be more preferable over SVG and CSS because you don't have to perform any DOM manipulations.

Broadway answered 17/6, 2015 at 12:53 Comment(0)
A
0

I made an online generator to create the shape using only CSS and clip-path: https://css-generators.com/starburst-shape/. It also provides the border-only version and since it uses clip-path, we can have gradient coloration

.box {
  width: 200px;
  aspect-ratio: 1;
  background: linear-gradient(red, blue);
  display: inline-block;
  margin: 10px;
  clip-path: polygon(100.00% 50.00%, 79.54% 55.21%, 96.98% 67.10%, 75.98% 65.00%, 88.30% 82.14%, 69.28% 72.98%, 75.00% 93.30%, 60.26% 78.19%, 58.68% 99.24%, 50.00% 80.00%, 41.32% 99.24%, 39.74% 78.19%, 25.00% 93.30%, 30.72% 72.98%, 11.70% 82.14%, 24.02% 65.00%, 3.02% 67.10%, 20.46% 55.21%, 0.00% 50.00%, 20.46% 44.79%, 3.02% 32.90%, 24.02% 35.00%, 11.70% 17.86%, 30.72% 27.02%, 25.00% 6.70%, 39.74% 21.81%, 41.32% 0.76%, 50.00% 20.00%, 58.68% 0.76%, 60.26% 21.81%, 75.00% 6.70%, 69.28% 27.02%, 88.30% 17.86%, 75.98% 35.00%, 96.98% 32.90%, 79.54% 44.79%);
}

.alt {
  clip-path: polygon(100.00% 50.00%, 86.54% 55.79%, 97.55% 65.45%, 82.97% 66.80%, 90.45% 79.39%, 76.16% 76.16%, 79.39% 90.45%, 66.80% 82.97%, 65.45% 97.55%, 55.79% 86.54%, 50.00% 100.00%, 44.21% 86.54%, 34.55% 97.55%, 33.20% 82.97%, 20.61% 90.45%, 23.84% 76.16%, 9.55% 79.39%, 17.03% 66.80%, 2.45% 65.45%, 13.46% 55.79%, 0.00% 50.00%, 13.46% 44.21%, 2.45% 34.55%, 17.03% 33.20%, 9.55% 20.61%, 23.84% 23.84%, 20.61% 9.55%, 33.20% 17.03%, 34.55% 2.45%, 44.21% 13.46%, 50.00% 0.00%, 55.79% 13.46%, 65.45% 2.45%, 66.80% 17.03%, 79.39% 9.55%, 76.16% 23.84%, 90.45% 20.61%, 82.97% 33.20%, 97.55% 34.55%, 86.54% 44.21%, 100% 50%, calc(100% - 25px) 50%, calc(86.54% - 18.27px) calc(44.21% - -2.89px), calc(97.55% - 23.78px) calc(34.55% - -7.73px), calc(82.97% - 16.48px) calc(33.20% - -8.40px), calc(90.45% - 20.23px) calc(20.61% - -14.69px), calc(76.16% - 13.08px) calc(23.84% - -13.08px), calc(79.39% - 14.69px) calc(9.55% - -20.23px), calc(66.80% - 8.40px) calc(17.03% - -16.48px), calc(65.45% - 7.73px) calc(2.45% - -23.78px), calc(55.79% - 2.89px) calc(13.46% - -18.27px), calc(50.00% - -0.00px) calc(0.00% - -25.00px), calc(44.21% - -2.89px) calc(13.46% - -18.27px), calc(34.55% - -7.73px) calc(2.45% - -23.78px), calc(33.20% - -8.40px) calc(17.03% - -16.48px), calc(20.61% - -14.69px) calc(9.55% - -20.23px), calc(23.84% - -13.08px) calc(23.84% - -13.08px), calc(9.55% - -20.23px) calc(20.61% - -14.69px), calc(17.03% - -16.48px) calc(33.20% - -8.40px), calc(2.45% - -23.78px) calc(34.55% - -7.73px), calc(13.46% - -18.27px) calc(44.21% - -2.89px), calc(0.00% - -25.00px) calc(50.00% - 0.00px), calc(13.46% - -18.27px) calc(55.79% - 2.89px), calc(2.45% - -23.78px) calc(65.45% - 7.73px), calc(17.03% - -16.48px) calc(66.80% - 8.40px), calc(9.55% - -20.23px) calc(79.39% - 14.69px), calc(23.84% - -13.08px) calc(76.16% - 13.08px), calc(20.61% - -14.69px) calc(90.45% - 20.23px), calc(33.20% - -8.40px) calc(82.97% - 16.48px), calc(34.55% - -7.73px) calc(97.55% - 23.78px), calc(44.21% - -2.89px) calc(86.54% - 18.27px), calc(50.00% - 0.00px) calc(100.00% - 25.00px), calc(55.79% - 2.89px) calc(86.54% - 18.27px), calc(65.45% - 7.73px) calc(97.55% - 23.78px), calc(66.80% - 8.40px) calc(82.97% - 16.48px), calc(79.39% - 14.69px) calc(90.45% - 20.23px), calc(76.16% - 13.08px) calc(76.16% - 13.08px), calc(90.45% - 20.23px) calc(79.39% - 14.69px), calc(82.97% - 16.48px) calc(66.80% - 8.40px), calc(97.55% - 23.78px) calc(65.45% - 7.73px), calc(86.54% - 18.27px) calc(55.79% - 2.89px), calc(100.00% - 25.00px) calc(50.00% - 0.00px));
}
<div class="box"></div>
<div class="box alt"></div>

Zig zag starburst shape using CSS

Attaboy answered 24/10, 2022 at 9:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.