Skip to content

Commit 762352e

Browse files
authored
Merge pull request #279 from GaryKeeble/Rates-graph-scale
Add rates graph balloon labels for maximum rates
2 parents ffb6cfe + 5c6972c commit 762352e

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

tabs/pid_tuning.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,78 @@ TABS.pid_tuning.initialize = function (callback) {
430430
}
431431
}
432432

433+
function drawAxisLabel(curveContext, axisLabel, x, y, align, color) {
434+
435+
curveContext.fillStyle = color || '#000000' ;
436+
curveContext.textAlign = align || 'center';
437+
curveContext.fillText(axisLabel, x, y);
438+
}
439+
440+
function drawBalloonLabel(curveContext, axisLabel, x, y, align, color, borderColor, textColor) {
441+
442+
/**
443+
* curveContext is the canvas to draw on
444+
* axisLabel is the string to display in the center of the balloon
445+
* x, y are the coordinates of the point of the balloon
446+
* align is whether the balloon appears to the left (align 'right') or right (align left) of the x,y coordinates
447+
* color, borderColor and textColor are the fill color, border color and text color of the balloon
448+
*/
449+
450+
const DEFAULT_OFFSET = 50; // in canvas scale; this is the horizontal length of the pointer
451+
const DEFAULT_RADIUS = 10; // in canvas scale, this is the radius around the balloon
452+
453+
const fontSize = parseInt(curveContext.font);
454+
455+
// calculate the width and height required for the balloon
456+
const width = (curveContext.measureText(axisLabel).width * 1.2);
457+
const height = fontSize * 1.5; // the balloon is bigger than the text height
458+
const pointerY = y; // always point to the required Y coordinate, even if we move the balloon itself to keep it on the canvas
459+
460+
// setup balloon background
461+
curveContext.fillStyle = color || '#ffffff' ;
462+
curveContext.strokeStyle = borderColor || '#000000' ;
463+
464+
// adjust the coordinates for determine where the balloon background should be drawn
465+
x += ((align=='right')?-(width + DEFAULT_OFFSET):0) + ((align=='left')?DEFAULT_OFFSET:0);
466+
y -= (height/2); if(y<0) y=0; else if(y>curveContext.height) y=curveContext.height; // prevent balloon from going out of canvas
467+
468+
var pointerLength = (height - 2 * DEFAULT_RADIUS ) / 6;
469+
470+
curveContext.beginPath();
471+
curveContext.moveTo(x + DEFAULT_RADIUS, y);
472+
curveContext.lineTo(x + width - DEFAULT_RADIUS, y);
473+
curveContext.quadraticCurveTo(x + width, y, x + width, y + DEFAULT_RADIUS);
474+
475+
if(align=='right') { // point is to the right
476+
curveContext.lineTo(x + width, y + DEFAULT_RADIUS + pointerLength);
477+
curveContext.lineTo(x + width + DEFAULT_OFFSET, pointerY); // point
478+
curveContext.lineTo(x + width, y + height - DEFAULT_RADIUS - pointerLength);
479+
}
480+
curveContext.lineTo(x + width, y + height - DEFAULT_RADIUS);
481+
482+
curveContext.quadraticCurveTo(x + width, y + height, x + width - DEFAULT_RADIUS, y + height);
483+
curveContext.lineTo(x + DEFAULT_RADIUS, y + height);
484+
curveContext.quadraticCurveTo(x, y + height, x, y + height - DEFAULT_RADIUS);
485+
486+
if(align=='left') { // point is to the left
487+
curveContext.lineTo(x, y + height - DEFAULT_RADIUS - pointerLength);
488+
curveContext.lineTo(x - DEFAULT_OFFSET, pointerY); // point
489+
curveContext.lineTo(x, y + DEFAULT_RADIUS - pointerLength);
490+
}
491+
curveContext.lineTo(x, y + DEFAULT_RADIUS);
492+
493+
curveContext.quadraticCurveTo(x, y, x + DEFAULT_RADIUS, y);
494+
curveContext.closePath();
495+
496+
// fill in the balloon background
497+
curveContext.fill();
498+
curveContext.stroke();
499+
500+
// and add the label
501+
drawAxisLabel(curveContext, axisLabel, x + (width/2), y + (height + fontSize)/2 - 4, 'center', textColor);
502+
503+
}
504+
433505
function checkInput(element) {
434506
var value = parseFloat(element.val());
435507
if (value < parseFloat(element.prop('min'))
@@ -713,6 +785,7 @@ TABS.pid_tuning.initialize = function (callback) {
713785
var curveWidth = rcCurveElement.width;
714786

715787
curveContext.clearRect(0, 0, curveWidth, curveHeight);
788+
curveContext.font = "24pt Verdana, Arial, sans-serif";
716789

717790
var maxAngularVel;
718791
if (!useLegacyCurve) {
@@ -721,7 +794,11 @@ TABS.pid_tuning.initialize = function (callback) {
721794
printMaxAngularVel(self.currentRates.pitch_rate, self.currentRates.rc_rate, self.currentRates.rc_expo, self.currentRates.superexpo, self.currentRates.deadband, maxAngularVelPitchElement),
722795
printMaxAngularVel(self.currentRates.yaw_rate, self.currentRates.rc_rate_yaw, self.currentRates.rc_yaw_expo, self.currentRates.superexpo, self.currentRates.yawDeadband, maxAngularVelYawElement));
723796

797+
// make maxAngularVel multiple of 200deg/s so that the auto-scale doesn't keep changing for small changes of the maximum curve
798+
maxAngularVel = Math.ceil(maxAngularVel/200) * 200;
799+
724800
drawAxes(curveContext, curveWidth, curveHeight, (curveHeight / 2) / maxAngularVel * 360);
801+
drawAxisLabel(curveContext, maxAngularVel.toFixed(0) + ' deg/s', (curveWidth / 2) - 10, parseInt(curveContext.font)*1.2, 'right');
725802
} else {
726803
maxAngularVel = 0;
727804
}
@@ -732,6 +809,17 @@ TABS.pid_tuning.initialize = function (callback) {
732809
drawCurve(self.currentRates.pitch_rate, self.currentRates.rc_rate, self.currentRates.rc_expo, self.currentRates.superexpo, self.currentRates.deadband, maxAngularVel, '#00ff00', -4, curveContext);
733810
drawCurve(self.currentRates.yaw_rate, self.currentRates.rc_rate_yaw, self.currentRates.rc_yaw_expo, self.currentRates.superexpo, self.currentRates.yawDeadband, maxAngularVel, '#0000ff', 4, curveContext);
734811

812+
if (!useLegacyCurve && maxAngularVel) {
813+
var maxAngularVelRoll = maxAngularVelRollElement.text() + ' deg/s',
814+
maxAngularVelPitch = maxAngularVelPitchElement.text() + ' deg/s',
815+
maxAngularVelYaw = maxAngularVelYawElement.text() + ' deg/s',
816+
rateScaling = (curveHeight / 2) / maxAngularVel;
817+
818+
drawBalloonLabel(curveContext, maxAngularVelRoll, curveWidth, rateScaling * (maxAngularVel - parseInt(maxAngularVelRoll)), 'right', '#FF8080', '#FF8080', '#000000');
819+
drawBalloonLabel(curveContext, maxAngularVelPitch, curveWidth, rateScaling * (maxAngularVel - parseInt(maxAngularVelPitch)), 'right', '#80FF80', '#80FF80', '#000000');
820+
drawBalloonLabel(curveContext, maxAngularVelYaw, curveWidth, rateScaling * (maxAngularVel - parseInt(maxAngularVelYaw)), 'right', '#8080FF', '#8080FF', '#000000');
821+
}
822+
735823
updateNeeded = false;
736824
}
737825
}, 0);

0 commit comments

Comments
 (0)