Click here to Skip to main content
15,896,414 members
Articles / Artificial Intelligence / Machine Learning

JavaScript Machine Learning and Neural Networks with Encog

Rate me:
Please Sign up or sign in to vote.
4.88/5 (7 votes)
16 Oct 2012Apache18 min read 88.9K   1.4K   27  
Use Encog genetic algorithms, simulated annealing, neural networks and more with HTML5 Javascript.
/*
 * Encog(tm) Core v0.1 - Javascript Version
 * http://www.heatonresearch.com/encog/
 * http://code.google.com/p/encog-java/

 * Copyright 2008-2012 Heaton Research, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *   
 * For more information on Heaton Research copyrights, licenses 
 * and trademarks visit:
 * http://www.heatonresearch.com/copyright
 */

ENCOG.namespace('ENCOG.GUI.Console');
ENCOG.namespace('ENCOG.GUI.CellGrid');
ENCOG.namespace('ENCOG.GUI.Drawing');
ENCOG.namespace('ENCOG.GUI.Agents2D');
ENCOG.namespace('ENCOG.GUI.TSP');

ENCOG.GUI.Console = function () {
    'use strict'
};

ENCOG.GUI.Console.prototype =
{
    consoleDiv:{},
    textarea:{},
    name:"Console",
    write:function (str) {
        'use strict';
        this.textarea.value += (str);
        this.textarea.scrollTop = this.textarea.scrollHeight;
    },
    writeLine:function (str) {
        'use strict';
        this.textarea.value += (str + '\n');
        this.textarea.scrollTop = this.textarea.scrollHeight;
    },
    clear:function () {
        'use strict';
        this.textarea.value = "";
    }
};

ENCOG.GUI.Console.create = function (id) {
    'use strict';
    var result = new ENCOG.GUI.Console();
    result.consoleDiv = document.getElementById(id);
    result.consoleDiv.innerHTML = '<textarea></textarea>';
    result.textarea = result.consoleDiv.getElementsByTagName('textarea')[0];
    return result;
};

ENCOG.GUI.CellGrid = function () {
    'use strict'
};

ENCOG.GUI.CellGrid.prototype =
{
    canvas:null,
    drawingContext:null,
    canvasDiv:null,
    canvasWidth:null,
    canvasHeight:null,
    gridWidth:null,
    gridHeight:null,
    determineColor:null,
    pointerDown:null,
    pointerUp:null,
    pointerMove:null,
    pointerMode:0,
    captureTouch:true,
    outline:false,
    NAME:"CellGrid",

    render:function () {
        var output, row, col, r, g, b, c;

        this.drawingContext.strokeStyle = 'grey';

        for (row = 0; row < this.gridHeight; row += 1) {
            for (col = 0; col < this.gridWidth; col += 1) {
                this.drawingContext.fillStyle = this.determineColor(row, col);
                this.drawingContext.fillRect(col * this.pixW, row * this.pixH, this.pixW, this.pixH);
                if (this.outline) {
                    this.drawingContext.strokeRect(col * this.pixW, row * this.pixH, this.pixW, this.pixW);
                }
            }
        }

        this.drawingContext.strokeStyle = "black";
    },
    ev_canvas:function (ev) {

        var row, col;

        if (ev.layerX || ev.layerX == 0) {
            ev._x = ev.layerX;
            ev._y = ev.layerY;
        }
        // Opera
        else if (ev.offsetX || ev.offsetX == 0) {
            ev._x = ev.offsetX;
            ev._y = ev.offsetY;
        }

        switch (this.pointerMode) {
            case ENCOG.GUI.CellGrid.MODE_XY:
                row = ev._y;
                col = ev._x;
                break;
            case ENCOG.GUI.CellGrid.MODE_CELL:
                row = Math.floor(ev._y / this.pixH);
                col = Math.floor(ev._x / this.pixW);
                break;
            case ENCOG.GUI.CellGrid.MODE_PCT:
                row = ev._y / this.canvas.height;
                col = ev._x / this.canvas.width;
                break;
        }

        if (ev.type == 'mousedown' || ev.type == 'touchstart') {
            if (this.pointerDown != null) {
                this.pointerDown(row, col);
            }
        }
        else if (ev.type == 'mouseup' || ev.type == 'touchend') {
            if (this.pointerUp != null) {
                this.pointerUp(row, col);
            }
        }
        else if (ev.type == 'mousemove' || ev.type == 'touchmove') {
            if (this.pointerMove != null) {
                this.pointerMove(row, col);
            }
            if (this.captureTouch && ev.type == 'touchmove') {
                ev.preventDefault();
            }
        }
    },
    clear:function () {
        this.canvas.width = this.canvas.width;
    }
};

ENCOG.GUI.CellGrid.MODE_XY = 0;
ENCOG.GUI.CellGrid.MODE_CELL = 1;
ENCOG.GUI.CellGrid.MODE_PCT = 2;

ENCOG.GUI.CellGrid.create = function (id, gridWidth, gridHeight, canvasWidth, canvasHeight) {
    'use strict';
    var result = new ENCOG.GUI.CellGrid();
    result.canvasDiv = document.getElementById(id);
    result.canvasWidth = canvasWidth;
    result.canvasHeight = canvasHeight;
    result.gridWidth = gridWidth;
    result.gridHeight = gridHeight;
    result.canvasDiv.innerHTML = '<canvas width="'
        + canvasWidth + '" height="' + canvasHeight + '">Browser not supported.</canvas>';
    result.canvas = result.canvasDiv.getElementsByTagName('canvas')[0];
    result.drawingContext = result.canvas.getContext('2d');
    result.pixW = Math.floor(result.canvas.width / result.gridWidth);
    result.pixH = Math.floor(result.canvas.height / result.gridHeight);

    result.canvas.addEventListener('mousedown', function (e) {
        result.ev_canvas(e);
    }, true);
    result.canvas.addEventListener('mousemove', function (e) {
        result.ev_canvas(e);
    }, true);
    result.canvas.addEventListener('mouseup', function (e) {
        result.ev_canvas(e);
    }, true);
    result.canvas.addEventListener('touchstart', function (e) {
        result.ev_canvas(e);
    }, true);
    result.canvas.addEventListener('touchend', function (e) {
        result.ev_canvas(e);
    }, true);
    result.canvas.addEventListener('touchmove', function (e) {
        result.ev_canvas(e);
    }, true);
    result.canvas.addEventListener('mouseout', function (e) {
        result.ev_canvas(e);
    }, true);
    return result;
};


ENCOG.GUI.Drawing = function () {
    'use strict'
};

ENCOG.GUI.Drawing.create = function (id, canvasWidth, canvasHeight) {
    'use strict';
    var result = new ENCOG.GUI.Drawing();

    result.canvasDiv = document.getElementById(id);
    result.canvasWidth = canvasWidth;
    result.canvasHeight = canvasHeight;
    result.canvasDiv.innerHTML = '<canvas width="'
        + canvasWidth + '" height="' + canvasHeight + '">Browser not supported.</canvas>';
    result.canvas = result.canvasDiv.getElementsByTagName('canvas')[0];
    result.drawingContext = result.canvas.getContext('2d');

    // Attach the mousedown, mousemove and mouseup event listeners.
    result.canvas.addEventListener('mousedown', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('mousemove', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('mouseup', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('touchstart', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('touchend', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('touchmove', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('mouseout', function (e) {
        result.ev_canvas(e)
    }, true);


    return result;
};

ENCOG.GUI.Drawing.prototype =
{
    canvas:null,
    drawingContext:null,
    canvasDiv:null,
    NAME:"Drawing",
    canvasWidth:null,
    canvasHeight:null,
    started:false,
    downsampleHeight:8,
    downsampleWidth:5,


    // Handle events to the canvas.  This allows drawing to occur.
    ev_canvas:function (ev) {
        // Firefox
        if (ev.layerX || ev.layerX == 0) {
            ev._x = ev.layerX;
            ev._y = ev.layerY;
        }
        // Opera
        else if (ev.offsetX || ev.offsetX == 0) {
            ev._x = ev.offsetX;
            ev._y = ev.offsetY;
        }

// This is called when you start holding down the mouse button.
// This starts the pencil drawing.
        if (ev.type === 'mousedown') {
            this.drawingContext.beginPath();
            this.drawingContext.moveTo(ev._x, ev._y);
            this.started = true;
        }

// This function is called every time you move the mouse. Obviously, it only
// draws if the tool.started state is set to true (when you are holding down
// the mouse button).
        else if (ev.type === 'mousemove') {
            if (this.started) {
                this.drawingContext.lineTo(ev._x, ev._y);
                this.drawingContext.stroke();
            }
        }

// This is called when you release the mouse button.
        else if (ev.type === 'mouseup') {
            if (this.started) {
                this.drawingContext.lineTo(ev._x, ev._y);
                this.drawingContext.stroke();
                this.started = false;
            }
        }
        else if (ev.type === 'mouseout') {
            if (this.started) {
                this.drawingContext.lineTo(ev._x, ev._y);
                this.drawingContext.stroke();
                this.started = false;
            }
        }
        else if (ev.type === 'touchstart') {
            this.drawingContext.beginPath();
            this.drawingContext.moveTo(ev._x, ev._y);
            this.started = true;
        }
        else if (ev.type === 'touchend') {
            if (this.started) {
                this.started = false;
            }
        }
        else if (ev.type === 'touchmove') {
            if (this.started) {
                this.drawingContext.lineTo(ev._x, ev._y);
                this.drawingContext.stroke();
                ev.preventDefault();
            }
        }
    },
    // Determine if the specificed horizontal line is clear.
    // This is used to find the top and bottom cropping lines.
    isHLineClear:function (row) {
        var imgd = this.drawingContext.getImageData(0, row, this.canvas.width, 1);
        var pix = imgd.data;

        for (var i = 0; i < pix.length; i++) {
            if (pix[i] > 0) {
                return false;
            }
        }

        return true;
    },

// Determine if the specificed vertical line is clear.
// This is used to find the left and right cropping lines.
    isVLineClear:function (col) {
        var imgd = this.drawingContext.getImageData(col, 0, 1, this.canvas.height);
        var pix = imgd.data;

        for (var i = 0; i < pix.length; i++) {
            if (pix[i] > 0) {
                return false;
            }
        }

        return true;
    },

// Downsample the drawing area.
    performDownSample:function () {
        'use strict';
        var top, bottom, left, right, cellWidth, cellHeight, result, resultIndex, row, col, pix, x, y, d, i, imgd;

        // first find a bounding rectangle so that we can crop out unused space
        top = 0;

        while (this.isHLineClear(top) && top < this.canvas.height) {
            top++;
        }

        bottom = this.canvas.height;

        while (this.isHLineClear(bottom) && bottom > 0) {
            bottom--;
        }

        left = 0;

        while (this.isVLineClear(left) && left < this.canvas.width) {
            left++;
        }

        right = this.canvas.width;

        while (this.isVLineClear(right) && right > 0) {
            right--;
        }

        if (bottom < top) {
            result = ENCOG.ArrayUtil.allocate1D(this.downsampleHeight * this.downsampleWidth);
            ENCOG.ArrayUtil.fillArray(result, 0, result.length, -1);
            return result;
        }
        //uncomment this if you want to see the cropping rectangle
        //drawingContext.strokeRect(left,top,right-left,bottom-top);

        // now downsample

        cellWidth = (right - left) / this.downsampleWidth;
        cellHeight = (bottom - top) / this.downsampleHeight;
        result = new Array();
        resultIndex = 0;

        // to downsample we are going to lay a "grid" over the drawing
        // the grid's dimensions are defined by DOWNSAMPLE_HEIGHT and
        // DOWNSAMPLE_WIDTH.  Typically 5x8.  If even one pixel is
        // present in a grid square, it is downsampled to "black".

        for (row = 0; row < this.downsampleHeight; row++) {
            for (col = 0; col < this.downsampleWidth; col++) {
                x = (cellWidth * col) + left;
                y = (cellHeight * row) + top;

                // obtain pixel data for the grid square
                imgd = this.drawingContext.getImageData(x, y, cellWidth, cellHeight);
                pix = imgd.data;

                d = false;
                // see if at least one pixel is "black"
                for (i = 0; i < pix.length; i++) {
                    if (pix[i] > 0) {
                        d = true;
                        break;
                    }
                }

                // we are downsampling to an array where 1.0 is black, and -1.0 is white.
                // this will be used for Euclidean distance measuring.
                if (d) {
                    result[resultIndex++] = 1.0;
                } else {
                    result[resultIndex++] = -1.0;
                }
            }
        }

        return result;
    },
    clear:function () {
        this.canvas.width = this.canvas.width;
    }
};


////////////////////////////////////

ENCOG.GUI.Agents2D = function () {
    'use strict'
};

ENCOG.GUI.Agents2D.create = function (id, canvasWidth, canvasHeight) {
    'use strict';
    var result = new ENCOG.GUI.Agents2D();

    result.canvasDiv = document.getElementById(id);
    result.canvasWidth = canvasWidth;
    result.canvasHeight = canvasHeight;
    result.canvasDiv.innerHTML = '<canvas width="'
        + canvasWidth + '" height="' + canvasHeight + '">Browser not supported.</canvas>';
    result.canvas = result.canvasDiv.getElementsByTagName('canvas')[0];
    result.drawingContext = result.canvas.getContext('2d');

    // Attach the mousedown, mousemove and mouseup event listeners.
    result.canvas.addEventListener('mousedown', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('mousemove', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('mouseup', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('touchstart', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('touchend', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('touchmove', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('mouseout', function (e) {
        result.ev_canvas(e)
    }, true);


    return result;
};

ENCOG.GUI.Agents2D.prototype =
{
    canvas:null,
    drawingContext:null,
    canvasDiv:null,
    NAME:"Agents2D",
    canvasWidth:null,
    canvasHeight:null,
    agents:null,
    agentSize:10,
    agentSpeed:5,
    pointerDown:null,
    pointerUp:null,
    pointerMove:null,
    captureTouch:true,


    // Handle events to the canvas.  This allows drawing to occur.
    ev_canvas:function (ev) {

    },
    reset:function (count) {
        'use strict';
        this.agents = [];
        for (var i = 0; i < count; i++) {
            this.agents[i] = [
                Math.floor(Math.random() * this.canvas.width),
                Math.floor(Math.random() * this.canvas.height),
                Math.floor(Math.random() * 360)];
        }
        this.render();
    },
    advance:function () {
        'use strict';
        var aff, r, r2, dy, dx, x, y, x2, y2, x3, y3, meanX, meanY, dx, dy, targetAngle, neighbors, nearest;
        var separation, alignment, cohesion, turnAmount;

        // loop over all agents
        for (var i = 0; i < this.agents.length; i++) {
            // Each particle is moving in a fixed speed in a direction
            // specified by the 2nd array element of the particle.
            // Adjust the X & Y (stored in the first/second array element)
            // to reflect this movement.
            r = this.agents[i][2] * (Math.PI / 180.0);
            dy = Math.cos(r);
            dx = Math.sin(r);
            this.agents[i][0] += (dx * this.agentSpeed);
            this.agents[i][1] += (dy * this.agentSpeed);

            // Bound.  Handle particles that fly off the edge of the universe.
            // These particles will loop to the other side of the universe.
            if (this.agents[i][0] < 0) {
                this.agents[i][0] = this.canvas.width;
            }
            else if (this.agents[i][0] > this.canvas.width) {
                this.agents[i][0] = 0;
            }

            if (this.agents[i][1] < 0) {
                this.agents[i][1] = this.canvas.height;
            }
            else if (this.agents[i][1] > this.canvas.height) {
                this.agents[i][1] = 0;
            }
        }
    },
    render:function () {
        'use strict';
        var aff, r, r2, dy, dx, x, y, x2, y2, x3, y3, meanX, meanY, dx, dy, targetAngle, neighbors, nearest, i;
        var separation, alignment, cohesion, turnAmount;

        // clear the canvas.
        this.canvas.width = this.canvas.width;

        // loop over all particles.
        for (i = 0; i < this.agents.length; i++) {
            // Draw the particle.  Each particle is s small traingle that
            // points in the direction that it is moving.
            x = this.agents[i][0];
            y = this.agents[i][1];

            r = (this.agents[i][2] + 180 - 15) * (Math.PI / 180.0);
            x2 = x + (Math.sin(r) * this.agentSize);
            y2 = y + (Math.cos(r) * this.agentSize);

            r2 = (this.agents[i][2] + 180 + 15) * (Math.PI / 180.0);
            x3 = x + (Math.sin(r2) * this.agentSize);
            y3 = y + (Math.cos(r2) * this.agentSize);

            this.drawingContext.strokeStyle = "#000000";
            this.drawingContext.beginPath();
            this.drawingContext.moveTo(x2, y2);
            this.drawingContext.lineTo(x, y);
            this.drawingContext.lineTo(x3, y3);
            this.drawingContext.closePath();
            this.drawingContext.stroke();
        }
    },
    // Plot gray lines to show an affinity group.  This is a particle and
    // all other particles that are neighbors.  If two flocks have no lines
    // between them, they have become independant.
    plotGroup:function (idx, others) {
        'use strict';
        var x1 = this.agents[idx][0];
        var y1 = this.agents[idx][1];

        for (var i = 0; i < others.length; i++) {
            var x2 = others[i][0];
            var y2 = others[i][1];

            this.drawingContext.strokeStyle = "#f0f0f0";
            this.drawingContext.beginPath();
            this.drawingContext.moveTo(x1, y1);
            this.drawingContext.lineTo(x2, y2);
            this.drawingContext.closePath();
            this.drawingContext.stroke();
        }
    },
    ev_canvas:function (ev) {

        if (ev.layerX || ev.layerX == 0) {
            ev._x = ev.layerX;
            ev._y = ev.layerY;
        }
        // Opera
        else if (ev.offsetX || ev.offsetX == 0) {
            ev._x = ev.offsetX;
            ev._y = ev.offsetY;
        }

        if (ev.type == 'mousedown' || ev.type == 'touchstart') {
            if (this.pointerDown != null) {
                this.pointerDown(ev._x, ev._y);
            }
        }
        else if (ev.type == 'mouseup' || ev.type == 'touchend') {
            if (this.pointerUp != null) {
                this.pointerUp(ev._x, ev._y);
            }
        }
        else if (ev.type == 'mousemove' || ev.type == 'touchmove') {
            if (this.pointerMove != null) {
                this.pointerMove(ev._x, ev._y);
            }
            if (this.captureTouch && ev.type == 'touchmove') {
                ev.preventDefault();
            }
        }
    }

};


////////////////////////////////////

ENCOG.GUI.TSP = function () {
    'use strict'
};

ENCOG.GUI.TSP.create = function (id, canvasWidth, canvasHeight) {
    'use strict';
    var result = new ENCOG.GUI.TSP();

    result.canvasDiv = document.getElementById(id);
    result.canvasWidth = canvasWidth;
    result.canvasHeight = canvasHeight;
    result.canvasDiv.innerHTML = '<canvas width="'
        + result.canvasWidth + '" height="' + result.canvasHeight + '">Browser not supported.</canvas>';
    result.canvas = result.canvasDiv.getElementsByTagName('canvas')[0];
    result.drawingContext = result.canvas.getContext('2d');

    // Attach the mousedown, mousemove and mouseup event listeners.
    result.canvas.addEventListener('mousedown', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('mousemove', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('mouseup', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('touchstart', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('touchend', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('touchmove', function (e) {
        result.ev_canvas(e)
    }, true);
    result.canvas.addEventListener('mouseout', function (e) {
        result.ev_canvas(e)
    }, true);


    return result;
};

ENCOG.GUI.TSP.prototype =
{
    canvas:null,
    drawingContext:null,
    canvasDiv:null,
    NAME:"TSP",
    canvasWidth:null,
    canvasHeight:null,
    pointerDown:null,
    pointerUp:null,
    pointerMove:null,
    captureTouch:true,
    cities:null,
    currentPath:null,
    tspMargin:10,

    // Handle events to the canvas.  This allows drawing to occur.
    ev_canvas:function (ev) {

    },
    reset:function (count) {
        'use strict';
        var marginWidth, marginHeight;

        this.cities = [];
        marginWidth = this.canvas.width - (this.tspMargin * 2);
        marginHeight = this.canvas.height - (this.tspMargin * 2);

        for (var i = 0; i < count; i++) {
            this.cities[i] = new Array(
                Math.floor(Math.random() * marginWidth) + this.tspMargin,
                Math.floor(Math.random() * marginHeight) + this.tspMargin);
        }

        this.currentPath = this.generatePath();
        this.render();

    },

    resetCircle: function(count) {
        // reset the cities
        this.cities = [];
        var ratio = (2 * Math.PI) / count;
        var marginWidth = this.canvas.width - (this.tspMargin * 2);
        var marginHeight = this.canvas.height - (this.tspMargin * 2);

        for (var i = 0; i < count; i++) {
            var x = Math.floor(Math.cos(ratio * i) * (marginWidth / 2) + (marginWidth / 2)) + this.tspMargin;
            var y = Math.floor(Math.sin(ratio * i) * (marginHeight / 2) + (marginHeight / 2)) + this.tspMargin;
            this.cities[i] = [x, y];
        }

        this.currentPath = this.generatePath();
        this.render();
    },

    pathDistance:function (path, i1, i2) {
        return this.distance(this.cities[path[i1]], this.cities[path[i2]]);
    },
    distance:function (a1, a2) {
        var result = 0;
        for (var i = 0; i < a1.length; i++) {
            var diff = a1[i] - a2[i];
            result += diff * diff;
        }
        return Math.sqrt(result);
    },
    calculatePathLength:function (path) {
        var result = 0;

        for (var i = 0; i < path.length - 1; i++) {
            result += this.distance(this.cities[path[i]], this.cities[path[i + 1]]);
        }

        return result;
    },
    generatePath:function () {
        var taken = new Array(this.cities.length);
        var path = new Array(this.cities.length);

        for (var i = 0; i < this.cities.length; i++) {
            taken[i] = false;
        }

        for (var i = 0; i < this.cities.length - 1; i++) {
            var icandidate;
            do
            {
                icandidate = Math.floor(Math.random() * path.length);
            } while (taken[icandidate]);

            path[i] = icandidate;
            taken[icandidate] = true;

            if (i == path.length - 2) {
                icandidate = 0;
                while (taken[icandidate]) {
                    icandidate++;
                }
                path[i + 1] = icandidate;
            }
        }

        return path;
    },
    render:function () {
        'use strict';

        this.canvas.width = this.canvas.width;

        for (var i = 0; i < this.cities.length; i++) {
            this.drawingContext.fillStyle = "#0000FF";
            this.drawingContext.beginPath();
            this.drawingContext.arc(this.cities[i][0], this.cities[i][1], 5, 0, Math.PI * 2, true);
            this.drawingContext.closePath();
            this.drawingContext.fill();
        }

        for (var i = 0; i < this.cities.length - 1; i++) {
            this.drawingContext.strokeStyle = "#000000";
            this.drawingContext.beginPath();
            this.drawingContext.moveTo(this.cities[this.currentPath[i]][0], this.cities[this.currentPath[i]][1]);
            this.drawingContext.lineTo(this.cities[this.currentPath[i + 1]][0], this.cities[this.currentPath[i + 1]][1])
            this.drawingContext.closePath();
            this.drawingContext.stroke();
        }
    },
    ev_canvas:function (ev) {

        if (ev.layerX || ev.layerX == 0) {
            ev._x = ev.layerX;
            ev._y = ev.layerY;
        }
        // Opera
        else if (ev.offsetX || ev.offsetX == 0) {
            ev._x = ev.offsetX;
            ev._y = ev.offsetY;
        }

        if (ev.type == 'mousedown' || ev.type == 'touchstart') {
            if (this.pointerDown != null) {
                this.pointerDown(ev._x, ev._y);
            }
        }
        else if (ev.type == 'mouseup' || ev.type == 'touchend') {
            if (this.pointerUp != null) {
                this.pointerUp(ev._x, ev._y);
            }
        }
        else if (ev.type == 'mousemove' || ev.type == 'touchmove') {
            if (this.pointerMove != null) {
                this.pointerMove(ev._x, ev._y);
            }
            if (this.captureTouch && ev.type == 'touchmove') {
                ev.preventDefault();
            }
        }
    }

};

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


Written By
Publisher
United States United States
Jeff Heaton, Ph.D., is a data scientist, an adjunct instructor for the Sever Institute at Washington University, and the author of several books about artificial intelligence. Jeff holds a Master of Information Management (MIM) from Washington University and a PhD in computer science from Nova Southeastern University. Over twenty years of experience in all aspects of software development allows Jeff to bridge the gap between complex data science problems and proven software development. Working primarily with the Python, R, Java/C#, and JavaScript programming languages he leverages frameworks such as TensorFlow, Scikit-Learn, Numpy, and Theano to implement deep learning, random forests, gradient boosting machines, support vector machines, T-SNE, and generalized linear models (GLM). Jeff holds numerous certifications and credentials, such as the Johns Hopkins Data Science certification, Fellow of the Life Management Institute (FLMI), ACM Upsilon Pi Epsilon (UPE), a senior membership with IEEE. He has published his research through peer reviewed papers with the Journal of Machine Learning Research and IEEE.

Comments and Discussions