JavaScript Day 28: Creating a UI Component

You know I like components. I’ve had it in the back of my mind since I started playing with JavaScript to try out making some minimalcomp type components in Canvas. This is a bit of a questionable endeavor. I mean, HTML has a pretty decent set of UI controls, right? But the pull was strong, and I finally gave in and at least made a rough attempt at a button. I think it’s pretty cool. I just threw this together in a couple of hours, so there’s likely a lot more that could be done with it, and possibly even some problems that need to be addressed. Nevertheless, it works pretty well for what it is.

My strategy was to create a constructor function and add functions to its prototype. Then pass in a canvas, x, y, label string, and callback in the constructor, very similar to how the minimalcomps PushButton works.

Well, here’s what I came up with:

[php lang=”JavaScript”]function Button(canvas, x, y, label, onclick) {
this.canvas = canvas;
this.context = this.canvas.getContext(“2d”);
this.x = x;
this.y = y;
this.label = label;
this.onclick = onclick;
this.width = 100;
this.height = 22;
this.state = “up”;
this.borderColor = “#999999”;
this.upColor = “#cccccc”;
this.overColor = “#dddddd”;
this.downColor = “#aaaaaa”;
this.draw();
}

Button.prototype.draw = function() {
// draw border
this.context.fillStyle = this.borderColor;
this.context.fillRect(this.x, this.y, this.width, this.height);

// draw face
if(this.state == “over”) {
this.context.fillStyle = this.overColor;
}
else if(this.state == “down”) {
this.context.fillStyle = this.downColor;
}
else {
this.context.fillStyle = this.upColor;
}
this.context.fillRect(this.x + 1, this.y + 1, this.width – 2, this.height – 2);

// draw label
this.context.font = “12px Arial”;
this.context.fillStyle = “#000000”;
this.context.fillText(this.label, this.x + (this.width – this.context.measureText(this.label).width) / 2, this.y + (this.height + 9) / 2);
};

Button.prototype.checkMouseDown = function(x, y) {
if(x > this.x && x < this.x + this.width && y > this.y && y < this.y + this.height) { this.state = "down"; } else { this.state = "up"; } this.draw(); }; Button.prototype.checkMouseUp = function(x, y) { if(x > this.x && x < this.x + this.width && y > this.y && y < this.y + this.height) { this.state = "over"; if(this.onclick != null) { this.onclick(); } } else { this.state = "up"; } this.draw(); }; Button.prototype.checkMouseMove = function(x, y) { if(x > this.x && x < this.x + this.width && y > this.y && y < this.y + this.height) { this.state = "over"; } else { this.state = "up"; } this.draw(); };[/php] I'll leave it to you to muddle through the code. There's no rocket science in there. If anything's not clear, feel free to ask in the comments. To use this button, you create it using the constructor function. Then you need to call checkMouseUp, checkMouseDown, and checkMouseMove on the button, passing in the mouse's x and y, every time one of those events occurs. It'd look like this: [php lang="JavaScript"]$(function () { var canvas, context, button; canvas = $("#canvas")[0]; context = canvas.getContext("2d"); button = new Button(canvas, 100, 100, "Click Me", function(){ context.beginPath(); context.arc(Math.random() * canvas.width, Math.random() * canvas.height, 5 + Math.random() * 15, 0, Math.PI * 2, false); context.fill(); }); $("#canvas").mousedown(function(event) { button.checkMouseDown(event.pageX - this.offsetLeft, event.pageY - this.offsetTop); }); $("#canvas").mouseup(function(event) { button.checkMouseUp(event.pageX - this.offsetLeft, event.pageY - this.offsetTop); }); $("#canvas").mousemove(function(event) { button.checkMouseMove(event.pageX - this.offsetLeft, event.pageY - this.offsetTop); }); });[/php] The callback function just draws a random circle on the canvas each time the button is pushed. Play around: http://www.bit-101.com/jscanvas/mar28.html

Again, I don’t present this as a fully complete, perfected piece of work, but more of a proof of concept. But I think it’s a concept I may give some more work to. I don’t think I’d go for creating a full set of MinimalCompsJS, but I can see a button, label, slider, radio button and checkbox would be pretty neat to have around. Time shall tell.

This entry was posted in JavaScript. Bookmark the permalink.

4 Responses to JavaScript Day 28: Creating a UI Component

  1. Jorshasaur says:

    This is an interesting experiment and certainly has merit Keith. Who knows, in the future we might find ourselves using a full page width and height canvas, and building ui elements this way might save the headache of cross-browser css3 support (I’m thinking rounded corners and background gradients here). Thanks for sharing.

  2. Vic says:

    I change code as so:

    var but1;
    var canvas=document.getElementById(‘stageCanvas’);

    but1 = new Button(canvas,100,100,”ClickMe”, function() {
    console.log(“Button Clicked”);
    }
    );//but

    /*
    canvas.addEventListener(‘mousedown’,onMouseDown,false);

    function onMouseDown(event) {
    console.log(“onMouseDown?”, event.pageX – this.offsetLeft, event.pageY – this.offsetTop);
    but1.checkMouseUp(event.pageX -this.offsetLeft, event.pageY – this.offsetTop);
    }
    */

    except I moved the commented code to AButton.js.

    (it will be in El.html gamina.org version 0.2.01 via: npm install gamina)

  3. Mike T. says:

    Question: if I’ve defined

    canvas = $(“#canvas”)[0];

    why do I still need to do

    $(“#canvas”).mousedown(function…

    Why can’t I say

    canvas.mousedown(function…

Leave a Reply