View on GitHub

line_intersection.js

A JavaScript library to find the intersection of two straight lines (useful for charting libraries)

Download this project as a .zip file Download this project as a tar.gz file

line_intersection.js

A JavaScript library to find the intersection of two straight lines (useful for charting libraries). Also includes a function that generate trendline from a chart data.

Written originally for highcharts but can work with any charting library as long as they support line data in the format [[x1, y1], [x2, y2], ... ] such as Flot, PlotKit, JS Charts etc. For other libraries, you will need to convert the data to this form and back after getting the intersection data.

Methods

Usage

getLineIntersectionData(line1_data, line2_data, user_options)

Documentation

/**
 * @param line1_data - Mandatory argument that contains the data of line1 of the form 
 *                      [[x1, y1], [x2, y2], ... [xn, yn]]
 * 
 * @param line2_data - Mandatory argument that contains the data of line2 of the form 
 *                      [[x1, y1], [x2, y2], ... [xn, yn]]
 * 
 * @param user_options - Optional argument that is an object containing custom options that overrides the default
 *                      behavior of the method. Refer the comments for each option in the opt object for the valid
 *                      values for that option.
 *
 * @returns
 * > an object with the following properties
 *     icptX - The intersection point X
 *     icptY - The intersection point Y
 *     line1_data - The new line1 data with intersection point added
 *     line2_data - The new line2 data with intersection point added
 * > or returns undefined
 *     if the lines are parallel,
 *     if any of the first two arguments are not in the form [[x1, y1], [x2, y2], ... [xn, yn]]
 *     if any of the line data has less than 2 points (it's not a line then)
 *     if the user_options argument or any of the options inside it is not in the required format
 *     if any callback set in user_options returns false
 */

Basic example

var line1 = [[0, 1], [2, 1]];
var line2 = [[1, 0], [1, 2]];
var forecast = getLineIntersectionData(line1, line2);
JSON.stringify(forecast)
>> {"icptX": 1, "icptY": 1, "line1_data": [[0,1],[1,1],[2,1]], "line2_data": [[1,0],[1,1],[1,2]]}

Example with chart

jQuery(function () {
    var data1 = [[2, 6], [12, 8]];
    var data2 = [[3, 1], [10, 5]];

    var forecast = getLineIntersectionData(data1, data2);

    var chart_linear = new Highcharts.Chart({
        chart: {
            renderTo: 'container'
        },
        series: [{
            //getLineIntersectionData() may return undefined if lines can not intersect
            data: forecast && forecast.line1_data || data1
        }, {
            data: forecast && forecast.line2_data || data2
        }]
    });
});

Output:

Basic chart example

getTrendlineData(data)

The code and this example were extracted from highcharts_trendline

Documentation

/** 
 * @param data - Mandatory argument that contains the chart data of the form 
 *                 [[x1, y1], [x2, y2], ... [xn, yn]]
 *
 * @returns an object containing the following properties
 *      data - new array containing the data for the straight trendline
 *      slope - slope of the trendline
 *      intercept - intercept of the trendline
 * 
 */

Example

jQuery(function () {
    // E.g. source data
    var sourceData = [
        [106.4, 271.8], [129.2, 213.4],
        [295.6, 432.3], [154.4, 398.1],
        [129.9, 133.2], [271.5, 432.1],
        [144.0, 134.7], [176.0, 399.2],
        [216.4, 319.2], [194.1, 542.1],
        [435.6, 665.3], [348.5, 435.9]
    ];

    var chart_linear = new Highcharts.Chart({
        chart: {
            renderTo: 'container'
        },
        series: [{
            type: 'scatter',
            data: sourceData
        }, {
            marker: {
                enabled: false
            },
            /* function returns data for trend-line */
            data: getTrendlineData(sourceData).data
        }]
    });
});

Output:

getTrendlineData screenshot 1

Example using both methods

jQuery(function () {
    var data1 = [
        [Date.UTC(2013, 0, 1), 50],
        [Date.UTC(2013, 0, 2), 58],
        [Date.UTC(2013, 0, 3), 58],
        [Date.UTC(2013, 0, 4), 58]
    ];
    var data2 = [
        [Date.UTC(2013, 0, 1), 0],
        [Date.UTC(2013, 0, 2), 12],
        [Date.UTC(2013, 0, 3), 18],
        [Date.UTC(2013, 0, 4), 22]
    ];
    var data1_t = getTrendlineData(data1).data;
    var data2_t = getTrendlineData(data2).data;
    var options = {
        icptPoint: {
            //name: 'Possible release date',
            marker: {
                enabled: true,
                fillColor: '#003300',
                lineColor: '#003300'
            }
        },
        validateIntersection: function(icptX, icptY) {
            // Don't connect the lines if the intersection point is
            // to the left of the chart
            if (icptX < data1_t[0][0] || icptX < data2_t[0][0]) {
                return false;
            }
        }
    };
    var forecast = getLineIntersectionData(data1_t, data2_t, options);

    var chart_linear = new Highcharts.Chart({
        chart: {
            renderTo: 'container'
        },
        colors: ['#990000', '#4679BD', '#990000', '#4679BD'],
        xAxis: {
            type: 'datetime',
            gridLineWidth: 1,
            gridLineDashStyle: 'shortdot'
        },
        yAxis: {
            min: 0,
            gridLineDashStyle: 'shortdot'
        },
        title: {
            text: 'Estimating release date'
        },
        series: [{
            name: 'Total issues',
            data: data1
        }, {
            name: 'Closed issues',
            data: data2
        }, {
            name: 'Total issues trend',
            //getLineIntersectionData() may return undefined if lines can not intersect
            data: forecast && forecast.line1_data || data1_t,
            marker: {
                enabled: false
            },
            dashStyle: 'longDash'
        }, {
            name: 'Closed issues trend',
            data: forecast && forecast.line2_data || data2_t,
            marker: {
                enabled: false
            },
            dashStyle: 'longDash',
        }]
    });
});

Output:

Trend forecast

See live demo for this chart here

Tests

Live unit tests available here

Credits