Adding the JavaScript

Now that we have discussed a little of the trigonometry necessary to draw our SVG chart, let me step through the JavaScript we need to add to make our code work:


<script>
document.getElementById("min_angle").onchange = function() {
var min_angle = Number(this.value);
var max_angle = Number(document.getElementById
("max_angle").value);

if( min_angle >= max_angle ) {
max_angle = min_angle + 1;
document.getElementById("max_angle").value = max_angle;
}

if( min_angle < this.min ) {
min_angle = this.min;
this.value = min_angle;
}
SetPie( min_angle / 180 * Math.PI, max_angle / 180 * Math.PI );
}

document.getElementById("max_angle").onchange = function() {
var min_angle = Number(document.getElementById
("min_angle").value);
var max_angle = Number(this.value);

if( min_angle >= max_angle ) {
min_angle = max_angle - 1;
document.getElementById("min_angle").value = min_angle;
}

if( max_angle > this.max ) {
max_angle = this.max;
this.value = max_angle;
}

SetPie( min_angle / 180 * Math.PI, max_angle / 180 * Math.PI );
}

function SetPie( start_angle, end_angle ) {
const svg = document.getElementById('pie');
const start_x = Math.cos( start_angle );
const start_y = Math.sin( start_angle );

const end_x = Math.cos( end_angle );
const end_y = Math.sin( end_angle );
var arc_flag_1 = 0;
var arc_flag_2 = 0;

if( end_angle - start_angle <= 3.14) {
arc_flag_1 = 0;
arc_flag_2 = 1;
}
else {
arc_flag_1 = 1;
arc_flag_2 = 0;
}

const path_data_1 =
`M 0 0 L ${start_x} ${start_y} A 1 1 0 ${arc_flag_1} 1
${end_x} ${end_y} L 0 0`;

const path_1 = document.createElementNS
('http://www.w3.org/2000/svg', 'path');
path_1.setAttribute('d', path_data_1);
path_1.setAttribute('fill', 'red');
svg.appendChild(path_1);

const path_data_2 =
`M 0 0 L ${end_x} ${end_y} A 1 1 0 ${arc_flag_2} 1
${start_x} ${start_y} L 0 0`;

const path_2 =
document.createElementNS('http://www.w3.org/2000/svg', 'path');
path_2.setAttribute('d', path_data_2);
path_2.setAttribute('fill', 'blue');
svg.appendChild(path_2);
}

SetPie( Number(document.getElementById("min_angle").value) / 180 *
Math.PI,
Number(document.getElementById("max_angle").value) / 180 * Math.PI );
</script>

Even though it is the last function in this code, I would like to begin by explaining the SetPie function, which is used to set the SVG pie chart that shows the emission angle range in red that the user has entered. Way back when we set up the SVG tag, we set the viewport to go from x and y values of -1 to 1. That is great, because using Math.cos and Math.sin will give us the values of the X and Y coordinates for the unit circle, which has a radius of 1 and so those values will also run from -1 to 1.

We use document.getElementById('pie') to grab the svg element from the DOM so we can modify it based on a change to the angle values. Next, we get the x and y coordinates on a unit circle with the Math.cos and Math.sin functions, respectively. We then do the same thing to get the ending x and y coordinates using the end_angle:

const end_x = Math.cos( end_angle );
const end_y = Math.sin( end_angle );

What we need to do in SVG is draw two paths. The first path will be drawn in red and will represent the angle where the particle system emitter will emit particles. The second path will be drawn in blue and will represent the part of our emission circle where we will not emit particles. When we draw an SVG arc, we give the arc two points and tell it with a flag if we need to take the long way (obtuse angle) or the short way (acute angle) around the circle. We do this by checking to see if the emission angle is less than π and set a flag that will go into our SVG based on this:

if( end_angle - start_angle <= 3.14) {
arc_flag_1 = 0;
arc_flag_2 = 1;
}
else {
arc_flag_1 = 1;
arc_flag_2 = 0;
}

Now, we need to define the path data and put it into the SVG path object. The following code sets the path data for the portion of our emitter in which we emit our particles:

const path_data_1 = `M 0 0 L ${start_x} ${start_y} A 1 1 0 ${arc_flag_1} 1 ${end_x} ${end_y} L 0 0`;

const path_1 = document.createElementNS('http://www.w3.org/2000/svg',
'path');
path_1.setAttribute('d', path_data_1);
path_1.setAttribute('fill', 'red');
svg.appendChild(path_1);

A series of commands define path data in SVG. If you look at the definition of path_data_1, it begins with M 0 0, which tells SVG to move the cursor to position 0, 0 without drawing. The next command is L ${start_x} ${start_y}. Because we are using a string template literal, ${start_x} and ${start_y} are replaced with the values in the start_x and start_y variables. This command draws a line from the current location we have moved to in the previous step (0,0) to the coordinates start_x and start_y. The next command in our path is the Arc command and begins with AA 1 1 0 ${arc_flag_1} 1 ${end_x} ${end_y}.

The first two parameters, 1 1, are the x and y radius of an ellipse. Because we want a unit circle, both of these values are 1. The 0 that follows is an X-axis rotation that SVG uses when drawing an ellipse. Because we are drawing a circle, we set this to 0. The value after that is ${arc_flag_1}. That is used to set the large arc flag, which tells SVG if we are drawing the obtuse arc (we set the value to 1) or the acute arc (we set the value to 0). The value after this is the sweep flag. This flag determines if we are drawing in the clockwise (value is 1) or counter-clockwise (value is 0) direction. We always want to draw in the clockwise direction, so this value is going to be 1. The last two parameters in our arc command are ${end_x} ${end_y}. These values are the end position of our arc, which we had determined earlier by getting the cosine and sine of our ending angle. After we have completed our arc, we finish our shape by drawing a line back to the 0,0 coordinate using the L 0 0 line command.

After we have drawn the emission angle in red, we cover the remainder of the circle in blue with a second path by drawing from the ending position to the starting position.

In the next section, we are going to build a simple particle emitter configuration tool.