Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Be able to display a polyline instead of circles only #260

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"file-loader": "^3.0.1",
"jest": "^23.6.0",
"jquery": "^3.3.1",
"leaflet": "1.6.0",
"ng-annotate-webpack-plugin": "^0.3.0",
"style-loader": "^0.23.1",
"ts-jest": "^23.10.5",
Expand Down
86 changes: 44 additions & 42 deletions src/data_formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,49 +165,51 @@ export default class DataFormatter {
let highestValue = 0;
let lowestValue = Number.MAX_VALUE;

tableData[0].forEach(datapoint => {
let key;
let longitude;
let latitude;

if (this.ctrl.panel.tableQueryOptions.queryType === 'geohash') {
const encodedGeohash = datapoint[this.ctrl.panel.tableQueryOptions.geohashField];
const decodedGeohash = decodeGeoHash(encodedGeohash);

latitude = decodedGeohash.latitude;
longitude = decodedGeohash.longitude;
key = encodedGeohash;
} else {
latitude = datapoint[this.ctrl.panel.tableQueryOptions.latitudeField];
longitude = datapoint[this.ctrl.panel.tableQueryOptions.longitudeField];
key = `${latitude}_${longitude}`;
}

const dataValue = {
key: key,
locationName: datapoint[this.ctrl.panel.tableQueryOptions.labelField] || 'n/a',
locationLatitude: latitude,
locationLongitude: longitude,
value: datapoint[this.ctrl.panel.tableQueryOptions.metricField],
valueFormatted: datapoint[this.ctrl.panel.tableQueryOptions.metricField],
valueRounded: 0,
};

if (dataValue.value > highestValue) {
highestValue = dataValue.value;
}

if (dataValue.value < lowestValue) {
lowestValue = dataValue.value;
}

dataValue.valueRounded = kbn.roundValue(dataValue.value, this.ctrl.panel.decimals || 0);
data.push(dataValue);
tableData.forEach(series => {
series.forEach(datapoint => {
let key;
let longitude;
let latitude;

if (this.ctrl.panel.tableQueryOptions.queryType === 'geohash') {
const encodedGeohash = datapoint[this.ctrl.panel.tableQueryOptions.geohashField];
const decodedGeohash = decodeGeoHash(encodedGeohash);

latitude = decodedGeohash.latitude;
longitude = decodedGeohash.longitude;
key = encodedGeohash;
} else {
latitude = datapoint[this.ctrl.panel.tableQueryOptions.latitudeField];
longitude = datapoint[this.ctrl.panel.tableQueryOptions.longitudeField];
key = `${latitude}_${longitude}`;
}

const dataValue = {
key: key,
locationName: datapoint[this.ctrl.panel.tableQueryOptions.labelField] || 'n/a',
locationLatitude: latitude,
locationLongitude: longitude,
value: datapoint[this.ctrl.panel.tableQueryOptions.metricField],
valueFormatted: datapoint[this.ctrl.panel.tableQueryOptions.metricField],
valueRounded: 0,
};

if (dataValue.value > highestValue) {
highestValue = dataValue.value;
}

if (dataValue.value < lowestValue) {
lowestValue = dataValue.value;
}

dataValue.valueRounded = kbn.roundValue(dataValue.value, this.ctrl.panel.decimals || 0);
data.push(dataValue);
});

data.highestValue = highestValue;
data.lowestValue = lowestValue;
data.valueRange = highestValue - lowestValue;
});

data.highestValue = highestValue;
data.lowestValue = lowestValue;
data.valueRange = highestValue - lowestValue;
}
}

Expand Down
233 changes: 233 additions & 0 deletions src/libs/Polyline.encoded.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
/*
* Utility functions to decode/encode numbers and array's of numbers
* to/from strings (Google maps polyline encoding)
*
* Extends the L.Polyline and L.Polygon object with methods to convert
* to and create from these strings.
*
* Jan Pieter Waagmeester <[email protected]>
*
* Original code from:
* http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/
* (which is down as of december 2014)
*/

(function () {
'use strict';

var defaultOptions = function (options) {
if (typeof options === 'number') {
// Legacy
options = {
precision: options
};
} else {
options = options || {};
}

options.precision = options.precision || 5;
options.factor = options.factor || Math.pow(10, options.precision);
options.dimension = options.dimension || 2;
return options;
};

var PolylineUtil = {
encode: function (points, options) {
options = defaultOptions(options);

var flatPoints = [];
for (var i = 0, len = points.length; i < len; ++i) {
var point = points[i];

if (options.dimension === 2) {
flatPoints.push(point.lat || point[0]);
flatPoints.push(point.lng || point[1]);
} else {
for (var dim = 0; dim < options.dimension; ++dim) {
flatPoints.push(point[dim]);
}
}
}

return this.encodeDeltas(flatPoints, options);
},

decode: function (encoded, options) {
options = defaultOptions(options);

var flatPoints = this.decodeDeltas(encoded, options);

var points = [];
for (var i = 0, len = flatPoints.length; i + (options.dimension - 1) < len;) {
var point = [];

for (var dim = 0; dim < options.dimension; ++dim) {
point.push(flatPoints[i++]);
}

points.push(point);
}

return points;
},

encodeDeltas: function (numbers, options) {
options = defaultOptions(options);

var lastNumbers = [];

for (var i = 0, len = numbers.length; i < len;) {
for (var d = 0; d < options.dimension; ++d, ++i) {
var num = numbers[i].toFixed(options.precision);
var delta = num - (lastNumbers[d] || 0);
lastNumbers[d] = num;

numbers[i] = delta;
}
}

return this.encodeFloats(numbers, options);
},

decodeDeltas: function (encoded, options) {
options = defaultOptions(options);

var lastNumbers = [];

var numbers = this.decodeFloats(encoded, options);
for (var i = 0, len = numbers.length; i < len;) {
for (var d = 0; d < options.dimension; ++d, ++i) {
numbers[i] = Math.round((lastNumbers[d] = numbers[i] + (lastNumbers[d] || 0)) * options.factor) / options.factor;
}
}

return numbers;
},

encodeFloats: function (numbers, options) {
options = defaultOptions(options);

for (var i = 0, len = numbers.length; i < len; ++i) {
numbers[i] = Math.round(numbers[i] * options.factor);
}

return this.encodeSignedIntegers(numbers);
},

decodeFloats: function (encoded, options) {
options = defaultOptions(options);

var numbers = this.decodeSignedIntegers(encoded);
for (var i = 0, len = numbers.length; i < len; ++i) {
numbers[i] /= options.factor;
}

return numbers;
},

encodeSignedIntegers: function (numbers) {
for (var i = 0, len = numbers.length; i < len; ++i) {
var num = numbers[i];
numbers[i] = (num < 0) ? ~(num << 1) : (num << 1);
}

return this.encodeUnsignedIntegers(numbers);
},

decodeSignedIntegers: function (encoded) {
var numbers = this.decodeUnsignedIntegers(encoded);

for (var i = 0, len = numbers.length; i < len; ++i) {
var num = numbers[i];
numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1);
}

return numbers;
},

encodeUnsignedIntegers: function (numbers) {
var encoded = '';
for (var i = 0, len = numbers.length; i < len; ++i) {
encoded += this.encodeUnsignedInteger(numbers[i]);
}
return encoded;
},

decodeUnsignedIntegers: function (encoded) {
var numbers = [];

var current = 0;
var shift = 0;

for (var i = 0, len = encoded.length; i < len; ++i) {
var b = encoded.charCodeAt(i) - 63;

current |= (b & 0x1f) << shift;

if (b < 0x20) {
numbers.push(current);
current = 0;
shift = 0;
} else {
shift += 5;
}
}

return numbers;
},

encodeSignedInteger: function (num) {
num = (num < 0) ? ~(num << 1) : (num << 1);
return this.encodeUnsignedInteger(num);
},

// This function is very similar to Google's, but I added
// some stuff to deal with the double slash issue.
encodeUnsignedInteger: function (num) {
var value, encoded = '';
while (num >= 0x20) {
value = (0x20 | (num & 0x1f)) + 63;
encoded += (String.fromCharCode(value));
num >>= 5;
}
value = num + 63;
encoded += (String.fromCharCode(value));

return encoded;
}
};

// Export Node module
if (typeof module === 'object' && typeof module.exports === 'object') {
module.exports = PolylineUtil;
}

// Inject functionality into Leaflet
if (typeof L === 'object') {
if (!(L.Polyline.prototype.fromEncoded)) {
L.Polyline.fromEncoded = function (encoded, options) {
return L.polyline(PolylineUtil.decode(encoded), options);
};
}
if (!(L.Polygon.prototype.fromEncoded)) {
L.Polygon.fromEncoded = function (encoded, options) {
return L.polygon(PolylineUtil.decode(encoded), options);
};
}

var encodeMixin = {
encodePath: function () {
return PolylineUtil.encode(this.getLatLngs());
}
};

if (!L.Polyline.prototype.encodePath) {
L.Polyline.include(encodeMixin);
}
if (!L.Polygon.prototype.encodePath) {
L.Polygon.include(encodeMixin);
}

L.PolylineUtil = PolylineUtil;
}
})();
2 changes: 1 addition & 1 deletion src/partials/editor.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ <h5 class="section-heading">Map Data Options</h5>
<div class="gf-form">
<label class="gf-form-label width-12">Location Data</label>
<div class="gf-form-select-wrapper max-width-10">
<select class="input-small gf-form-input" ng-model="ctrl.panel.locationData" ng-options="t for t in ['countries', 'countries_3letter', 'states', 'probes', 'geohash', 'json endpoint', 'jsonp endpoint', 'json result', 'table']"
<select class="input-small gf-form-input" ng-model="ctrl.panel.locationData" ng-options="t for t in ['countries', 'countries_3letter', 'states', 'probes', 'geohash', 'json endpoint', 'jsonp endpoint', 'json result', 'table', 'polyline']"
ng-change="ctrl.changeLocationData()"></select>
</div>
</div>
Expand Down
22 changes: 21 additions & 1 deletion src/worldmap.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as _ from 'lodash';
import * as L from './libs/leaflet';
import * as L from 'leaflet';
import './libs/Polyline.encoded';
import WorldmapCtrl from './worldmap_ctrl';

const tileServers = {
Expand All @@ -26,6 +27,7 @@ export default class WorldMap {
map: any;
legend: any;
circlesLayer: any;
polylineLayer: any;

constructor(ctrl, mapContainer) {
this.ctrl = ctrl;
Expand All @@ -45,6 +47,7 @@ export default class WorldMap {
zoom: parseInt(this.ctrl.panel.initialZoom, 10) || 1,
});
this.setMouseWheelZoom();
this.polylineLayer = L.featureGroup();

const selectedTileServer = tileServers[this.ctrl.tileServer];
(<any>window).L.tileLayer(selectedTileServer.url, {
Expand Down Expand Up @@ -253,6 +256,23 @@ export default class WorldMap {
this.map.setZoom(parseInt(zoomFactor, 10));
}

addPolyline(encoded) {
var coordinates = L.Polyline.fromEncoded(encoded).getLatLngs();
L.polyline(coordinates).addTo(this.polylineLayer);
this.polylineLayer.addTo(this.map);
}

addPolylines(series, doCenter) {
series.map(line => {
return this.addPolyline(line.polyline);
});

if (doCenter) {
this.map.fitBounds(this.polylineLayer.getBounds());
}
}


remove() {
this.circles = [];
if (this.circlesLayer) {
Expand Down
Loading