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);
},
},
}
Related
I have tried time and time again to utilize this same script & formatting to try to also get the "lost" checkbox to move to the "lost" tab (on the same script) and I've been at a loss. Any help on how to get two identical actions/scripts to work simultaneously? My current script allows the checkbox for "sold" to go in a "sold" tab, and i need the same for "lost" if that makes sense.
function onEdit(e) {
let sheet;
if (e.range.columnStart !== 9
|| e.range.rowStart === 2
|| !(sheet = e.range.getSheet()).getName().match(/^(Cynthia|Jenni|Kelsi|Monte)$/i)) {
return;
};
const targetSheet = SpreadsheetApp.getActive().getSheetByName('Sold');
const targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet.getRange(e.range.rowStart, 1, 1, 8).moveTo(targetRange);
sheet.deleteRow(e.range.rowStart);
}
I think you should try changing
!(sheet = e.range.getSheet()).getName().match(/^(Cynthia|Jenni|Kelsi|Monte)$/i)
into
!(sheet === e.range.getSheet()).getName().match(/^(Cynthia|Jenni|Kelsi|Monte)$/i)
I'm working on a sheet to build a list of products to import into Shopify.
For this, I have a pdf of some basic data (that is irrelevant here) out of which I build a string to crawl the product supplier's website and format the data in a way suitable for import in Shopify.
The products have a varying number of images (1 - 8), so I'm trying to build my script in a way that if a product has more than one image, I am trying to add additional rows under it and add every image past the first into a new row.
Here is my code:
function iterateThroughRows() {
// get spreadsheet
const sheet = SpreadsheetApp.getActive().getSheetByName("MySheet");
const data = sheet.getDataRange().getValues();
// Loop over rows
data.forEach( (row, rowIndex) => {
const imageSrcArray = [ /* list of image URLs, fetched from remote server */ ]
imageSrcArray.forEach( (img, arrayIndex) => {
if(arrayIndex == 0) { // for the first array item, just add it to the current row
const imageCell = sheet.getRange(rowIndex + 1, 24)
imageCell.setValue( imageSrcArray[arrayIndex] )
} else { // for each array item past the first one, add a new row and enter the value there
sheet.insertRows(rowIndex)
const imageCell = sheet.getRange(rowIndex + arrayIndex + 1, 24)
imageCell.setValue( imageSrcArray[arrayIndex] )
}
})
// adding some more values to other cells
});
}
As is this doesn't really work.
I worked on this all day yesterday and had a version using insertRowAfter() that did add additional rows, but added them all lumped together (i.e. there would be 15 rows after the first product, but none after any of the others). But since Google App Script doesn't have version control I lost that version.
I think the problem was that the forEach seems to move on to the newly created rows and keeps adding things from there rather than moving on to the initial next row.
So I'm more or less at the end of my wit with this. Any advise on how to properly do this would be highly appreciated.
I can understand your frustration, it is indeed because you care calculating the row based on the sheet in its version before you added new rows to it.
So my proposal would be to do this, as the currentRow allows you to track the current row you are working on. I also updated the insertRowAfter(), as I assume this is what you actually wanted to do.
let currentRow = 1;
data.forEach( (row, rowIndex) => {
const imageSrcArray = [ "img1URL", "img2URL"]
if( !imageSrcArray.length ) return
imageSrcArray.forEach( (img, arrayIndex) => {
if( arrayIndex == 0 ){
sheet.getRange(currentRow, 24).setValue( img )
} else {
sheet.insertRowAfter(currentRow)
sheet.getRange(currentRow+1, 24).setValue( img )
}
// New rows in between were created
currentRow++
})
});
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);
}
I am trying to perform a Drag and Drop operation on our Angular application using Protractor Jasmine. I am able to get hold of the source item but as the test runs, the source element gets selected but nothing happens thereafter; the drag and drop operation does not take place. There are no errors shown in the console.
An interesting thing about the destination container is that the items dropped here can be resized as per user wish. Also, there is no clearly marked place/area in the destination container where the dragged item will get dropped! But the container does have an ID; though that has still not helped here.
Here is the code:
let dragAndDrop = require('html-dnd').code;
.
.
.
function dragAndDropListItems(fdIndex: number): void {
let dragElement = element.all(by.repeater('listDefinition in lists')).get(fdIndex); // Select the first repeater corresponding to the first List Item in the list
let dragElementh5 = dragElement.all(by.css('a')).get(0); // Select the first List Item
let printFD = dragElementh5.getText().then((text: string) => {
console.log(text); // Print the innerHTML text from the chosen List Item to the Console
});
let finalDrop = element.all(by.css('[id="dashboardContainerDiv"]')).get(0);
dragElement.click();
browser.actions().dragAndDrop(dragElement, finalDrop).perform();
};
I have tried using coordinate based DragNDrop operation as well but the same in every case.
Other tried options include:
//browser.executeScript(dragAndDrop, dragElement, finalDrop); // Perform the drag and drop operation
//browser.driver.actions().dragAndDrop(dragElement, finalDrop).perform();
//browser.actions().dragAndDrop(dragElement, { x: 400, y: 400 }).perform();
// browser.driver.actions().mouseDown(dragElement).mouseMove(finalDrop).mouseUp(finalDrop).perform();
Kindly suggest a solution to this issue.
#FlorentB. I have attached the Code with your scripts imported.
let JS_DRAG_DROP = require('./drag-drop.js');
function dragAndDropListItems(fdIndex: number): void {
/*
let source = driver.find_element_by_css_selector("#drag")
target = driver.find_element_by_css_selector("#drop")
driver.execute_async_script(JS_DRAG_DROP, source, target)
# drag and drop an element by offset {x:500, y:200}
source = driver.find_element_by_css_selector("#drag")
driver.execute_async_script(JS_DRAG_DROP, source, None, 500, 200)
# drag and drop an element with a delay of 101ms before the drop
source = driver.find_element_by_css_selector("#drag")
target = driver.find_element_by_css_selector("#drop")
driver.execute_async_script(JS_DRAG_DROP, source, target, 0, 0, 101)
*/
let source = element.all(by.repeater('listDefinition in
lists')).get(fdIndex); // Select the first repeater corresponding to the
first List Item in the list
let dragElementh5 = source.all(by.css('a')).get(0); // Select the first List
Item
let printFD = dragElementh5.getText().then((text: string) => {
console.log(text); // Print the innerHTML text from the chosen List Item
to the Console
});
//browser.driver.switchTo().frame('dashboardContainerDiv');
/*
let finalDropClass = element.all(by.css('[class="dashboard mb10"]')).get(0);
let finalDropCon =
finalDropClass.all(by.css('[id="dashboardContainerDiv"]')).get(0);
let finalDrop =
finalDropCon.all(by.css('[id="dashboardContainerUl"]')).get(0);
*/
let target = element.all(by.css('[id="dashboardContainerDiv"]')).get(0);
//dragElement.click();
browser.executeScript(JS_DRAG_DROP, source, target); // Perform the drag and
drop operation
//browser.actions().dragAndDrop(dragElement, finalDrop).perform();
//browser.driver.actions().dragAndDrop(dragElement, finalDrop).perform();
//browser.actions().dragAndDrop(dragElement, { x: 400, y: 400 }).perform();
// browser.driver.actions().mouseDown(dragElement).mouseMove(finalDrop).mouseUp(finalDrop).perform();
};
Try
https://github.com/html-dnd/html-dnd
Installing it and using the typescript example worked for me.
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.