Update maplibre/mapbox geoJSON line, from sockets.io data - socket.io

I am currently receiving on client side, some coordinates (lat, lon) from my Node-Express-Socket.IO server. I am using these coordinates to update a marker, with my callback function:
socket.on("geolocation-data", function(msg) {
// update marker position
marker.setLngLat([msg.lon, msg.lat]);
}
So far, so good. Now I want to draw a line between the coordinates I am receiving and another fixed point.
I am adding a data source (with arbitrary initial values), then a layer in a separate function:
map.on('load', function() {
map.addSource('route', {
'type': 'geojson',
'data': 'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
[40, 40],
[50, 50],
]
}
});
map.addLayer({
'id': 'route',
'type': 'line',
'source': 'route',
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': '#888',
'line-width': 8
}
});
I have tried adding map.getSource('route').setData(// new data here) inside the sockets.io callback but I cannot get the line to update. As soon as I move it outside and put it inside map.on('load') it works, but only if I hardcode some values.
What am I doing wrong?
EDIT: I have also tried putting the socket functions inside the map.on('load') function, but it didn't work either.

SOLVED!
I was putting lat, lon instead of lon,lat to the new data (where as in the marker data it was correct).
So overall structure is:
map.on('load', function () {
socket.on("geolocation-data", function (msg) {
// do something
//update variable geoJSONline, according to the msg
map.getSource('route').setData(geoJSONline);
}
map.addSource('route', {
type: 'geojson',
data: geoJSONline
});
map.addLayer({
'id': 'route',
'type': 'line',
'source': 'route',
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': '#888',
'line-width': 8
}
});

Related

Kendo Chart Does not show Data

Im sending my json data through controller like following:i have written the query here just to prevent making it complicated and messy :
My Controller Returning This:
public JsonResult powerConverter(string regionalManager)
foreach (DataRow dt in dt_power_conv.Rows)
{
_powerConv.turbineName.Add(dt["turbine_name"].ToString());
_powerConv.duration_hrs.Add(double.Parse(dt["duration_hrs"].ToString()));
_powerConv.abb_conv.Add(dt["abb_conv"].ToString());
_powerConv.eei_conv.Add(dt["eei_conv"].ToString());
_powerConv.leit_drive_conv.Add(dt["leit_drive_conv"].ToString());
}
return Json(_powerConv, JsonRequestBehavior.AllowGet);
}
in my view I get it with an Ajax call and simply bind my chart with it:
$.ajax({
dataType: "json",
type: "POST",
url: "#Url.Action("powerConverter","Ranking")",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({ "regionalManager": tmpString }),
success: function (result) {
debugger;
$("#powerChart").kendoChart({
dataSource: {
data: result
},
chartArea: {
background: "#fcfcfc",
},
series: [{
axis: "l100km",
type: "column",
// name: "DURATION",
color: "#008080",
field: "duration_hrs",
categoryField: "turbineName"
},
],
categoryAxis: {
axisCrossingValue: [0, 20],
majorGridLines: {
visible: false
},
line: {
visible: true
},
labels: {
rotation: 340
},
},
tooltip: {
visible: true,
// majorUnit:10,
template: " #= value #"
},
});
}
});
I also posted the screen shot of my json,but still its not working,i set the categoryField and field with the exact name im getting from json but the chart shows nothing
It looks like the controller is returning two arrays, one for errorDuration and one for turbineName. Try changing the controller to return an array of objects.
You would want a review of returned json to show
[0] = { duration: 1, turbine: "a" }
[1] = { duration: 2, turbine: "b" }
[2] = { duration: 3, turbine: "c" }
In the chart the config settings for the series the field names have to match exactly the property names of the data elements, thus
field: "duration",
categoryField: "turbine",
Added
The controller code appears to be populating a list of a model class whose fields are also lists. Try updating it to return the Json for a list of objects
For quickness this example shows how using anonymous objects. Strongly typed objects are highly recommended for robustness and Visual Studio intellisense. The field names that you use in your kendo chart configuration will be "turbine_name" and "duration_hours"
// This technique copied from #Paul Rouleau answer to
// https://stackoverflow.com/questions/612689/a-generic-list-of-anonymous-class
// initialize an empty list that will contain objects having two fields
var dataForJson = new List<Tuple<string, double>>()
.Select(t => new {
turbine_name = t.Item1,
duration_hours = t.Item2 }
).ToList();
// go through data table and move data into the list
foreach (DataRow row in myDataTable.Rows)
{
dataForJson.Add (new {
turbine_name = (string)row["turbine_name"],
duration_hours = (double)row["duration_hours"]
});
}
return Json(dataForJson, JsonRequestBehavior.AllowGet);
Note, if you do further research you will find numerous other ways to convert a data table into a Json

C3.js combination chart with time series - tooltip not functional

I've been trying for 3 days to get this chart to display the way I want it to. Everything was working 100% until I realized the grouped bar chart numbers were off.
Example: When the bottom bar value equals 10 and the top bar value equals 20, the top of the grouped bar read 30. This is the default behavior, but not how I want to represent my data. I want the top of the grouped bar to read whatever the highest number is, which lead me to this fiddle representing the data exactly how I wanted to.
After refactoring my logic, this is what I have so far. As you can see the timeseries line is broken up and the tooltip is not rendering the group of data being hovered over.
My questions:
1) How to get the tooltip to render all three data points (qty, price, searches)
2) How to solidify the timeseries line so it's not disconnected
Any help would be greatly appreciated so I can move on from this 3 day headache!
Below is most of my code - excluding the JSON array for brevity, which is obtainable at my jsfiddle link above. Thank you in advance for your time.
var chart = c3.generate({
bindto: '#chart',
data: {
x: 'x-axis',
type: 'bar',
json: json,
xFormat: '%Y-%m-%d',
keys: {
x: 'x-axis',
y: 'searches',
value: ['qty', 'searches', 'price']
},
types: {
searches: 'line'
},
groups: [
['qty', 'price']
],
axes: {
qty: 'y',
searches: 'y2'
},
names: {
qty: 'Quantity',
searches: 'Searches',
price: 'Price ($)'
},
colors: {
price: 'rgb(153, 153, 153)',
qty: 'rgb(217, 217, 217)',
searches: 'rgb(255, 127, 14)'
}
},
bar: {
width: {
ratio: 0.60
}
},
axis: {
x: {
type: 'timeseries',
label: { text: 'Timeline', position: 'outer-right' },
tick: {
format: '%Y-%m-%d'
}
},
y: {
type: 'bar',
label: {
text: 'Quantity / Price',
position: 'outer-middle'
}
},
y2: {
show: true,
label: {
text: 'Searches',
position: 'outer-middle'
}
}
},
tooltip: {
grouped: true,
contents: function(d, defaultTitleFormat, defaultValueFormat, color) {
var data = this.api.data.shown().map(function(series) {
var matchArr = series.values.filter(function(datum) {
return datum.value != undefined && datum.x === d[0].x;
});
if (matchArr.length > 0) {
matchArr[0].name = series.id;
return matchArr[0];
}
});
return this.getTooltipContent(data, defaultTitleFormat, defaultValueFormat, color);
}
}
});
1) If I got it right, you want tooltip to show all values, even if some of them are null.
Null values are hidden by default. You can replace them with zero (if it is suitable for your task) and thus make them visible.
Also, it seems to me that there is a shorter way to get grouped values:
var data = chart.internal.api.data().map(function(item) {
var row = item.values[d[0].index]; // get data for selected index
if (row.value === null) row.value = 0; // make null visible
return row;
});
2) I think you are talking about line.connectNull option:
line: {
connectNull: true
}
UPDATE
Looks like having duplicate keys breaks work of api.data() method.
You need to change json structure to make keys unique:
Before:
var json = [
{"x-axis":"2017-07-17","qty":100},
{"x-axis":"2017-07-17","price":111},
{"x-axis":"2017-07-17","searches":1},
{"x-axis":"2017-07-18","qty":200},
{"x-axis":"2017-07-18","price":222},
{"x-axis":"2017-07-18","searches":2}
];
After:
var json = [
{"x-axis":"2017-07-17","qty":100,"price":111,"searches":1},
{"x-axis":"2017-07-18","qty":200,"price":222,"searches":2}
];
See fiddle.

Can we add event listeners to "Vega-Lite" specification?

I am new to Vega and Vega-Lite. I am creating a simple bar chart using Vega-Lite but I am not able to add any event listeners e.g. "hover".
I want to hover a bar and change the color of the bar.
If you're using Vega-Embed, it returns a promise with a reference to the view which allows you to use addEventListener - explained in the docs here.
Here is an example:
const width = 600
const color = blue
embed(element, {
$schema: 'https://vega.github.io/schema/vega-lite/3.0.0-rc6.json',
data: { 'values': data },
mark: {
type: 'line',
color,
point: {
color,
}
},
width,
height: width / 2,
encoding: {
'x': {
field: 'label',
type: 'temporal',
},
'y': {
field: 'value',
type: 'quantitative',
},
}
}).then(({spec, view}) => {
view.addEventListener('mouseover', function (event, item) {
console.log(item.datum)
})
})

Handsontable change a column source

Is it possible to change the source in a Handsontable instance when inside an event?
Below is my code:
var container2 = $('#example2');
var hot2 = new Handsontable(container2, {
data: {},
minRows: 5,
colHeaders: ['Car', 'Year', 'Car Color'],
columns: [
{
type: 'autocomplete',
source: ['BMW', 'Chrysler', 'Nissan', 'Suzuki', 'Toyota', 'Volvo'],
strict: true,
allowInvalid: false
}, ,
{},
{
type: 'autocomplete',
source: ['yellow', 'red', 'orange', 'green', 'blue', 'gray', 'black', 'white', 'purple', 'lime', 'olive', 'cyan'],
strict: true,
allowInvalid: false
}]
});
Handsontable.hooks.add('afterChange', afterChangedCallback, hot2);
function afterChangedCallback(p) {
console.log(p);
if (p[0][1] == 0) {
alert('This means the first column has changed, I now want to update the colors here');
}
}
When a user selects a different car brand, I only want to populate the dropdown of "Car Color" with certain colors. Thus, not all car brands has the same colors.
EDIT
I updated the callback function to this based on the accepted answer:
function afterChanged(p) {
console.log(p);
if (p[0][1] == 0) {
hot2.updateSettings({
cells: function (row, col, prop) {
if (row == p[0][0] && col == 2) {
var cellProperties = {};
cellProperties.source = ['red', 'yellow', 'blue'];
return cellProperties;
}
}
});
}
}
Yup, you can use the updateSettings method to change the source of an entire column or particular cell. You probably want per-cell so I would do:
hot.updateSettings({
cells: newCellDefinitionFunction()
})
Of course this new definition is up to you to figure out. It could just be returning the same cellProperties each time but check on some global array for what sources to use for which cells.

Reading json with key:value in ext.store in sencha touch 2

I'm trying to load a particular json file into a listview; but sencha proxy doesn't seem to understand the key pairs of "CurrencyName" and "Value". I'm clueless on how to associate those two values into usable data.
Here's the json:
{
"timestamp": 1335294053,
"base": "USD",
"rates": {
"AED": 3.6732,
"AFN": 48.32,
"ALL": 106.040001
}
}
my store:
proxy: {
type: 'ajax',
url: 'http://localhost/CurrencyFX/latest.json',
reader: {
type: 'json',
rootProperty: 'rates'
}
},
my model:
Ext.define('CurrencyFX.model.Currency', {
extend: 'Ext.data.Model',
config: {
fields: [ 'name', 'value' ]
}
});
You'll need to write your own JSON reader subclass to make this work, as the data you are dealing with isn't an array.
Thankfully, doing this is fairly simple. Here is something that should do the job:
Ext.define('Ext.data.reader.Custom', {
extend: 'Ext.data.reader.Json',
alias : 'reader.custom',
getRoot: function(data) {
if (this.rootAccessor) {
data = this.rootAccessor.call(this, data);
}
var values = [],
name;
for (name in data) {
values.push({
name: name,
value: data[name]
});
}
return values;
}
});
Which will work with the following store configuration:
var store = Ext.create('Ext.data.Store', {
fields: ['name', 'value'],
autoLoad: true,
proxy: {
type: 'ajax',
url: '0000.json',
reader: {
type: 'custom',
rootProperty: 'rates'
}
}
});
Notice the reader type is now custom.
I tested this locally with your data and it seemed to work just fine.

Resources