In OpenLayers, I have a button (show), when I press on it, I got a layer on the map
My question: How can I show many layers consequently With a certain frame rate
(Something like a loop!)
to show a new/other layer every X seconds, use setInterval
let's assume that you somehow got an array of dates for which you have tiles, and a function displayLayerByDate(dateObject) that can show the layer.
function animatedLayers(arrayOfDates) {
let currentIdx = 0;
const handle = setInterval(function() {
const currentDate = arrayOfDates[currentIdx];
displayLayerByDate(dateObject);
}, 5000);
}
Related
I have 2 series (lines) displayed as shown in demo. I can have up to 30 series (lines) in one go.
What is implemented is, as soon as I move the mouse, it should update the current value (for all series (lines) - remember I can have up to 30 series in one go) in the grid shown right below stock chart. It is working as expected.
Pls find working demo : https://stackblitz.com/edit/react-ts-qcsum9?file=stockchart%2Fstockchart.js,constants%2Fzoom-level.js,stockchart%2FchartOptions.js
FYI: You can focus on only mouseOver function rather than looking in to all other files as demo has so many files.
Problem : Problem related to performance
As I told you I can have up to 30 series (lines) in one go. In given demo, there are two series(lines) and when you select 30 days, you have to move your mouse slowly in other to see updated or current hovered value in the gird. If you move your mouse speedily, it will not update the value immediately (I think that is obvious).
But the problem is on each mouse move, I'm looping through all available lines multiple times and perform some logic. I know it is a bit complex logic as shown in below code snippet. It runs every time when mouse is moved for each hovered point for all the lines. This is very bad way of updating the current value.
I know this is not the correct implementation but I really have NO IDEA how to optimize it. Any help would be greatly appreciated.
Code: Select all
point: {
events: {
mouseOver: (e) => {
const xAxisValue = e.target.x;
const chart = e.target.series.chart;
const series = chart.yAxis[0].series;
const totalGridSeries = [...stockGrid];
for (let i = 0; i < series.length; i++) {
const name = series[i].name || series[i].name;
const foundSeries = totalGridSeries.find(
(x) => x.name === name
);
if (foundSeries) {
if (xAxisValue) {
const foundPoint = series[i].points.find(
(t) => t.x === xAxisValue
);
if (foundPoint && foundPoint.y) {
foundSeries.currentValue = foundPoint.y;
} else {
foundSeries.currentValue = undefined;
}
} else {
foundSeries.currentValue = undefined;
}
}
}
setStockGrid(totalGridSeries);
},
},
}
I'm making a store bot and I ran into some SetInterval errors. I want to make it so each variable has the user's id so when I run a different command, it will know which interval to stop. (If that makes sense).
Here is my code:
if(message.content.startsWith(`!open`) {
var cashier1[message.author.id] = function () {
BalanceJSON[message.author.id].bal += 10
Fs.writeFileSync(`./DB/balance.json`, JSON.stringify(BalanceJSON));
}
setInterval(cashier1[message.author.id], 5000);
}
All this code is in a bot.on('message', message => { })
I wanna be able to stop an certain player's interval with clearInterval(cashier1[message.author.id])
The function setInterval returns a unique id which can be used to clear the interval again (See the example for more information).
The solution to your problem is to store the unique id of the interval in some object or database and use that to clear the interval again. See the example code below:
// Create an object to store the intervals.
const cashierIntervals = {};
// Inside your message handler.
// Some dummy if statement for demonstration purpose.
if (message.content === 'setInterval') {
// Create the setInterval and store the unique id in the cashier intervals object.
// You should probably add more checks to see if there is already an interval stored for this author id etc.
cashierIntervals[message.author.id] = setInterval(() => {
BalanceJSON[message.author.id].bal += 10;
Fs.writeFileSync(`./DB/balance.json`, JSON.stringify(BalanceJSON));
}, 5000);
} else if (message.content === 'clearInterval') {
// Clear the interval based on the author id.
// Again, probably add more checks to see if the author id has an interval stored etc.
clearInterval(cashierIntervals[message.author.id]);
// Delete the stored interval entry from the global intervals object.
// Not necessary but it keeps the intervals object small.
delete cashierIntervals[message.author.id];
}
Create an object that takes an id as a key. Your value will be the function you want to interval
Your main file:
const cashier1 = {
// Template for your key:values
'999999999': yourRepeatingFunction(),
}
// Lets say message.author.id returns '999999999'
// Doing setInterval(cashier1[message.author.id], 5000) Will call yourRepeatingFunction()
I have an AngularJs app. in a single controller, i have to pull data from 3 different source and display the data in 3 different sections. (in top , mid and bottom section). data in each section would vary in a set delay. for top section, i have used Set interval and clear interval. for mid and bottom section , i have used $interval.For mid section, the delay is set to 7 and for bottom section, it is set to 10 sec.
when i launch the application, everything works fine. but with time, the mid and bottom section varies in every 2 or 3 seconds instead of 7 and 10 respectively. i dont know where i am doing the mistake. i have not added $interval.cancel as i want the mid and bottom section to bring the data in 7 and 10 sec delay continuously without stopping. i am also using socket to bring the data for all the sections. I have not used $scope.on'Destory' . i don't if that has any impact here. below is the code. Any help would be greatly appreciated.
socket.on('midsection', function (data) {
tableJson = [];
SplicedJson = [];
jsoninput = [];
jsoninput.push(data);
// splitting single array in to two array's so that we can display them one after the other after some delay
SplicedJson.push(jsoninput[0].splice(0, 6));
tableJson.push(jsoninput[0]);
$scope.tableData = tableJson;
//Creating interval and setting counter just to swap the json source for display
var Counter = 1;
$interval(function () {
Counter++;
if (Counter % 2 === 0) {
$scope.tableData = SplicedJson;
}
else {
$scope.tableData = tableJson;
}
}, 7000);
});
socket.on('lastSection', function (data) {
if (data.length > 3) {
array1.push(data[0]["publisher"]);
array1.push(data[1]["publisher"]);
array1.push(data[2]["publisher"]);
array2.push(data[0]["title"]);
array2.push(data[1]["title"]);
array2.push(data[2]["title"]);
$scope.msg = array1;
$scope.msg2 = array2;
$interval(function () {
data = shuffle(data); // caling custom built shuffle fn to shuffle the data to display random data everytime
console.log('Shuffled', data);
array1= [];
array2= [];
array1.push(data[0]["publisher"]);
array1.push(data[1]["publisher"]);
array1.push(data[2]["publisher"]);
array2.push(data[0]["title"]);
array2.push(data[1]["title"]);
array2.push(data[2]["title"]);
$scope.msg = array1;
$scope.msg2 = array2;
},10000);
}
});
Code # connection launch is below
io.on('connection', function (socket) {
socket.join(socket.handshake.query.room)
var entExFilepath = './midsectionData.json';
var parsedJSON = JSON.parse(fs.readFileSync(entExFilepath, 'utf8'));
fs.watchFile(entExFilepath, function () {
parsedJSON = JSON.parse(fs.readFileSync(entExFilepath, 'utf8'));
io.sockets.emit('midsection', parsedJSON);
});
io.sockets.emit('midsection', parsedJSON);
if (feedresults.length > 3) {
io.sockets.emit('lastsection', feedresults);
}
I found the cause for this issue. the problem was when i send the data for mid and last section, i was doing socket.emit which was equivalent to broadcasting the answer to all the clients.So Whenever a new request comes to the server, socket.emit was being called and sent the data to the client. (which means it also calls the internal block when ever a new request comes. so the interval is called again and again).I should have done like below. This resolved the issue.
//io.sockets.emit('lastsection', feedresults);
io.sockets.in(socket.handshake.query.room).emit('lastsection', feedresults);// This should send the data to the current client
Hope this helps others
I have an angularjs app using ui.grid with the infinite scrolling module. I am using whole row filtering as described in the documentation like so:
function MyController($scope){
var that = this;
var getData = function(){
//logic left out for brevity
};
var onRegisterApi = function(gridApi){
gridApi.grid.registerRowsProcessor(function (rows) {
return that.filterRowProcessor.apply(that, [rows]);
}, 200);
gridApi.infiniteScroll.on.needLoadMoreData($scope, getData);
};
this.options["onRegisterApi"] = onRegisterApi;
}
//...code excluded for brevity...
MyController.prototype.filterRowProcessor = function(renderableRows){
renderableRows.forEach(function(row) {
if (this.selectedMap[row.entity["Id"]]) {
row.visible = false;
}
});
return renderableRows;
}
The idea is to filter out rows which have an Id belonging to a specific collection; which works as designed. My problem is that when I get my first page of data the filter row processor removes enough rows from visibility that my scroll bar disappears. This in turn causes the infinite scroll api to never raise the "needLoadMoreData" event.
Is this uncharted territory, or is there a way around this? I am also open to not filtering by that mechanism if its easier to do another way.
UPDATE (01/08/2016)
I have found a work around that I don't like very much. Essentially I have a known page size and if the data coming in to the grid is less than that page size and my callback returns false for "end of query", I automatically issue a next page query. I would rather find a solution via the grid api, but for now this will work.
if(this.itemsSource.data.length < constants.PAGE_SIZE && !continuation.endOfQuery){
//call get data again
}
After thinking about it for a while I decided on the below method as my solution. I am still open to suggestions if it makes more sense to do it a different way. Rather than relying on a length of data (which only loosely translates to having a scroll bar) I decided to calculate the height of the total rows visible, compared to the viewport of the grid.
//this method get called from the callback from needsMoreData
//hasMoreData is the same boolean flag sent in to dataLoaded
var shouldRetrieveMore = function (gridApi, hasMoreData){
if (!hasMoreData) {
return false;
}
var totalCountOfRows = gridApi.grid.getVisibleRowCount();
if (totalCountOfRows === 0) {
return true;
}
var height = gridApi.grid.getViewportHeight();
var heightOfRow = gridApi.grid.getVisibleRows()[0].$$height;
return ((heightOfRow * totalCountOfRows) <= height);
}
One additional addendum to the solution could be to sum the $$heights of all the rows, but I decided against it since in my uses they are always the same height.
I have a Gridview on my page and I'm using buffered store. Is there a way to get the visible number of row count. Thank you
Here is a sample code that you can try: (I hope you'll get some idea from this)
// The below condition has to be checked for each record
// record: record instance
var me = this; // grid scope
Ext.Array.each(me.columns, function (item) { // iterate through each column in the grid
if (item.hidden || !item.dataIndex) { // you can avoid hidden columns and one's that re not bound to the store
return;
}
var cellVal;
try {
cellVal = Ext.fly( me.view.getCell(record, item)).select('cell selector class').elements[0].innerHTML;
} catch (e) {
// handle if you want
}
if (!Ext.isEmpty(cellVal)) {
// this record has been rendered
}
}, this);
This will get you all the records that are rendered. Since you are using a bufferedRenderer, this will also return the records that are rendered but not in the view, you can check and put an offset for the buffer.
Note: I've a similar logic in working in ExtJs 5 but haven't tested in touch.