Is there any way to add angular gradient to jQuery knob plugin, so that it starts from one color and along the arc, changes into another?
I digged the internet for a solution but no one ever tried this or posted a solution. Finally I am posting a Q&A. If anyone has a better solution, please share with us.
During the initialization, I have overridden the draw method and checked for the attribute shaded="true". If it's there, then a gradient is formed, starting from white and moving towards fgColor. To chose starting color other than white, set the attribute shadeColor="#(color hex code)".
<input class="knob" value="95" autocomplete="off" data-readOnly=true data-fgColor="#FF0000" data-bgColor="transparent" shaded="1" shadeColor="#00FF00"/>
<script>
$(function(){
$('.knob').knob({
draw : function () {
var a = this.angle(this.cv) // Angle
, sa = this.startAngle // Previous start angle
, sat = this.startAngle // Start angle
, ea // Previous end angle
, eat = sat + a // End angle
, r = 1;
this.g.lineWidth = this.lineWidth;
if(this.$.attr('shaded')){
var color1 = r ? this.o.fgColor : this.fgColor;
var color2 = this.$.attr('shadeColor') ? this.$.attr('shadeColor') : '#ffffff';
var grad = getGradient(color2, color1);
var saDeg = parseInt((sa * 180 / Math.PI) % 360);
var eatDeg = parseInt((eat * 180 / Math.PI) % 360);
for(var angle = saDeg;(angle % 360) != eatDeg;angle++){
sat = angle * (Math.PI / 180);
eat = (angle + 2) * (Math.PI / 180);
if(grad.color2[0] != grad.color1[0] && (angle + 1) % grad.steps[0] == 0){
grad.color1[0] += grad.adder[0];
}
if(grad.color2[1] != grad.color1[1] && (angle + 1) % grad.steps[1] == 0){
grad.color1[1] += grad.adder[1];
}
if(grad.color2[2] != grad.color1[2] && (angle + 1) % grad.steps[2] == 0){
grad.color1[2] += grad.adder[2];
}
color = '#' + toHex(grad.color1[0]) + toHex(grad.color1[1]) + toHex(grad.color1[2]);
this.g.beginPath();
this.g.strokeStyle = color;
this.g.arc(this.xy, this.xy, this.radius, sat, eat, false);
this.g.stroke();
}
} else {
this.g.beginPath();
this.g.strokeStyle = r ? this.o.fgColor : this.fgColor ;
this.g.arc(this.xy, this.xy, this.radius, sat, eat, false);
this.g.stroke();
}
return false;
}
});
});
function getGradient(color1, color2){
var ret = new Object();
ret.color1 = new Array();
ret.color2 = new Array();
ret.steps = new Array();
ret.adder = new Array();
color1 = color1.replace('#','');
ret.color1[0] = parseInt(color1.slice(0,2), 16),
ret.color1[1] = parseInt(color1.slice(2,4), 16),
ret.color1[2] = parseInt(color1.slice(4,6), 16);
color2 = color2.replace('#','');
ret.color2[0] = parseInt(color2.slice(0,2), 16),
ret.color2[1] = parseInt(color2.slice(2,4), 16),
ret.color2[2] = parseInt(color2.slice(4,6), 16);
ret.steps[0] = (ret.color1[0] == ret.color2[0])? 0 : parseInt(360 / Math.abs(ret.color1[0] - ret.color2[0])),
ret.steps[1] = (ret.color1[1] == ret.color2[1])? 0 : parseInt(360 / Math.abs(ret.color1[1] - ret.color2[1])),
ret.steps[2] = (ret.color1[2] == ret.color2[2])? 0 : parseInt(360 / Math.abs(ret.color1[2] - ret.color2[2])),
ret.adder[0] = (ret.color1[0] > ret.color2[0])? -1 : 1;
ret.adder[1] = (ret.color1[1] > ret.color2[1])? -1 : 1;
ret.adder[2] = (ret.color1[2] > ret.color2[2])? -1 : 1;
return ret;
}
function toHex(number){
number = number.toString(16);
if(number.length < 2){
number = '0' + number;
}
return number;
}
</script>
It draws a separate arc for each degree (with arc angle of 2 degrees instead of one for the sake of smoothness). The colors of arcs go through a transition from fgColor to shadeColor.
The color mixing effect is like paint mixing rather than light mixing, so if you start from green and go towards red, you won't get the yellow shade in the center. It would look cool with light mixing effect but don't know how to do that exactly. Also it is not a well optimized code, it's just a solution. Huge room for improvement..
Great, exactly what I needed! I added the "cursor" option as well, because that was the only thing that was not working yet.
var drawGradient = function () {
var a = this.angle(this.cv) // Angle
, sa = this.startAngle // Previous start angle
, sat = this.startAngle // Start angle
, eat = sat + a // End angle
, r = 1;
this.g.lineCap = this.lineCap;
this.g.lineWidth = this.lineWidth;
if (this.o.bgColor !== "none") {
this.g.beginPath();
this.g.strokeStyle = this.o.bgColor;
this.g.arc(this.xy, this.xy, this.radius, this.endAngle - 0.00001, this.startAngle + 0.00001, true);
this.g.stroke();
}
if (this.$.attr('shaded')) {
var color1 = r ? this.o.fgColor : this.fgColor;
var color2 = this.$.attr('shadeColor') ? this.$.attr('shadeColor') : '#ffffff';
var grad = getGradient(color2, color1);
var saDeg = parseInt((sa * 180 / Math.PI) % 360);
var eatDeg = parseInt((eat * 180 / Math.PI));
var normalizedAngle = 0
var normalizedEatAngle = eatDeg - saDeg;
if(this.o.cursor == true) {
var size = 40;
} else if(this.o.cursor != false) {
var size = this.o.cursor;
this.o.cursor = true;
}
if(this.o.cursor) {
if(normalizedEatAngle <= size) {
normalizedEatAngle = size;
}
}
for (var angle = saDeg; normalizedAngle < normalizedEatAngle; angle++, normalizedAngle++) {
sat = angle * (Math.PI / 180);
eat = (angle + 2) * (Math.PI / 180);
if (grad.color2[0] != grad.color1[0] && (angle + 1) % grad.steps[0] == 0) {
grad.color1[0] += grad.adder[0];
}
if (grad.color2[1] != grad.color1[1] && (angle + 1) % grad.steps[1] == 0) {
grad.color1[1] += grad.adder[1];
}
if (grad.color2[2] != grad.color1[2] && (angle + 1) % grad.steps[2] == 0) {
grad.color1[2] += grad.adder[2];
}
if(!this.o.cursor || (normalizedAngle + size) > normalizedEatAngle) {
color = '#' + toHex(grad.color1[0]) + toHex(grad.color1[1]) + toHex(grad.color1[2]);
this.g.beginPath();
this.g.strokeStyle = color;
this.g.arc(this.xy, this.xy, this.radius, sat, eat, false);
this.g.stroke();
}
}
} else {
this.g.beginPath();
this.g.strokeStyle = r ? this.o.fgColor : this.fgColor;
this.g.arc(this.xy, this.xy, this.radius, sat, eat, false);
this.g.stroke();
}
return false;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With