126 lines
No EOL
4.3 KiB
JavaScript
126 lines
No EOL
4.3 KiB
JavaScript
/*
|
|
* The MIT License
|
|
|
|
Copyright (c) 2013 by Sveinn Steinarsson
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
*/
|
|
|
|
(function ($) {
|
|
"use strict";
|
|
|
|
var floor = Math.floor,
|
|
abs = Math.abs;
|
|
|
|
function largestTriangleThreeBuckets(data, threshold) {
|
|
|
|
var data_length = data.length;
|
|
if (threshold >= data_length || threshold === 0) {
|
|
return data; // Nothing to do
|
|
}
|
|
|
|
var sampled = [],
|
|
sampled_index = 0;
|
|
|
|
// Bucket size. Leave room for start and end data points
|
|
var every = (data_length - 2) / (threshold - 2);
|
|
|
|
var a = 0, // Initially a is the first point in the triangle
|
|
max_area_point,
|
|
max_area,
|
|
area,
|
|
next_a;
|
|
|
|
sampled[ sampled_index++ ] = data[ a ]; // Always add the first point
|
|
|
|
for (var i = 0; i < threshold - 2; i++) {
|
|
|
|
// Calculate point average for next bucket (containing c)
|
|
var avg_x = 0,
|
|
avg_y = 0,
|
|
avg_range_start = floor( ( i + 1 ) * every ) + 1,
|
|
avg_range_end = floor( ( i + 2 ) * every ) + 1;
|
|
avg_range_end = avg_range_end < data_length ? avg_range_end : data_length;
|
|
|
|
var avg_range_length = avg_range_end - avg_range_start;
|
|
|
|
for ( ; avg_range_start<avg_range_end; avg_range_start++ ) {
|
|
avg_x += data[ avg_range_start ][ 0 ] * 1; // * 1 enforces Number (value may be Date)
|
|
avg_y += data[ avg_range_start ][ 1 ] * 1;
|
|
}
|
|
avg_x /= avg_range_length;
|
|
avg_y /= avg_range_length;
|
|
|
|
// Get the range for this bucket
|
|
var range_offs = floor( (i + 0) * every ) + 1,
|
|
range_to = floor( (i + 1) * every ) + 1;
|
|
|
|
// Point a
|
|
var point_a_x = data[ a ][ 0 ] * 1, // enforce Number (value may be Date)
|
|
point_a_y = data[ a ][ 1 ] * 1;
|
|
|
|
max_area = area = -1;
|
|
|
|
for ( ; range_offs < range_to; range_offs++ ) {
|
|
// Calculate triangle area over three buckets
|
|
area = abs( ( point_a_x - avg_x ) * ( data[ range_offs ][ 1 ] - point_a_y ) -
|
|
( point_a_x - data[ range_offs ][ 0 ] ) * ( avg_y - point_a_y )
|
|
) * 0.5;
|
|
if ( area > max_area ) {
|
|
max_area = area;
|
|
max_area_point = data[ range_offs ];
|
|
next_a = range_offs; // Next a is this b
|
|
}
|
|
}
|
|
|
|
sampled[ sampled_index++ ] = max_area_point; // Pick this point from the bucket
|
|
a = next_a; // This a is the next a (chosen b)
|
|
}
|
|
|
|
sampled[ sampled_index++ ] = data[ data_length - 1 ]; // Always add last
|
|
|
|
return sampled;
|
|
}
|
|
|
|
|
|
function processRawData ( plot, series ) {
|
|
series.data = largestTriangleThreeBuckets( series.data, series.downsample.threshold );
|
|
}
|
|
|
|
|
|
var options = {
|
|
series: {
|
|
downsample: {
|
|
threshold: 1000 // 0 disables downsampling for this series.
|
|
}
|
|
}
|
|
};
|
|
|
|
function init(plot) {
|
|
plot.hooks.processRawData.push(processRawData);
|
|
}
|
|
|
|
$.plot.plugins.push({
|
|
init: init,
|
|
options: options,
|
|
name: "downsample",
|
|
version: "0.1"
|
|
});
|
|
|
|
})(jQuery); |