Cyb3rMann Cyb3rMann - 3 months ago 26
Javascript Question

Change button attribute on hide/show canvas

Whilst learning, i keep going back over what i have done to understand it properly, make changes and improvements. At the moment, i am going over my hide/show function.

I have 3 buttons which controls the visibility of their respective canvases.
My code did look like this:

function toggleRedDot(){
document.getElementById('btnRed').click(); {
if(canvas.style.visibility=='hidden'){
canvas.style.visibility='visible';
btnRed.style.color='Red';
}else{
canvas.style.visibility='hidden';
btnRed.style.color='Black';
}
}
};


Both the Green and Blue toggle functions are identical except for the button color. My project actually has 7 buttons and canvases. I'm trying to put all these functions into 1, and this is now what i have:

function toggle_visibility(id)
{
var ele = document.getElementById(id);
if (ele.style.visibility == 'hidden')
{
ele.style.visibility = 'visible';
}
else
{
ele.style.visibility = 'hidden';
}
}


I have been unable to work out how to now change the corresponding button color attribute. The idea is that the button will look 'on' when canvas is visible and the color reverts to Black when 'off'.

I also need the answer to be in just javascript please, as this is what i am learning.
I am also hoping to do a similar sort of thing to my drawDots function as they also differ in class, and location. Thank you.

I made a snippet:



var canvas = document.getElementById('redDot');
var ctxR = canvas.getContext('2d');
var canvas1 = document.getElementById('greenDot');
var ctxG = canvas1.getContext('2d');
var canvas2 = document.getElementById('blueDot');
var ctxB = canvas2.getContext('2d');

var cw = canvas.width;
var ch = canvas.height;

drawDots();

function toggle_visibility(id) {
var ele = document.getElementById(id);
if (ele.style.visibility == 'hidden') {
ele.style.visibility = 'visible';
} else {
ele.style.visibility = 'hidden';
}
}

function drawDots() {

// Red Dot
ctxR.clearRect(0, 0, cw, ch);
ctxR.save();
ctxR.translate(cw / 2, ch / 2);
ctxR.beginPath();
ctxR.arc(-50, 0, 10, 0, 2 * Math.PI);
ctxR.closePath();
ctxR.fillStyle = 'Red';
ctxR.fill();
ctxR.restore();

// Green Dot
ctxG.clearRect(0, 0, cw, ch);
ctxG.save();
ctxG.translate(cw / 2, ch / 2);
ctxG.beginPath();
ctxG.arc(0, 0, 10, 0, 2 * Math.PI);
ctxG.closePath();
ctxG.fillStyle = 'Green';
ctxG.fill();
ctxG.restore();

// Blue Dot
ctxB.clearRect(0, 0, cw, ch);
ctxB.save();
ctxB.translate(cw / 2, ch / 2);
ctxB.beginPath();
ctxB.arc(50, 0, 10, 0, 2 * Math.PI);
ctxB.closePath();
ctxB.fillStyle = 'Blue';
ctxB.fill();
ctxB.restore();
};

#wrapper {
position: relative;
}
canvas {
position: absolute;
border: 1px solid red;
}
.red {
color: Red;
}
.green {
color: Green;
}
.blue {
color: Blue;
}

<div id="btnWrapper">
<button id="btnRed" class="red" title="Toggle Red Dot" onclick="toggle_visibility('redDot')">&#9737;</button>
<button id="btnGreen" class="green" title="Toggle Green Dot" onclick="toggle_visibility('greenDot')">&#9737;</button>
<button id="btnBlue" class="blue" title="Toggle Blue Dot" onclick="toggle_visibility('blueDot')">&#9737;</button>
</div>
<div id="wrapper">
<canvas id="redDot" width="200" height="100"></canvas>
<canvas id="greenDot" width="200" height="100"></canvas>
<canvas id="blueDot" width="200" height="100"></canvas>
</div>




Answer

As you say there are more than 3 colours I have written an example that will simplify the creation of multiply buttons.

The buttons and canvases are uniquely identified by their colour so I use the colours to query the DOM for references and use a function closure (forEach callback function) to hold the references for when needed.

I would have actually created the buttons and canvas inside that function as well but you may want it in the html so there will still be so tedious markup to create when adding more buttons.

Rather than manipulate the element styles I have add the DOM classes, .black for the button, and .hide and .show for the canvas. So all that is needed is to set the element's class name rather than their styles. Will make it easier if you have a complicated set of styles to switch between.

"Red,Green,Blue".split(",").forEach((col,i)=>{
    var col_l = col.toLowerCase();
    var ctx = document.getElementById(col_l+ 'Dot').getContext('2d');
    var btn = document.getElementById("btn"+col);
    btn.title ="Toggle "+col +" Dot" ;
    btn.className = col_l ;
    ctx.canvas.className = "show";
    var cw = ctx.canvas.width;
    var ch = ctx.canvas.height;
    ctx.clearRect(0, 0, cw, ch);
    ctx.fillStyle = col;
    ctx.beginPath();
    ctx.arc(cw/2 -50 + i * 50, ch/2, 10, 0, 2 * Math.PI);
    ctx.fill();
    function toggle(){  // this function has closure over col_l ,ctx, and btn
        if (ctx.canvas.className == 'hide') {
           ctx.canvas.className = "show";
           btn.className = col_l ;
        }else{
           ctx.canvas.className = "hide";
           btn.className = "black";
        }
    }        
    btn.addEventListener("click",toggle);
});
#wrapper {
  position: relative;
}
canvas {
  position: absolute;
  border: 1px solid red;
}
 /* for canvas hide and show */
.hide {
    visibility : hidden;
}
.show {
    visibility : visible;
}
.red {
  color: Red;
}
.green {
  color: Green;
}
.blue {
  color: Blue;
}
.black {  /* "black" colour button */
  color: Black;
}
<!-- removed most of the stuff that is better added in code. -->
<div id="btnWrapper">  
  <button id="btnRed">&#9737;</button> 
  <button id="btnGreen">&#9737;</button>
  <button id="btnBlue">&#9737;</button>
</div>
<div id="wrapper">
  <canvas id="redDot" width="200" height="100"></canvas>
  <canvas id="greenDot" width="200" height="100"></canvas>
  <canvas id="blueDot" width="200" height="100"></canvas>
</div>