Skip to main content

Home | Math Display Experiments | JSXGraph Internal Angles of a Triangle

Page by Murray Bourne, IntMath.com. Last updated: 21 Feb 2016

JSXGraph Internal Angles of a Triangle

Last updated: 21 February 2016.

In the following interactive graph, we want all our angles to show as internal angles of the triangle.

However, by default, JSXGraph displays angle sizes based on the order of the points defining each angle.

In the following triangle, JSXGraph reads ∠ABC as the external reflex angle 284.6°. If we want the internal angle, we need to reverse the first and third points: ∠CBA = 75.4°

When we drag the points, as soon as one of the angles is more than 180° (e.g. drag point C beyond line AB), all will "snap" to show the external angle.

The Problem: External angles

Drag any of the angle points through the opposite side of the triangle. You'll see reflex angles.

Here's the code used:


board = JXG.JSXGraph.initBoard('jxgbox0',
   {axis:false,boundingbox:[-5.9,8,5.9,-5.9],
	keepaspectratio:true,showCopyright:false,
	showNavigation:false});
var qr = [], arc2,isInDragMode;
qr[1] = board.create('point', [0,0], 
  {style:5,fillColor:'#ff00ff'});
qr[2] = board.create('point', [5,0], 
  {style:5,fillColor:'#ff00ff'});
qr[3] = board.create('point', [3.85,4.4],  
  {style:5,fillColor:'#ff00ff'});
  
var triArr1 = [qr[3],qr[2],qr[1]];
var tri = board.createElement('polygon',triArr1,
  {strokeWidth:2, strokeColor:'#dd00dd',highlight:false});
  
var arc1 = board.create('angle',triArr1,{radius:1,name:'θ2'});
var triArr2 = [qr[2],qr[1],qr[3]];
var arc2 = board.create('angle',triArr2,{radius:1,name:'θ1'});
var triArr3 = [qr[1],qr[3],qr[2]];
var arc3 = board.create('angle',triArr3,{radius:1,name:'θ3'});

board.create('text', [-5, 3, function () {
    return '<p>&theta;_1 = ' + (arc2.Value() * 180 / Math.PI).toFixed(1) + '&deg;</p>'
	 +'<p>&theta;_2 = ' + (arc1.Value() * 180 / Math.PI).toFixed(1) + '&deg;</p>'
	 +'<p>&theta;_3 = ' + (arc3.Value() * 180 / Math.PI).toFixed(1) + '&deg;</p>';
}],{highlight:false,fixed:true}); 

A workaround

The following code swaps the angle point order when any angle becomes reflex.


board = JXG.JSXGraph.initBoard('jxgbox1',
   {axis:false,boundingbox:[-5.9,8,5.9,-5.9],
	keepaspectratio:true,showCopyright:false,
	showNavigation:false});
var qr = [], arc2,isInDragMode;
qr[1] = board.create('point', [0,0], 
  {style:5,fillColor:'#ff00ff'});
qr[2] = board.create('point', [5,0], 
  {style:5,fillColor:'#ff00ff'});
qr[3] = board.create('point', [3.85,4.4], 
  {style:5,fillColor:'#ff00ff'});
  
var triArr1 = [qr[3],qr[2],qr[1]];
var tri = board.createElement('polygon',triArr1,
  {strokeWidth:2, strokeColor:'#dd00dd',highlight:false});
  
var arc1 = board.create('angle',triArr1,{radius:1,name:'&theta;2'});
var triArr2 = [qr[2],qr[1],qr[3]];
var arc2 = board.create('angle',triArr2,{radius:1,name:'&theta;1'});
var triArr3 = [qr[1],qr[3],qr[2]];
var arc3 = board.create('angle',triArr3,{radius:1,name:'&theta;3'});

var updateG = function() {
	board.suspendUpdate();
	if( arc1.Value() > Math.PI) {
		board.removeObject(arc1);
		triArr1 = [triArr1[2], triArr1[1], triArr1[0]];	
		arc1 = board.create('angle',triArr1,{radius:1,name:'&theta;2'});			
		board.removeObject(arc2);
		triArr2 = [triArr2[2], triArr2[1], triArr2[0]];
		arc2 = board.create('angle',triArr2,{radius:1,name:'&theta;1'});			
		board.removeObject(arc3);
		triArr3 = [triArr3[2], triArr3[1], triArr3[0]];
		arc3 = board.create('angle',triArr3,{radius:1,name:'&theta;3'});				
	}		
	board.unsuspendUpdate();
}
qr[1].on('drag',function(){
	updateG();
});
qr[2].on('drag',function(){
	updateG();
});
qr[3].on('drag',function(){
	updateG();
}); 

board.create('text', [-5, 3, function () {
    return '<p>&theta;_1 = ' + (arc2.Value() * 180 / Math.PI).toFixed(1) + '&deg;</p>'+
	 '<p>&theta;_2 = ' + (arc1.Value() * 180 / Math.PI).toFixed(1) + '&deg;</p>'+
	 '<p>&theta;_3 = ' + (arc3.Value() * 180 / Math.PI).toFixed(1) + '&deg;</p>'+
	 '<p>&theta;_1 + &theta;_2 + &theta;_3 = 180&deg;</p>';
}],{highlight:false,fixed:true});

Easier Alternative?

Since version 0.99.2, it has been possible to create angles as "nonreflex" using board.create('nonreflexangle'..., as follows.

However, while the indicated angle is now internal, the magnitude of the angle given by arc1.Value() remains the reflex angle.

board2 = JXG.JSXGraph.initBoard('jxgbox2',
   {axis:false,boundingbox:[-5.9,8,5.9,-5.9],
	keepaspectratio:true,showCopyright:false,
	showNavigation:false});
var qr = [], arc2,isInDragMode;

qr[1] = board2.create('point', [0,0], 
  {style:5,fillColor:'#ff00ff'});
qr[2] = board2.create('point', [5,0], 
  {style:5,fillColor:'#ff00ff'});
qr[3] = board2.create('point', [3.85,4.4],  
  {style:5,fillColor:'#ff00ff'});
  
var triArr1 = [qr[3],qr[2],qr[1]];

var tri = board2.createElement('polygon',triArr1,
  {strokeWidth:2, strokeColor:'#dd00dd',highlight:false});
var arc1 = board2.create('nonreflexangle',triArr1,
   {radius:1,name:'&theta;2'});
var triArr2 = [qr[2],qr[1],qr[3]];
var arc2 = board2.create('nonreflexangle',triArr2,
   {radius:1,name:'&theta;1'});
var triArr3 = [qr[1],qr[3],qr[2]];
var arc3 = board2.create('nonreflexangle',triArr3,
   {radius:1,name:'&theta;3'});
	
board2.create('text', [-5, 3, function () {
    return '<p>&theta;_1 = ' + (arc2.Value() * 180 / Math.PI).toFixed(1) + '&deg;</p>'+
	 '<p>&theta;_2 = ' + (arc1.Value() * 180 / Math.PI).toFixed(1) + '&deg;</p>'+
	 '<p>&theta;_3 = ' + (arc3.Value() * 180 / Math.PI).toFixed(1) + '&deg;</p>';
}],{highlight:false,fixed:true}); 

A fix for reflex angle magnitudes

In this version, we test if the angle is greater than 180°, and if so, output the magnitude of the triangle's associated internal angle.

board2 = JXG.JSXGraph.initBoard('jxgbox3',
   {axis:false,boundingbox:[-5.9,8,5.9,-5.9],
	keepaspectratio:true,showCopyright:false,
	showNavigation:false});
var qr = [], arc2,isInDragMode;
qr[1] = board2.create('point', [0,0], 
  {style:5,fillColor:'#ff00ff'});
qr[2] = board2.create('point', [5,0], 
  {style:5,fillColor:'#ff00ff'});
qr[3] = board2.create('point', [3.85,4.4],  
  {style:5,fillColor:'#ff00ff'});
  
var triArr1 = [qr[3],qr[2],qr[1]];
var tri = board2.createElement('polygon',triArr1,
  {strokeWidth:2, strokeColor:'#dd00dd',highlight:false});
var arc1 = board2.create('nonreflexangle',triArr1,
   {radius:1,name:'&theta;2'});
var triArr2 = [qr[2],qr[1],qr[3]];
var arc2 = board2.create('nonreflexangle',triArr2,
   {radius:1,name:'&theta;1'});
var triArr3 = [qr[1],qr[3],qr[2]];
var arc3 = board2.create('nonreflexangle',triArr3,
   {radius:1,name:'&theta;3'});
	
board2.create('text', [-5, 3, function () {
	if(arc2.Value() > Math.PI) {
		ang2 =  (360 - arc2.Value() * 180 / Math.PI).toFixed(1);
		ang1 =  (360 - arc1.Value() * 180 / Math.PI).toFixed(1);
		ang3 =  (360 - arc3.Value() * 180 / Math.PI).toFixed(1);
	} else {
		ang2 =  (arc2.Value() * 180 / Math.PI).toFixed(1);
		ang1 =  (arc1.Value() * 180 / Math.PI).toFixed(1);
		ang3 =  (arc3.Value() * 180 / Math.PI).toFixed(1);
	}
    return '<p>&theta;_1 = ' + ang2 + '&deg;</p>'+
	 '<p>&theta;_2 = '  + ang1 +  '&deg;</p>'+
	 '<p>&theta;_3 = '  + ang3 +  '&deg;</p>'+
	 '<p>&theta;_1 + &theta;_2 + &theta;_3 = 180&deg;</p>';
}],{highlight:false,fixed:true}); 

Any questions or comments on these examples, please add them here.

Search IntMath, blog and Forum

Search IntMath