You can use flood filling to color clicked areas bounded by your user-defined lines.
Let the user draw their lines on the canvas.
When the user clicks on a region bounded by lines, floodfill that region with a color.
Note: you must draw your gridlines underneath the canvas or else those gridlines will act as boundaries for the floodfill algorithm and you will just fill a grid cell. You can use CSS to layer an image under your canvas or use a separate canvas to draw the gridlines.

Here's starting example code and a Demo: http://jsfiddle.net/m1erickson/aY4Xs/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
// canvas and mousedown related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
// save canvas size to vars b/ they're used often
var canvasWidth=canvas.width;
var canvasHeight=canvas.height;
// define the grid area
// lines can extend beyond grid but
// floodfill wont happen outside beyond the grid
var gridRect={x:50,y:50,width:200,height:200}
drawGridAndLines();
// draw some test gridlines
function drawGridAndLines(){
ctx.clearRect(0,0,canvas.width,canvas.height)
// Important: the lineWidth must be at least 5
// or the floodfill algorithm will "jump" over lines
ctx.lineWidth=5;
ctx.strokeRect(gridRect.x,gridRect.y,gridRect.width,gridRect.height);
ctx.beginPath();
ctx.moveTo(75,25);
ctx.lineTo(175,275);
ctx.moveTo(25,100);
ctx.lineTo(275,175);
ctx.stroke();
}
// save the original (unfilled) canvas
// so we can reference where the black bounding lines are
var strokeData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
// fillData contains the floodfilled canvas data
var fillData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
// Thank you William Malone for this great floodFill algorithm!
// http://www.williammalone.com/articles/html5-canvas-javascript-paint-bucket-tool/
//////////////////////////////////////////////
function floodFill(startX, startY, startR, startG, startB) {
var newPos;
var x;
var y;
var pixelPos;
var neighborLeft;
var neighborRight;
var pixelStack = [[startX, startY]];
while (pixelStack.length) {
newPos = pixelStack.pop();
x = newPos[0];
y = newPos[1];
// Get current pixel position
pixelPos = (y * canvasWidth + x) * 4;
// Go up as long as the color matches and are inside the canvas
while (y >= 0 && matchStartColor(pixelPos, startR, startG, startB)) {
y -= 1;
pixelPos -= canvasWidth * 4;
}
pixelPos += canvasWidth * 4;
y += 1;
neighborLeft = false;
neighborRight = false;
// Go down as long as the color matches and in inside the canvas
while (y <= (canvasHeight-1) && matchStartColor(pixelPos, startR, startG, startB)) {
y += 1;
fillData.data[pixelPos] = fillColor.r;
fillData.data[pixelPos + 1] = fillColor.g;
fillData.data[pixelPos + 2] = fillColor.b;
fillData.data[pixelPos + 3] = 255;
if (x > 0) {
if (matchStartColor(pixelPos - 4, startR, startG, startB)) {
if (!neighborLeft) {
// Add pixel to stack
pixelStack.push([x - 1, y]);
neighborLeft = true;
}
} else if (neighborLeft) {
neighborLeft = false;
}
}
if (x < (canvasWidth-1)) {
if (matchStartColor(pixelPos + 4, startR, startG, startB)) {
if (!neighborRight) {
// Add pixel to stack
pixelStack.push([x + 1, y]);
neighborRight = true;
}
} else if (neighborRight) {
neighborRight = false;
}
}
pixelPos += canvasWidth * 4;
}
}
}
function matchStartColor(pixelPos, startR, startG, startB) {
// get the color to be matched
var r = strokeData.data[pixelPos],
g = strokeData.data[pixelPos + 1],
b = strokeData.data[pixelPos + 2],
a = strokeData.data[pixelPos + 3];
// If current pixel of the outline image is black-ish
if (matchstrokeColor(r, g, b, a)) {
return false;
}
// get the potential replacement color
r = fillData.data[pixelPos];
g = fillData.data[pixelPos + 1];
b = fillData.data[pixelPos + 2];
// If the current pixel matches the clicked color
if (r === startR && g === startG && b === startB) {
return true;
}
// If current pixel matches the new color
if (r === fillColor.r && g === fillColor.g && b === fillColor.b) {
return false;
}
return true;
}
function matchstrokeColor(r, g, b, a) {
// never recolor the initial black divider strokes
// must check for near black because of anti-aliasing
return (r + g + b < 100 && a === 255);
}
// Start a floodfill
// 1. Get the color under the mouseclick
// 2. Replace all of that color with the new color
// 3. But respect bounding areas! Replace only contiguous color.
function paintAt(startX, startY) {
// get the clicked pixel's [r,g,b,a] color data
var pixelPos = (startY * canvasWidth + startX) * 4,
r = fillData.data[pixelPos],
g = fillData.data[pixelPos + 1],
b = fillData.data[pixelPos + 2],
a = fillData.data[pixelPos + 3];
// this pixel's already filled
if (r === fillColor.r && g === fillColor.g && b === fillColor.b) {
return;
}
// this pixel is part of the original black image--don't fill
if (matchstrokeColor(r, g, b, a)) {
return;
}
// execute the floodfill
floodFill(startX, startY, r, g, b);
// put the colorized data back on the canvas
ctx.putImageData(fillData, 0, 0);
}
// end floodFill algorithm
//////////////////////////////////////////////
// get the pixel colors under x,y
function getColors(x,y){
var data=ctx.getImageData(x,y,1,1).data;
return({r:data[0], g:data[1], b:data[2], a:data[3] });
}
// create a random color object {red,green,blue}
function randomColorRGB(){
var hex=Math.floor(Math.random()*16777215).toString(16);
var r=parseInt(hex.substring(0,2),16);
var g=parseInt(hex.substring(2,4),16);
var b=parseInt(hex.substring(4,6),16);
return({r:r,g:g,b:b});
}
function handleMouseDown(e){
e.preventDefault();
// get the mouse position
x=parseInt(e.clientX-offsetX);
y=parseInt(e.clientY-offsetY);
// don't floodfill outside the gridRect
if(
x<gridRect.x+5 ||
x>gridRect.x+gridRect.width ||
y<gridRect.y+5 ||
y>gridRect.y+gridRect.height
){return;}
// get the pixel color under the mouse
var px=getColors(x,y);
// get a random color to fill the region with
fillColor=randomColorRGB();
// floodfill the region bounded by black lines
paintAt(x,y,px.r,px.g,px.b);
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
}); // end $(function(){});
</script>
</head>
<body>
<h4>Click in a region within the grid square.</h4>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
[ Info about getImageData and the pixel array ]
context.getImageData().data
gets an array representing r,g,b & a values of the specified area of the canvas (in our case we selected the whole canvas). The top-left pixel (0,0) is the first element(s) in the array.
Each pixel is represented by 4 sequential elements in the array.
The first array element holds the red component (0-255), the next element holds blue, the next holds green and the next holds the alpha (opacity).
// pixel 0,0
red00=data[0];
green00=data[1];
blue00=data[2];
alpha00=data[3];
// pixel 1,0
red10=data[4];
green10=data[5];
blue10=data[6];
alpha10=data[7];
Therefore, you jump to the red element of any pixel under the mouse like this:
// pixelPos is the position in the array of the first of 4 elements for pixel (mouseX,mouseY)
var pixelPos = (mouseY * canvasWidth + mouseX) * 4
And you can get all 4 r,g,b,a values by getting the next 4 pixel array elements
var r = fillData.data[pixelPos];
var g = fillData.data[pixelPos + 1];
var b = fillData.data[pixelPos + 2];
var a = fillData.data[pixelPos + 3];