1
\$\begingroup\$

Ultimately I want to be able to draw a checkerboard (wall) of user-defined size. This wall is made up of tiles of a user-defined size. This main wall can then be split up into multiple sections (outputs) dependent on user defined limits. The data-flow is then drawn in each individual output(see Example 2), not just for the entire wall(Example 1).

I was provided an elegant solution by user @Blindman67 that iterates through each tile in the map and sets it's flow in the order of the flow. This works wonderfully until I change it to set a tile to be the end of the flow once it reaches the limit of a single output.

If you check out example 3 I start to add in some extremely crude if/else if statements to check for every possibility in the 8 different flows, setting the ends and beginnings of flows as well as arrow directions manually. This is extremely sloppy and I'd much prefer something more akin to what's going on in example 1, but with a working data flow drawn for each individual output.

Here are two pictures of what I can do thus far. Looking at the 2nd picture, you'll see I want to be able to fill in the remaining 3 empty outputs with their respective data flows.

Example 1 - no output limits

Example 2 - missing data flows

I don't know if I should change the 'Infinity' limit to be the limits of the outputs here:

const flows = {
        none : -1,
        right : 0,
        down : 1,
        left : 2,
        up : 3,
        end : 4,  // for end of flow
        start : 5,  // for start
        dirs : [[1,0],[0,1],[-1,0],[0,-1]], // x,y step for each direction
        // Maps are used to workout the flow layout
        // x,y is the starting position with 0 as top or left and 1 as bottom or right
        // directions has an array for each direction. the first item is the travel
        // direction and the second item is the max number of steps befor turning
        map1 : { // top left start rigth, down, left, down 
            x : 0, y : 0,
            directions : [[0,Infinity],[1,1],[2,Infinity],[1,1]],
        },
        map2 : {  // top right start, left, down, right, down 
            x : 1, y : 0,
            directions : [[2,Infinity],[1,1],[0,Infinity],[1,1]],
        },
        map3 : {
            x : 0, y : 1, // bottom left start, up, right, down, right
            directions : [[3,Infinity],[0,1],[1,Infinity],[0,1]],
        },
        map4 : {
            x : 1, y : 1, // bottom right start, up, left, down, left
            directions : [[3,Infinity],[2,1],[1,Infinity],[2,1]],
        },
    }

Or if I need to edit the createFlow(); function to add a check for each individual output:

// Creates flow map for tiles. flow maps are in flows as flow.map1, map2... etc
function createFlow(tiles,flowMap){
    var i = 0;
    var prevtile, tile;
    var count = 0;
    var x = flowMap.x * (cols-1);
    var y = flowMap.y * (rows-1);
    var moving = true;
    while(moving){
        var ind = x + y * cols;
        prevtile = tile;
        var tile = tiles[ind];
        var dir = flowMap.directions[i % flowMap.directions.length];
        var nx = x + flows.dirs[dir[0]][0];
        var ny = y + flows.dirs[dir[0]][1];
        if(nx >= cols || nx >= outCols || nx < 0 || ny >= rows || ny >= outRows || ny < 0 || count >= dir[1]){//determine what tiles stop changing nx/ny/dir
            i += 1;
            dir = flowMap.directions[i % flowMap.directions.length];
            nx = x + flows.dirs[dir[0]][0];
            ny = y + flows.dirs[dir[0]][1];
            if(nx >= cols || nx >= outCols || nx < 0 || ny >= rows || ny >= outRows || ny < 0){//determine where flow stops
                tile.flow = flows.end;
                break;
            }
            count = 0;
        }
        if(tile === undefined){
            prevtile.flow = flows.end;
            break;
        }
        if(prevtile === undefined){
            tile.flow = flows.start;   
        }else{
            tile.flow = dir[0];
        }
        count += 1;
        x = nx;
        y = ny;
    }
}

Example 1 - Flow functions correctly, but no output limits:

/** CreateImage.js begin **/
    // creates a blank image with 2d context
    var createImage=function(w,h){var i=document.createElement("canvas");i.width=w;i.height=h;i.ctx=i.getContext("2d");return i;}
    
    /** CreateImage.js end **/
    var canvas = createImage(512,512);
    var ctx = canvas.ctx;
    document.body.appendChild(canvas);
    
    // cell size
    var size = 40;
    
    // constants for directions
    const flows = {
        none : -1,
        right : 0,
        down : 1,
        left : 2,
        up : 3,
        end : 4,  // for end of flow
        start : 5,  // for start
        dirs : [[1,0],[0,1],[-1,0],[0,-1]], // x,y step for each direction
        // Maps are used to workout the flow layout
        // x,y is the starting position with 0 as top or left and 1 as bottom or right
        // directions has an array for each direction. the first item is the travel
        // direction and the second item is the max number of steps befor turning
        map1 : { // top left start rigth, down, left, down 
            x : 0, y : 0,
            directions : [[0,Infinity],[1,1],[2,Infinity],[1,1]],
        },
        map2 : {  // top right start, left, down, right, down 
            x : 1, y : 0,
            directions : [[2,Infinity],[1,1],[0,Infinity],[1,1]],
        },
        map3 : {
            x : 0, y : 1, // bottom left start, up, right, down, right
            directions : [[3,Infinity],[0,1],[1,Infinity],[0,1]],
        },
        map4 : {
            x : 1, y : 1, // bottom right start, up, left, down, left
            directions : [[3,Infinity],[2,1],[1,Infinity],[2,1]],
        },
    }
    // colours
    const col1 = "#FA6"
    const col2 = "#6AF"
    // array of leds
    var leds = [];
    // number columns and rows
    var rows;
    var cols;
    // reset or setup leds
    function reset(leds){
        leds.length = 0;
        cols = Math.floor(canvas.height / size);
        rows = Math.floor(canvas.width / size);
        for(var y = 0; y < canvas.height-size; y+= size){
            for(var x = 0; x < canvas.width-size; x += size){
                var c = (Math.floor(y / size) % 2 + Math.floor(x / size) % 2) % 2;
                leds.push({
                    x,y,size,
                    flow : flows.none,
                    col : c ? col1 : col2,
                })
    
            }    
        }
    }
    // Creates flow map for leds. flow maps are in flows as flow.map1, map2... etc
    function createFlow(leds,flowMap){
        var i = 0;
        var prevLed, led;
        var count = 0;
        var x = flowMap.x * (cols-1);
        var y = flowMap.y * (rows-1);
        var moving = true;
        while(moving){
            var ind = x + y * cols;
            prevLed = led;
            var led = leds[ind];
            var dir = flowMap.directions[i % flowMap.directions.length];
            var nx = x + flows.dirs[dir[0]][0];
            var ny = y + flows.dirs[dir[0]][1];
            if(nx >= cols || nx < 0 || ny >= rows || ny < 0 || count >= dir[1]){
                i += 1;
                dir = flowMap.directions[i % flowMap.directions.length];
                nx = x + flows.dirs[dir[0]][0];
                ny = y + flows.dirs[dir[0]][1];
                if(nx >= cols || nx < 0 || ny >= rows || ny < 0){
                    led.flow = flows.end;
                    break;
                }
                count = 0;
            }
            if(led === undefined){
                prevLed.flow = flows.end;
                break;
            }
            if(prevLed === undefined){
                led.flow = flows.start;   
            }else{
                led.flow = dir[0];
            }
            count += 1;
            x = nx;
            y = ny;
        }
    }
    
    // draws the leds
    function draw(leds){
        function arrow(led){
            if(led.flow === flows.none){
                return;
            }
            var step = led.size * (1/4);
            var x = led.x + led.size -step;
            var y = led.y + step
            ctx.strokeStyle = "white";
            ctx.lineWidth = 2;
            ctx.beginPath();
            if(led.flow === flows.end){
                ctx.setTransform(1,0,0,1,x,y);
                ctx.moveTo(-step / 2, -step / 2);
                ctx.lineTo(step / 2, step / 2);
                ctx.moveTo(step / 2, -step / 2);
                ctx.lineTo(-step / 2, step / 2);
                
                ctx.stroke();
                ctx.setTransform(1,0,0,1,0,0);
                return;
            }else if(led.flow === flows.start){
                ctx.setTransform(1,0,0,1,x,y);
                ctx.moveTo(step / 2, 0);
                ctx.arc(0,0, step / 2,0,Math.PI * 2);
                ctx.stroke();
                ctx.setTransform(1,0,0,1,0,0);
                return;
            }else if(led.flow === flows.right){
                ctx.setTransform(1,0,0,1,x,y);
            } else if(led.flow === flows.left){
                ctx.setTransform(-1,0,0,1,x,y);
            } else if(led.flow === flows.down){
                ctx.setTransform(0,1,1,0,x,y);
            } else if(led.flow === flows.up){
                ctx.setTransform(0,-1,1,0,x,y);
                //ctx.setTransform(0,1,-1,0,0,0);
            }
            ctx.moveTo(-step / 2, 0);
            ctx.lineTo(step / 2, 0);
            ctx.moveTo(step / 4, -step / 4);
            ctx.lineTo(step / 2, 0);
            ctx.lineTo(step / 4, step / 4);
            ctx.stroke();
            ctx.setTransform(1,0,0,1,0,0);
        }
        ctx.clearRect(0,0,canvas.width,canvas.height)
        var i = 0;
        while(i < leds.length){
            var l = leds[i++];
            ctx.fillStyle = l.col
            ctx.fillRect(l.x,l.y,l.size,l.size);
            arrow(l);
        }
    }
    
    var flowMaps = [flows.map1,flows.map2,flows.map3,flows.map4];
    var currentFlow = 3;
    function drawAll(){
        reset(leds);
        draw(leds);
        setTimeout(setFlow,1000);
    }
    function setFlow(){
        createFlow(leds,flowMaps[(currentFlow++) % flowMaps.length]);
        draw(leds);
        setTimeout(drawAll,4000);
    }
    drawAll();

Example 2 - Flow functions correctly within the limits of one single output.

/** CreateImage.js begin **/
	//wall size
    var wallx = 500;
    var wally = 500;
    
    //output size
    var outputx = 250;
    var outputy = 250;
    
    // tile size
    var tilex = 25;
    var tiley = 25;
    
    // vars for output limits evenly divisible by tile size    
    var LCDoutputx = outputx;
    var LCDoutputy = outputy;
    
    //round down LCDoutputy to the next coordinate evenly divisible by a tile's y value.
    if ((outputy % tiley) != 0){
	    LCDoutputy = (Math.floor(outputy/tiley))*tiley;   
    }
    //round down LCDoutputx to the next coordinate evenly divisible by a tile's x value.
    if ((outputx % tilex) != 0){
	    LCDoutputx = (Math.floor(outputx/tilex))*tilex;   
    }
    
    // creates a blank image with 2d context
    var createImage=function(w,h){var i=document.createElement("canvas");i.width=w;i.height=h;i.ctx=i.getContext("2d");return i;}
    
    /** CreateImage.js end **/
    var canvas = createImage(wallx, wally);
    var ctx = canvas.ctx;
    document.body.appendChild(canvas);
    
    // constants for directions
    const flows = {
        none : -1,
        right : 0,
        down : 1,
        left : 2,
        up : 3,
        end : 4,  // for end of flow
        start : 5,  // for start
        dirs : [[1,0],[0,1],[-1,0],[0,-1]], // x,y step for each direction
        // Maps are used to workout the flow laoutputy
        // x,y is the starting position with 0 as top or left and 1 as bottom or right
        // directions has an array for each direction. the first item is the travel
        // direction and the second item is the max number of steps befor turning
        map1 : { // top left start rigth, down, left, down 
            x : 0, y : 0,
            directions : [[0,Infinity],[1,1],[2,Infinity],[1,1]],
        },
        map2 : {  // top right start, left, down, right, down 
            x : 1, y : 0,
            directions : [[2,Infinity],[1,1],[0,Infinity],[1,1]],
        },
        map3 : {
            x : 0, y : 1, // bottom left start, up, right, down, right
            directions : [[3,Infinity],[0,1],[1,Infinity],[0,1]],
        },
        map4 : {
            x : 1, y : 1, // bottom right start, up, left, down, left
            directions : [[3,Infinity],[2,1],[1,Infinity],[2,1]],
        },
    }
    // colours
    const col1 = "#FA6" //orng
    const col2 = "#6AF" //l. blue
    const col3 = "#03CEA4" //green
    const col4 = "#FB4D3D" //red
    const col5 = "#345995" //d.blue
    var colA;
    var colB;
    // array of tiles
    var tiles = [];
    // number columns and rows
    var rows;
    var cols;
    // number of outputs
    var outputsW = Math.ceil(wallx/outputx);
    var outputsH = Math.ceil(wally/outputy);
    // number of cols/rows in each output
    var outCols = Math.floor(outputx/tilex);
    var outRows = Math.floor(outputy/tiley);
    // reset or setup tiles
    function reset(tiles){
        tiles.length = 0;
        rows = Math.floor(canvas.height / tiley);
        cols = Math.floor(canvas.width / tilex);
        for(var y = 0; y <= canvas.height-tiley; y+= tiley){ //changed < to <= 
            for(var x = 0; x <= canvas.width-tilex; x += tilex){ //changed < to <=
         		var d = (Math.floor(y / LCDoutputy) % 2 + Math.floor(x / LCDoutputx) % 2) % 2; //added LCDoutputt for output background color to work. Was outputy. The entire map's output background colors were off by one row, showing an extra row beyond what the limits should be.
		 		//console.log("Y : "+y+" divided by Out Y Limit : "+outputy);
         		//console.log("Y result : "+Math.floor(y/outputy) % 2);
         		//console.log("X : "+x+" divided by Out X Limit : "+outputx);
         		//console.log("X result : "+Math.floor(x/outputx) % 2);
         		//console.log(d);
                var c = (Math.floor(y / tiley) % 2 + Math.floor(x / tilex) % 2) % 2;
                tiles.push({
                    x,y,tilex,tiley,
                    flow : flows.none,
                    output : d ? (colA = col3, colB = col4) : (colA = col1, colB = col2),
                    col : c ? colA : colB,
                    
                })
            }    
        }
    }
    // Creates flow map for tiles. flow maps are in flows as flow.map1, map2... etc
    function createFlow(tiles,flowMap){
        var i = 0;
        var prevtile, tile;
        var count = 0;
        var x = flowMap.x * (cols-1);
        var y = flowMap.y * (rows-1);
        var moving = true;
        while(moving){
            var ind = x + y * cols;
            prevtile = tile;
            var tile = tiles[ind];
            var dir = flowMap.directions[i % flowMap.directions.length];
            var nx = x + flows.dirs[dir[0]][0];
            var ny = y + flows.dirs[dir[0]][1];
            //console.log(count);
            //console.log("I : "+i+" X , Y : "+x+" , "+y);
            //console.log("IND : "+ind+" NX , NY : "+nx+" , "+ny);
            //console.log("DIR : "+dir);
            //console.log("Columns : "+cols+" Out Columns : "+outCols);
            //console.log("Rows : "+rows+" Out Rows : "+outRows);
            if(nx >= cols || nx >= outCols || nx < 0 || ny >= rows || ny >= outRows || ny < 0 || count >= dir[1]){//determine what tiles stop changing nx/ny/dir
                i += 1;
                dir = flowMap.directions[i % flowMap.directions.length];
                nx = x + flows.dirs[dir[0]][0];
                ny = y + flows.dirs[dir[0]][1];
                if(nx >= cols || nx >= outCols || nx < 0 || ny >= rows || ny >= outRows || ny < 0){//determine where flow stops
                    tile.flow = flows.end;
                    break;
                }
                count = 0;
            }
            if(tile === undefined){
                prevtile.flow = flows.end;
                break;
            }
            if(prevtile === undefined){
                tile.flow = flows.start;   
            }else{
                tile.flow = dir[0];
            }
            count += 1;
            x = nx;
            y = ny;
        }
    }
    
    // draws the tiles
    function draw(tiles){
        function arrow(tile){
            if(tile.flow === flows.none){
                return;
            }
            if (tilex<tiley) {
	            var step = tile.tilex * (1/4);
            } else {
	        	var step = tile.tiley * (1/4);   
            }
            //var step = tile.tilex * (1/4);
            var x = tile.x + tile.tilex -step;
            var y = tile.y + step
            ctx.strokeStyle = "white";
            ctx.lineWidth = 2;
            ctx.beginPath();
            if(tile.flow === flows.end){
                ctx.setTransform(1,0,0,1,x,y);
                ctx.moveTo(-step / 2, -step / 2);
                ctx.lineTo(step / 2, step / 2);
                ctx.moveTo(step / 2, -step / 2);
                ctx.lineTo(-step / 2, step / 2);
                
                ctx.stroke();
                ctx.setTransform(1,0,0,1,0,0);
                return;
            }else if(tile.flow === flows.start){
                ctx.setTransform(1,0,0,1,x,y);
                ctx.moveTo(step / 2, 0);
                ctx.arc(0,0, step / 2,0,Math.PI * 2);
                ctx.stroke();
                ctx.setTransform(1,0,0,1,0,0);
                return;
            }else if(tile.flow === flows.right){
                ctx.setTransform(1,0,0,1,x,y);
            } else if(tile.flow === flows.left){
                ctx.setTransform(-1,0,0,1,x,y);
            } else if(tile.flow === flows.down){
                ctx.setTransform(0,1,1,0,x,y);
            } else if(tile.flow === flows.up){
                ctx.setTransform(0,-1,1,0,x,y);
                //ctx.setTransform(0,1,-1,0,0,0);
            }
            ctx.moveTo(-step / 2, 0);
            ctx.lineTo(step / 2, 0);
            ctx.moveTo(step / 4, -step / 4);
            ctx.lineTo(step / 2, 0);
            ctx.lineTo(step / 4, step / 4);
            ctx.stroke();
            ctx.setTransform(1,0,0,1,0,0);
        }
        ctx.clearRect(0,0,canvas.width,canvas.height)
        var i = 0;
        while(i < tiles.length){
            var l = tiles[i++];
            ctx.fillStyle = l.col
            ctx.fillRect(l.x,l.y,l.tilex,l.tiley);
            arrow(l);
        }
        
    }
    
    var flowMaps = [flows.map1,flows.map2,flows.map3,flows.map4];
    var currentFlow = 4;
    function drawAll(){
        reset(tiles);
        draw(tiles);
        //setTimeout(setFlow,1000);
        setFlow();
    }
    function setFlow(){
        createFlow(tiles,flowMaps[(currentFlow++) % flowMaps.length]);
        draw(tiles);
        //setTimeout(drawAll,4000); //comment out this line to stop map change cycle
    }
    drawAll();

Example 3 - Flow function totally botched but gives an idea of the flexibility I want with user defined fields

/** CreateImage.js begin **/
	//output size
    var outputx = 256;
    var outputy = 256;
    
    // tile size
    var tilex = 64;
    var tiley = 64;
    
    // rows & columns
    var rows = 8;
    var cols = 8;
    
    // wall/map size dictated by rows/cols
    wallx = tilex*cols;
	wally = tiley*rows;
    
        
    // creates a blank image with 2d context
    var createImage=function(w,h){var i=document.createElement("canvas");i.width=w;i.height=h;i.ctx=i.getContext("2d");return i;}
    
    /** CreateImage.js end **/
    var canvas = createImage(wallx, wally);
    var ctx = canvas.ctx;
    document.body.appendChild(canvas);
    
    // constants for directions
    const flows = {
        none : -1,
        right : 0,
        down : 1,
        left : 2,
        up : 3,
        end : 4,  // for end of flow
        start : 5,  // for start
        dirs : [[1,0],[0,1],[-1,0],[0,-1]], // x,y step for each direction
        // Maps are used to workout the flow laoutputy
        // x,y is the starting position with 0 as top or left and 1 as bottom or right
        // directions has an array for each direction. the first item is the travel
        // direction and the second item is the max number of steps befor turning
        map1 : { // top left start rigth, down, left, down 
            x : 0, y : 0,
            directions : [[0,Infinity],[1,1],[2,Infinity],[1,1]],
        },
        map2 : {  // top right start, left, down, right, down 
            x : 1, y : 0,
            directions : [[2,Infinity],[1,1],[0,Infinity],[1,1]],
        },
        map3 : {
            x : 0, y : 1, // bottom left start, right, up, left, up
            directions : [[0,Infinity],[3,1],[2,Infinity],[3,1]],
        },
        map4 : {
            x : 1, y : 1, // bottom right start, left, up, right, up
            directions : [[2,Infinity],[3,1],[0,Infinity],[3,1]],
        },
        map5 : {
            x : 0, y : 0, // top left start, down, right, up, right
            directions : [[1,Infinity],[0,1],[3,Infinity],[0,1]],
        },
        map5 : {
            x : 1, y : 0, // top right start, down, left, down, left
            directions : [[1,Infinity],[2,1],[1,Infinity],[2,1]],
        },
        map7 : {
            x : 0, y : 1, // bottom left start, up, right, down, right
            directions : [[3,Infinity],[0,1],[1,Infinity],[0,1]],
        },
        map8 : {
            x : 1, y : 1, // bottom right start, up, left, down, left
            directions : [[3,Infinity],[2,1],[1,Infinity],[2,1]],
        },
        
    }
    // colours
    const col1 = "#FA6" //orng
    const col2 = "#6AF" //l. blue
    const col3 = "#03CEA4" //green
    const col4 = "#FB4D3D" //red
    const col5 = "#345995" //d.blue
    var colA;
    var colB;
    // array of tiles
    var tiles = [];
    // number of outputs
    var outputsW = Math.ceil(wallx/outputx);
    var outputsH = Math.ceil(wally/outputy);
    // number of cols/rows in each output
    var outCols = Math.floor(outputx/tilex);
    var outRows = Math.floor(outputy/tiley);
    // reset or setup tiles
    function reset(tiles){
	    
	    console.log("**Begin Reset***");
	    report();
	    wallx = tilex*cols;
		wally = tiley*rows;
		ctx.canvas.width = wallx;
		ctx.canvas.height = wally;
		ctx.clearRect(0,0,canvas.width,canvas.height);
	    canvas = createImage(wallx, wally);
	    //document.body.appendChild(canvas);
	    
	    // vars for output limits evenly divisible by tile size    
	    var LCDoutputx = outputx;
	    var LCDoutputy = outputy;
	    
	    //round down LCDoutputy to the next coordinate evenly divisible by a tile's y value.
	    if ((outputy % tiley) != 0){
		    LCDoutputy = (Math.floor(outputy/tiley))*tiley;   
	    }
	    //round down LCDoutputx to the next coordinate evenly divisible by a tile's x value.
	    if ((outputx % tilex) != 0){
		    LCDoutputx = (Math.floor(outputx/tilex))*tilex;   
	    }
	    
	    outCols = Math.floor(outputx/tilex);
		outRows = Math.floor(outputy/tiley);

	    
		//ctx = canvas.ctx;
		//document.body.appendChild(canvas);
        tiles.length = 0;
        //rows = Math.floor(wally / tiley);
        //cols = Math.floor(wallx / tilex);
        
        for(var y = 0; y <= wally-tiley; y+= tiley){ //changed < to <=
            for(var x = 0; x <= wallx-tilex; x+= tilex){ //changed < to <=
	            console.log("x,y = "+x+", "+y); 
	            console.log("wallx = "+wallx);
	            console.log("tilex = "+tilex);
         		var d = (Math.floor(y / LCDoutputy) % 2 + Math.floor(x / LCDoutputx) % 2) % 2; //added LCDoutputt for output background color to work. Was outputy. The entire map's output background colors were off by one row, showing an extra row beyond what the limits should be.
		 		//console.log("Y : "+y+" divided by Out Y Limit : "+outputy);
         		//console.log("Y result : "+Math.floor(y/outputy) % 2);
         		//console.log("X : "+x+" divided by Out X Limit : "+outputx);
         		//console.log("X result : "+Math.floor(x/outputx) % 2);
         		//console.log(d);
                var c = (Math.floor(y / tiley) % 2 + Math.floor(x / tilex) % 2) % 2;
                tiles.push({
                    x,y,tilex,tiley,
                    flow : flows.none,
                    output : d ? (colA = col3, colB = col4) : (colA = col1, colB = col2),
                    col : c ? colA : colB,
                })
            }    
        }
        console.log("___End Reset;");
        report();
    }
    // Creates flow map for tiles. flow maps are in flows as flow.map1, map2... etc
    function createFlow(tiles,flowMap){
        var i = 0;
        var prevtile, tile;
        var count = 0;
        var x = flowMap.x * (cols-1);
        //console.log(x);
        var y = flowMap.y * (rows-1);
        //console.log(y);
        var moving = true;
        while(moving){
	        //console.log("***   Moving   ***");
	        //console.log("x = "+x+" y = "+y);
	        //console.log("nx = "+nx+" ny = "+ny);
            var ind = x + y * cols;
            //console.log(tiles[ind]);
            /*console.log("ind = x + y * cols");
            console.log("ind = "+x+" + "+y+" * "+cols);
            console.log(ind);*/
            prevtile = tile;
            var tile = tiles[ind];
            var dir = flowMap.directions[i % flowMap.directions.length];
            //console.log(dir);
            var nx = x + flows.dirs[dir[0]][0];
            var ny = y + flows.dirs[dir[0]][1];
            //console.log("nx/ny change");
            //console.log("x ("+x+") + flows.dirs[dir[0]][0]("+flows.dirs[dir[0]][0]+") = nx = "+nx);
            //console.log("y ("+y+") + flows.dirs[dir[0]][1]("+flows.dirs[dir[0]][1]+") = ny = "+ny);
            //console.log("Count = "+count);
            
            //console.log("I : "+i+" X , Y : "+x+" , "+y);
            //console.log("IND : "+ind+" NX , NY : "+nx+" , "+ny);
            //console.log("DIR : "+dir);
            //console.log("Columns : "+cols+" Out Columns : "+outCols);
            //console.log("Rows : "+rows+" Out Rows : "+outRows);
            
            if(nx >= cols ||  nx < 0 || ny >= rows || ny < 0 || count >= dir[1]){//if next x or y is less than 0 or out of map bounds
                i += 1; //increase i by 1
                dir = flowMap.directions[i % flowMap.directions.length]; //update dir to match i
                nx = x + flows.dirs[dir[0]][0]; //update nx
                //console.log("nx add : "+flows.dirs[dir[0]][0]);
                ny = y + flows.dirs[dir[0]][1]; //update ny
                //console.log("ny add : "+flows.dirs[dir[0]][1]);
               
                if(nx >= outCols || ny >= outRows){
	                //console.log("nx = "+nx+" > outCols = "+outCols);
	                //console.log("ny = "+ny+" > outRows = "+outRows);	
                	/*if(nx === outCols){
	                	prevtile.flow = flows.end;
                	} */
                }
               
                if(nx >= cols || nx < 0 || ny >= rows || ny < 0){//determine where flow stops
                    tile.flow = flows.end;
                    break;
                }
                count = 0;
            }
            
            if(tile === undefined){
                prevtile.flow = flows.end;
                break;
            }
            if(prevtile === undefined){
                tile.flow = flows.start;   
            }else{
                tile.flow = dir[0];
            }
            //data case checks for additional flows.starts/ends
            //flow 1
            if(currentFlow === 0){ 
	            //arrows
	            if(!((tile.y/tile.tiley) % 2) && (tile.x/tile.tilex+1) % outCols === 0){
		            tile.flow = flows.down;
		        } else if(((tile.y/tile.tiley) % 2) && (tile.x/tile.tilex) % outCols === 0){
		            tile.flow = flows.down;
		        }
	            //end 
	        	if((tile.x/tile.tilex) % outCols === 0 && (tile.y/tile.tiley+1) % outRows == 0){
	            	tile.flow =  flows.end;
	            //start
	            } else if ((tile.x/tile.tilex) % outCols === 0 && (tile.y/tile.tiley) % outRows == 0){
	            	tile.flow =  flows.start;
	            }
	        //flow 2
            } else if (currentFlow === 1){
	            //arrows
	            if(!((tile.y/tile.tiley) % 2) && (tile.x/tile.tilex) % outCols === 0){
		            tile.flow = flows.down;
		        } else if(((tile.y/tile.tiley) % 2) && (tile.x/tile.tilex+1) % outCols === 0){
		            tile.flow = flows.down;
		        }
		        //end
	            if((((tile.x/tile.tilex+1) % outCols === 0) || ((tile.x/tile.tilex+1) % cols === 0)) && (tile.y/tile.tiley+1) % outRows == 0){
	            	tile.flow =  flows.end;
	            //start
	            } else if ((((tile.x/tile.tilex+1) % outCols === 0) || ((tile.x/tile.tilex+1) % cols === 0)) && (tile.y/tile.tiley) % outRows == 0){
	            	tile.flow =  flows.start;
	            }
	        //flow 3
            } else if (currentFlow === 2){
	            //arrows
	            if(!((tile.x/tile.tilex) % 2) && (tile.y/tile.tiley) % outCols === 0){
		            tile.flow = flows.right;
		        } else if(((tile.x/tile.tilex) % 2) && (tile.y/tile.tiley+1) % outCols === 0){
		            tile.flow = flows.right;
		        }
		        //end
	            if((tile.x/tile.tilex+1) % outCols === 0 && (tile.y/tile.tiley+1) % outRows == 0){
	            	tile.flow =  flows.end;
	            //start
	            } else if ((tile.x/tile.tilex) % outCols === 0 && (tile.y/tile.tiley+1) % outRows == 0){
	            	tile.flow =  flows.start;
	            }
	            //if odd # of columns
	            if(!(cols % 2 === 0)){
		        	//end
		            if((tile.x/tile.tilex+1) % cols === 0 && (tile.y/tile.tiley) % outRows == 0){
		            	tile.flow =  flows.end;
		            }    
	            }
	            //if odd # of output columns
	            if(!(outCols % 2 === 0)){
		        	//end
		            if((tile.x/tile.tilex+1) % outCols === 0 && (tile.y/tile.tiley) % outRows == 0){
		            	tile.flow =  flows.end;
		            } 
	            }
	        //flow 4
            } else if(currentFlow === 3){
	            //arrows
	            if(((tile.x/tile.tilex) % 2) && (tile.y/tile.tiley) % outCols === 0){
		            tile.flow = flows.left;
		        } else if(!((tile.x/tile.tilex) % 2) && (tile.y/tile.tiley+1) % outCols === 0){
		            tile.flow = flows.left;
		        }
		        //end 
	        	if((tile.x/tile.tilex) % outCols === 0 && (tile.y/tile.tiley+1) % outRows == 0){
	            	tile.flow =  flows.end;
	            //start
	            } else if ((tile.x/tile.tilex+1) % outCols === 0 && (tile.y/tile.tiley+1) % outRows == 0){
	            	tile.flow =  flows.start;
	            }
	            
            }

            count += 1;
            x = nx;
            y = ny;
        }
    }
    
    // draws the tiles
    function draw(tiles){
        function arrow(tile){
            if(tile.flow === flows.none){
	            console.log("no flow");
                return;
            }
            if (tilex<tiley) {
	            var step = tile.tilex * (1/4);
            } else {
	        	var step = tile.tiley * (1/4);   
            }
            //var step = tile.tilex * (1/4);
            var x = tile.x + tile.tilex -step;
            var y = tile.y + step
            ctx.strokeStyle = "white";
            ctx.lineWidth = 2;
            ctx.beginPath();
            if(tile.flow === flows.end){
                ctx.setTransform(1,0,0,1,x,y);
                ctx.moveTo(-step / 2, -step / 2);
                ctx.lineTo(step / 2, step / 2);
                ctx.moveTo(step / 2, -step / 2);
                ctx.lineTo(-step / 2, step / 2);
                
                ctx.stroke();
                ctx.setTransform(1,0,0,1,0,0);
                return;
            }else if(tile.flow === flows.start){
                ctx.setTransform(1,0,0,1,x,y);
                ctx.moveTo(step / 2, 0);
                ctx.arc(0,0, step / 2,0,Math.PI * 2);
                ctx.stroke();
                ctx.setTransform(1,0,0,1,0,0);
                return;
            }else if(tile.flow === flows.right){
                ctx.setTransform(1,0,0,1,x,y);
            } else if(tile.flow === flows.left){
                ctx.setTransform(-1,0,0,1,x,y);
            } else if(tile.flow === flows.down){
                ctx.setTransform(0,1,1,0,x,y);
            } else if(tile.flow === flows.up){
                ctx.setTransform(0,-1,1,0,x,y);
                //ctx.setTransform(0,1,-1,0,0,0);
            }
            ctx.moveTo(-step / 2, 0);
            ctx.lineTo(step / 2, 0);
            ctx.moveTo(step / 4, -step / 4);
            ctx.lineTo(step / 2, 0);
            ctx.lineTo(step / 4, step / 4);
            ctx.stroke();
            ctx.setTransform(1,0,0,1,0,0);
        }
        ctx.clearRect(0,0,canvas.width,canvas.height)
        var i = 0;
        while(i < tiles.length){
            var l = tiles[i++];
            console.log("i = "+i+", tiles.length = "+tiles.length);

            ctx.fillStyle = l.col
            ctx.fillRect(l.x,l.y,l.tilex,l.tiley);
            arrow(l);
            ctx.fillStyle = '#FFF';
            //ctx.font = "10 Arial";
			ctx.fillText("#"+i,l.x+l.tilex*1/8,l.y+l.tiley*5/16); //toggle individual tile ID's
			ctx.fillText("pix: "+l.x+", "+l.y,l.x+l.tilex*1/8,l.y+l.tiley*8/16);
			ctx.fillText("flow: "+l.flow,l.x+l.tilex*1/8,l.y+l.tiley*11/16);
			//ctx.fillText("d: "+l.output,l.x+l.tilex*1/8,l.y+l.tiley*14/16);
			ctx.fillText("tile : "+l.x/l.tilex+", "+l.y/l.tiley,l.x+l.tilex*1/8,l.y+l.tiley*14/16);
        }
       
    }
    
    var flowMaps = [flows.map1,flows.map2,flows.map3,flows.map4,flows.map5,flows.map6,flows.map7,flows.map8];
    var currentFlow = 0;
    function drawAll(){
	    reset(tiles);
	    createFlow(tiles,flowMaps[currentFlow]);
        draw(tiles);
        //setTimeout(setFlow,1000);
    }
    /*function setFlow(){
        createFlow(tiles,flowMaps[(currentFlow++) % flowMaps.length]);
        draw(tiles);
        //setTimeout(drawAll,4000); //comment out this line to stop map change cycle
    }*/
    function report(){
	    	console.log("Canvas Width : "+canvas.width);
            console.log("Canvas Height : "+canvas.height);
	        console.log("Wall Width : "+wallx);
            console.log("Wall Height : "+wally);
            console.log("Tiles Wide : "+cols);
            console.log("Tiles Hight : "+rows);
            console.log("Tile Width : "+tilex);
            console.log("Tile Height : "+tiley);
            console.log("Output Width : "+outputx);
            console.log("Output Height : "+outputy);
			console.log("Output Columns : "+outCols);
            console.log("Output Rows : "+outRows);
            console.log("currentFlow = "+currentFlow);

    }
    drawAll();
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
	<div id="inputs">
		<span id="wall">
		Wall Width : <input id="wallx" type="text" placeholder="in pixels">
		Wall Height : <input id="wally" type="text" placeholder="in pixels">
		<hr>
		Tiles Wide : <input id="cols" type="text" placeholder="in tiles">
		Tiles High : <input id="rows" type="text" placeholder="in tiles">
		<hr>
		Tile Width : <input id="tilex" type="text" placeholder="in pixels">
		Tile Height : <input id="tiley" type="text" placeholder="in pixels">
		<hr>
		Output Width Limit : <input id="outputx" type="text" placeholder="in pixels">
		Output Height Limit : <input id="outputy" type="text" placeholder="in pixels">
		<hr>
		<form id="dataFlow">
			Flow 1 : <input id="flow1" type="radio" name="flow" value="0" checked="checked">
			Flow 2 : <input id="flow2" type="radio" name="flow" value="1">
			Flow 3 : <input id="flow3" type="radio" name="flow" value="2">
			Flow 4 : <input id="flow4" type="radio" name="flow" value="3">
			Flow 5 : <input id="flow5" type="radio" name="flow" value="4">
			Flow 6 : <input id="flow6" type="radio" name="flow" value="5">
			Flow 7 : <input id="flow7" type="radio" name="flow" value="6">
			Flow 8 : <input id="flow8" type="radio" name="flow" value="7">
		</form>
		</span>
	</div>
	
	

	<script type="text/javascript" src="createImage.js">
	</script>
		<script>
		$(function(){

			
			var $wallx=document.getElementById('wallx');
			var $wally=document.getElementById('wally');
			var $cols=document.getElementById('cols');
			var $rows=document.getElementById('rows');
			var $tilex=document.getElementById('tilex');
			var $tiley=document.getElementById('tiley');
			var $outputx=document.getElementById('outputx');
			var $outputy=document.getElementById('outputy');
			
			var $flow1=document.getElementById('flow1');
			var $flow2=document.getElementById('flow2');
			var $flow3=document.getElementById('flow3');
			var $flow4=document.getElementById('flow4');
			var $flow5=document.getElementById('flow5');
			var $flow6=document.getElementById('flow6');
			var $flow7=document.getElementById('flow7');
			var $flow8=document.getElementById('flow8');
			
			$wallx.value=wallx;
			$wally.value=wally;
			$cols.value=cols;
			$rows.value=rows;
			$tilex.value=tilex;
			$tiley.value=tiley;
			$outputx.value=outputx;
			$outputy.value=outputy;
			
			$wallx.addEventListener("change", function(){
				wallx=this.value; //.value converts input field int to string***
				console.log("	wallx changed to : "+wallx);
				drawAll();
			}, false);
			
			$wally.addEventListener("change", function(){
				wally=this.value; //.value converts input field int to string***
				console.log("	wally changed to : "+wally);
				drawAll();
			}, false);
			
			$cols.addEventListener("change", function(){
				cols=parseInt(this.value); //.value converts input field int to string***
				console.log("	cols changed to : "+cols);
				drawAll();
				$wallx.value=wallx;
				$wally.value=wally;
			}, false);
			
			$rows.addEventListener("change", function(){
				rows=parseInt(this.value); //.value converts input field int to string***
				console.log("	rows changed to : "+rows);
				drawAll();
				$wallx.value=wallx;
				$wally.value=wally;
			}, false);
			
			$tilex.addEventListener("change", function(){
				tilex=parseInt(this.value); //.value converts input field int to string***
				console.log("	tilex changed to : "+tilex);
				drawAll();
				$wallx.value=wallx;
				$wally.value=wally;
				$outputx.value=outputx;
				$outputy.value=outputy;
				
				
			}, false);
			
			$tiley.addEventListener("change", function(){
				tiley=parseInt(this.value); //.value converts input field int to string***
				console.log("	tiley changed to : "+tiley);
				drawAll();
				$wallx.value=wallx;
				$wally.value=wally;
				$outputx.value=outputx;
				$outputy.value=outputy;
				
			}, false);
			
			$outputx.addEventListener("change", function(){
				outputx=parseInt(this.value); //.value converts input field int to string***
				console.log("	outputx changed to : "+outputx);
				drawAll();
			}, false);
			
			$outputy.addEventListener("change", function(){
				outputy=parseInt(this.value); //.value converts input field int to string***
				console.log("	outputy changed to : "+outputy);
				drawAll();
			}, false);
			
			$flow1.addEventListener("click", function(){
		        currentFlow=parseInt(this.value); //.value converts input field int to string***
		        drawAll();
		    }, false);
		    
		    $flow2.addEventListener("click", function(){
		        currentFlow=parseInt(this.value); //.value converts input field int to string***
		        drawAll();
		    }, false);
		    
		    $flow3.addEventListener("click", function(){
		        currentFlow=parseInt(this.value); //.value converts input field int to string***
		        drawAll();
		    }, false);
		    
		    $flow4.addEventListener("click", function(){
		        currentFlow=parseInt(this.value); //.value converts input field int to string***
		        drawAll();
		    }, false);
		    
		    $flow5.addEventListener("click", function(){
		        currentFlow=parseInt(this.value); //.value converts input field int to string***
		        drawAll();
		    }, false);
		    
		    $flow6.addEventListener("click", function(){
		        currentFlow=parseInt(this.value); //.value converts input field int to string***
		        drawAll();
		    }, false);
		    
		    $flow7.addEventListener("click", function(){
		        currentFlow=parseInt(this.value); //.value converts input field int to string***
		        drawAll();
		    }, false);
		    
		    $flow8.addEventListener("click", function(){
		        currentFlow=parseInt(this.value); //.value converts input field int to string***
		        drawAll();
		    }, false);
		});
	</script>
</body>

\$\endgroup\$
  • \$\begingroup\$ Consider: All eight flows are fairly simple transforms of each other. You should be able draw any flow in a three-stage process; (1) data --> baseFlow; (2) baseFlow --> finalFlow; (3) finalFlow --> renderedOnCanvas, where baseFlow and finalFlow are unrendered representations of the data, and the mapping baseFlow --> finalFlow is some combination of flip-horizontal, flip-vertical, flip-leading_diagonal, flip-trailing-diagonal. Thus, issues like the one you are having will need to be solved once at the baseFlow stage. \$\endgroup\$ – Roamer-1888 Feb 28 '17 at 5:27
  • \$\begingroup\$ Also: You would benefit from encapsulating the code in a constructor function, say Checkerboard(), such that you can call var myBoard = new Checkerboard(params) as many times as necessary to make multiple boards, each on its own canvas. \$\endgroup\$ – Roamer-1888 Mar 6 '17 at 16:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.