Getting undefined when selecting html element in Javascript - select

I have a number of tv display clones loaded onto my page. After the clone is made, it will create a new TV object at the end of the loop definition, but for some reason, when it tries to access the index based canvas element from the page, it returns undefined. I tested that when hardcoding cnvs[0] from inside the constructor, it will return the canvas element. Indexing cnvs1 will return undefined; however, I see the tv has already been cloned before this line is executed. Shouldn't there then be a second canvas element of class ".static" that can be selected? In addition to the code, I attached a screenshot of my debugger screen in Chrome to see what the scope reads following "this.cnv = cnvs1", which should dynamically be cnvs[this.index]. Thanks in advance!
const container = document.getElementsByTagName("main")[0];
const template = document.getElementsByClassName("tv-set")
const cnvs = $(".static");
/**TBD**/
class TV {
constructor (id = "tv-0", name = "Blank Slate") {
this.id = id;
this.name = name;
console.log("NEW TV CREATED: ", this);
console.log("ID: ", this.id);
this.gifArr = gifCarousel_dict[this.name];
console.log("Media selection for this tv: ", this.gifArr);
// this.cnv = $(this.id).find('.static')[0];
// this.cnv = document.querySelector("[data-name=" + CSS.escape(this.id) + "]");
this.index = getSecondPart(id);
// this.cnv = $(".static")[this.index + 1];
this.cnv = cnvs[1];
console.log(this.cnv);
this.cnv.setAttribute("c", this.cnv.getContext("2d"));
this.cnv.setAttribute("cw", this.cnv.offsetWidth);
this.cnv.setAttribute("ch", this.cnv.offsetHeight);
this.staticScrn = this.cnv.getAttribute("c").createImageData(this.cnv.setAttribute("ch"), this.cnv.setAttribute("cw"));
console.log("This canvas element: ", this.cnv);
//Static display
this.isStatic = true;
}
showStatic() {
console.log(`Printing the tv name from the prototype fxn: ${this.name}`);
// this.isStatic = true;
c.clearRect(0, 0, cw, ch);
for (var i = 0; i < staticScrn.data.length; i += 4) {
let shade = 127 + Math.round(Math.random() * 128);
staticScrn.data[0 + i] = shade;
staticScrn.data[1 + i] = shade;
staticScrn.data[2 + i] = shade;
staticScrn.data[3 + i] = 255;
}
c.putImageData(staticScrn, 0, 0);
staticTO = setTimeout(runStatic, 1e3 / staticFPS);
}
}
for (let i = 0; i < phases.length; i++) {
const clone = template[i].cloneNode(true);
clone.setAttribute("id", "tv-" + (i + 1))
console.log("clone id: ", clone.getAttribute("id"))
clone.setAttribute("data-channel", 0)
clone.setAttribute("name", phases[i])
// clone.style.backgroundColor = phases[i].channels[0]
container.appendChild(clone)
var tvName = 'tvPhase' + clone.getAttribute("name");
//Instantiate TV object
window['tvPhase' + clone.getAttribute("name")] = new TV(clone.getAttribute("id"), clone.getAttribute("name"));
console.log("New Tv Created: ", tvName)
}

As I was about to post this question, I caught my bug...but I figured perhaps someone could learn from my stupid mistake! Turns out, it was because of line const cnvs = $(".static"); Setting this constant prior to the cloning operation means it will contain only the first canvas element and cannot be changed even after clones are created since it's a constant (face palm). The solution, of course, is to just define this.cnv = $(".static")[this.index]; directly or set the global cnvs as a var/let cnvs, still wrapping my head around when to use which.

Related

Getting the cell given the cell value in google sheets using app script

I'm trying to write a script that tracks payment dates in google sheets (shows a different colour (either FontColor or Background) three days before payment, another colour on the day of payment and a totally different colour after the payment date.I'd appreciate if there's anyone with know how on how to use those values to get the cell name and use it to change the FontColor or alternatively if there's a better solution
Here is my google sheet
[![enter image description here][1]][1]
This is the code I've written to get the dates into a list
function myFunction() {
let spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
let lastRow = spreadsheet.getLastRow();
let lastCol = spreadsheet.getLastColumn();
var dataRange = spreadsheet.getActiveSheet().getRange(2, 11, lastRow, lastCol)
dataRange.setFontColor("green")
var data = dataRange.getDisplayValues();
let dates=[];
for (let i=0; i < dates.length; i++ ) {
// console.log(dates[i])
if (dates[i] === new Date().toLocaleDateString()) {
dataRange.setBackground('pink')
} else if (dates[i]) {
// do sth
} else {
// maintain the current state
}
}
}
Does it need to be with scripts?? With conditional formatting that would be MUCH faster, easier and uploads constantly.
You can apply it to the entire sheet or to a specific range. Use this custom formula (change A1 with the top left formula of your range)
=if(A1="",FALSE,(A1 - Today()) < 0)
Get sure to set these conditions in the correct order (in these case it would be preferrable to be the past dates, the actual date and the close future dates). Like this:
Here you have a link to play with:
https://docs.google.com/spreadsheets/d/1zhEFRQwOyAYQwXfv5lYTjI7B-6fIfz1rgdCt3MGvzmI/edit?usp=sharing
Payment Tracker
function paymentTracker() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getActiveSheet();
const rg = sh.getRange(2, 11, sh.getLastRow() - 1, sh.getLastColumn() - 10);
rg.setFontColor("black")
const vs = rg.getDisplayValues();
const d = new Date();
//Logger.log('y: %s,m: %s,d: %s', d.getFullYear(), d.getMonth(), d.getDate());
const dt = new Date(d.getFullYear(), d.getMonth(), d.getDate());
const dtv = dt.valueOf();
const dt3 = new Date(d.getFullYear(), d.getMonth(), d.getDate() + 3);
const dt3v = dt3.valueOf();
vs.forEach((r, i) => {
let ds = r.map(ds => {
let t = ds.split('/');
//Logger.log(JSON.stringify(t))
let v = new Date(Number(t[2]), Number(t[1]) - 1, Number(t[0])).valueOf();
let diff3 = dt3v - v;
if (dt3v == v) {
return "purple";
} else if (dtv == v) {
return "green";
} else {
return "pink";
}
});
sh.getRange(i + 2, 11, 1, ds.length).setBackgrounds([ds]);
})
}

How to remove L.rectangle(boxes[i])

I few days ago I implement a routingControl = L.Routing.control({...}) which works perfect for my needs. However I need for one of my customer also the RouteBoxer which I was also able to implement it. Now following my code I wants to remove the boxes from my map in order to draw new ones. However after 2 days trying to find a solution I've given up.
wideroad is a param that comes from a dropdown list 10,20,30 km etc.
function routeBoxer(wideroad) {
this.route = [];
this.waypoints = []; //Array for drawBoxes
this.wideroad = parseInt(wideroad); //Distance in km
this.routeArray = routingControl.getWaypoints();
for (var i=0; i<routeArray.length; i++) {
waypoints.push(routeArray[i].latLng.lng + ',' + routeArray[i].latLng.lat);
}
this.route = loadRoute(waypoints, this.drawRoute);
}; //End routeBoxer()
drawroute = function (route) {
route = new L.Polyline(L.PolylineUtil.decode(route)); // OSRM polyline decoding
boxes = L.RouteBoxer.box(route, this.wideroad);
var bounds = new L.LatLngBounds([]);
for (var i = 0; i < boxes.length; i++) {
**L.rectangle(boxes[i], {color: "#ff7800", weight: 1}).addTo(this.map);**
bounds.extend(boxes[i]);
}
console.log('drawRoute:',boxes);
this.map.fitBounds(bounds);
return route;
}; //End drawRoute()
loadRoute = function (waypoints) {
var url = '//router.project-osrm.org/route/v1/driving/';
var _this = this;
url += waypoints.join(';');
var jqxhr = $.ajax({
url: url,
data: {
overview: 'full',
steps: false,
//compression: false,
alternatives: false
},
dataType: 'json'
})
.done(function(data) {
_this.drawRoute(data.routes[0].geometry);
//console.log("loadRoute.done:",data);
})
.fail(function(data) {
//console.log("loadRoute.fail:",data);
});
}; //End loadRoute()
Well, my problem is now how to remove previously drawn boxes in order to draw new ones because of changing the wideroad using a dropdown list. Most of this code I got from the leaflet-routeboxer application.
Thanks in advance for your help...
You have to keep a reference to the rectangles so you can manipulate them (remove them) later. Note that neither Leaflet nor Leaflet-routeboxer will do this for you.
e.g.:
if (this._currentlyDisplayedRectangles) {
for (var i = 0; i < this._currentlyDisplayedRectangles.length; i++) {
this._currentlyDisplayedRectangles[i].remove();
}
} else {
this._currentlyDisplayedRectangles = [];
}
for (var i = 0; i < boxes.length; i++) {
var displayedRectangle = L.rectangle(boxes[i], {color: "#ff7800", weight: 1}).addTo(this.map);
bounds.extend(boxes[i]);
this._currentlyDisplayedRectangles.push(displayedRectangle);
}
If you don't store a reference to the L.rectangle() instance, you obviously won't be able to manipulate it later. This applies to other Leaflet layers as well - not storing explicit references to Leaflet layers is a usual pattern in Leaflet examples.

syncfusion chart background line will be dotted line

I want my chart backgroud line will be dotted. Which property can i use for dotted in syncfusion? I tried but i coudn't do this. I don't know exactly which propertly will use for dotted line.
Here is my code:
control.AutoTempFileCleanUp = true;
control.OutputFormat = ImageProviderOutputFormat.DiskFile;
control.Model.Series.Clear();
ChartModel chartModel = new ChartModel();
ChartSeries chart = new ChartSeries(yAxisBar1LegendName, ChartSeriesType.Column);
chart.Text = yAxisBar1LegendName;
control.ChartArea.PrimaryXAxis.TickLabelsDrawingMode = ChartAxisTickLabelDrawingMode.UserMode;
// = string.Format("");
control.ChartArea.PrimaryXAxis.Labels.Add(new ChartAxisLabel("", Color.Black, new Font("Arial", 10), 0, "", ChartValueType.Custom));
int counter = 1;
DoubleRange dr = new DoubleRange(1, 100);
foreach (DataRow row in ds.Tables[0].Rows)
{
double bar1Value = Convert.ToDouble(row[yAxisValueColumn1]);
chart.Points.Add(counter, bar1Value);
control.ChartArea.PrimaryXAxis.Labels.Add(new ChartAxisLabel(row["ModuleCode"].ToString(), Color.Black, new Font("Arial", 10), counter, "", ChartValueType.Custom));
counter++;
}
chart.PrepareStyle += new ChartPrepareStyleInfoHandler(series_PrepareStyle);
control.ChartArea.PrimaryXAxis.DrawGrid = false;
control.PrimaryXAxis.GridLineType.ForeColor = Color.DarkGray;
control.PrimaryYAxis.GridLineType.ForeColor = Color.DarkGray;
control.PrimaryXAxis.LineType.ForeColor = Color.DarkGray;
control.PrimaryYAxis.LineType.ForeColor = Color.DarkGray;
control.Text = chartHeader;
control.ChartArea.PrimaryYAxis.Title = yAxisText;
control.ChartArea.PrimaryXAxis.Title = xAxisText;
control.ChartArea.PrimaryXAxis.TitleAlignment = StringAlignment.Center;
control.ChartArea.PrimaryXAxis.IsVisible = true;
control.ChartArea.PrimaryXAxis.LabelAlignment = StringAlignment.Center;
control.ChartArea.PrimaryXAxis.VisibleRange.Min = 0;
control.ChartArea.PrimaryXAxis.VisibleRange.Max = counter;
control.ChartArea.PrimaryXAxis.VisibleRange.Interval = 1;
control.ChartArea.PrimaryYAxis.EdgeLabelsDrawingMode = ChartAxisEdgeLabelsDrawingMode.Center;
control.ChartArea.PrimaryYAxis.GridDrawMode = ChartAxisGridDrawingMode.Default;
//control.PrimaryXAxis.EdgeLabelsDrawingMode = ChartAxisEdgeLabelsDrawingMode.Center;
control.PrimaryXAxis.Font = new Font("Arial", 10F);
control.PrimaryYAxis.Font = new Font("Arial", 10F);
counter = 0;
foreach (ChartSeries series in control.Series)
{
Color color;
if (counter == 0)
{
color = Color.Green;
else
{
color = Color.Red;
}
series.Style.Interior = new BrushInfo(color);
series.Style.Border.Color = Color.DarkGray;
series.Style.Font.Bold = true;
series.Style.TextColor = Color.Black;
series.Style.TextOrientation = ChartTextOrientation.Left;
series.Style.TextFormat = "{0}";
counter++;
}
control.Width = 650;
control.Series3D = false;
control.ShowLegend = false;
control.BorderStyle = BorderStyle.None;
control.BorderAppearance.SkinStyle = ChartBorderSkinStyle.None;
//control.Legend.Alignment = ChartAlignment.Far;
}
Here is my chart image:
Thanks for using syncfusion products.
We have analyzed your query. If you want to customize the grid lines in axis, then you can use the “DashStyle” property in GridLineType which property is used to change the line style. And you can also specify the grid line style as Dash, DashDot, DashDotDot, Dot, Solid in axis.
And please find the below code snippet
this.ChartWebControl1.PrimaryYAxis.GridLineType.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot;
And we have also prepared a sample for your reference in ASP.NET classic platform and attached in the below location.
Sample Link : http://www.syncfusion.com/downloads/support/directtrac/160606/ze/Sample1273790903
Please find the output of the sample below:
And also we wish to let you know that the above mentioned property is also applicable for chart control in windows forms, ASP.NET classic and ASP.NET MVC classic platforms.
Please contact us via syncfusion support, if you have any queries related to using syncfusion products.

Removing items from leaflet markercluster

I have two functions that load markers into my map. (Both functions are called on success of an ajax call)
First Function is like this:
function loadEpsMarkers(data) {
for (var i = 0; i < data.length; i++) {
var plateNo = data[i].PLATE_NUMBER;
var permitNo = data[i].PERMITINFOID;
var inventoryId = data[i].INVENTORY_ID;
var icon = epsiconR;
if (data[i].INVENTORY_STATUS === 'Complete') {
icon = epsiconC;
}
var popup = '<h5>EPS</h5>' + 'Plate:' + plateNo + '<br/>' +
' Permit: <a class=\'link\' data-inventoryId="' + inventoryId + '" href=' + url + '>' + permitNo + '</a>' +
'<p style=\"color:blue\">' + '' + '<a class=\'link\' href=' + url + '>' +
'Import' + '</a>' + '<br/>' + '<a class=\'link\' href=' + url + '>' +
'Duplicate' + '</a>' + '<br/>' + '<a class=\'link\' href=' + url + '>' +
'Removed' + '</a>' + '<br/>' + '</p>';
var m = L.marker([data[i].REF_LATITUDE, data[i].REF_LONGITUDE], { icon: icon, draggable: 'true' })
.bindPopup(popup);
markerClusters.addLayer(m);
}
map.addLayer(markerClusters);
map.invalidateSize(false);
}
The second Function is same except the data is different.
This works fine and I get the clustered markers as expected.
Now I have a button, when I click this button, it should hide the markers from the first call.
The easy way out is to remove layers and then redo just the second call. But that seems like an inefficient way of doing this.
This gets more complex if I have 4 such data calls and I want to toggle markers from each of those calls.
I have tried something like this as well:
$('#dvEpsOnlyMarkers').click(function () {
markerClusters.removeLayer(m);
});
But that isn't working. Any ideas on how I can make this work ?
Thanks in advance
A very simple way of achieving what you describe is to store references to markers of each group in arrays, and manipulate those arrays to add / remove the layers into MCG:
var markersCall1 = [],
markersCall2 = [],
markersCall3 = [],
markersCall4 = [];
function loadEpsMarkersX(data) { // Replace X by 1...4
for (var i = 0; i < data.length; i++) {
// Convert data...
var m = L.marker(/* latLng, options, popup... */);
markersCallX.push(m); // Replace X by 1...4
}
// Actually add to MarkerClusterGroup.
// Replace X by 1...4
markerClusters.addLayers(markersCallX); // note the addLayers with "s".
}
$('#dvEpsOnlyMarkersX').click(function (event) { // Replace X by 1...4
// Assuming it is a checkbox, you can use it to toggle.
if (this.checked) {
// Replace X by 1...4
markerClusters.addLayers(markersCallX); // note the "s".
} else {
// Replace X by 1...4
markerClusters.removeLayers(markersCallX); // note the "s".
}
});
When you have batches of markers to add / remove like in your case, you can conveniently use the MarkerClusterGroup methods addLayers and removeLayers (with a trailing s) with an array of the markers to process. These methods are much more efficient than adding / removing markers one by one.

Titanium Appcelerator iPhone App - App crashes when the table view is scrolled close to 1000th record and slows down when it starts scrolling

We have a sample app that loads 10 records each from the db and shows in a table vioew. The next ten records are taken when the scroll reaches the bottom (like the sample of dynamic scroll view in kitchen sink and following the same sample code). However the app scrolling becomes slower and slower when the no of records increases and then crashes when we were showing close to 1000th record. We have even more records to show (10000) and all the rows shows an 50X50 image and two texts.
if (search.value != null && search.value != ''){
dbrows = db.execute('select id, name, scientificname from siteRecords where name like \'%' + search.value + '%\' order by commonname limit 10 offset ' + lastRow);
}else{
dbrows = db.execute('select id, name, scientificname from siteRecords order by name limit 10 offset ' + lastRow);
}
tsEnd = new Date;
var duration = tsBegin.getTime() - tsEnd.getTime();
perfTableView.appendRow({title:"To fetch the record from 0 to " + (lastRow + 20) + " took: " + duration + " ms"});
tsBegin = new Date;
var rowCount = 0;
while (dbrows.isValidRow()) {
var row;
if( dbrows.fieldByName('name')[0] != curheader || initHeader == 0){
initHeader = 1;
curheader = dbrows.fieldByName('name')[0];
row = Ti.UI.createTableViewRow({height:55,backgroundColor:'#ffffff',backgroundSelectedColor:'#eeee33',hasChild:true,className:'birds',header:curheader});
index.push({title:curheader,index:rowNumber });
} else {
row = Ti.UI.createTableViewRow({height:55,backgroundColor:'#ffffff',backgroundSelectedColor:'#eeee33',hasChild:true,className:'birds'});
}
var lblBirdID = Ti.UI.createLabel({
text: dbrows.fieldByName('id'),
color: '#000000',
textAlign:'left',
left:4,
top:8,
height:100,
font:{fontWeight:'bold',fontSize:10},
visible:false
});
row.add(lblBirdID);
media = dbrows.fieldByName('scientificname').replace(' ', '_') + '.jpg';
var path = Titanium.Filesystem.resourcesDirectory + 'Birds/images/'
if (Titanium.Filesystem.getFile(path,media).exists())
{
var f;
if (isAndroid){
f = '../images/' + media;
}else{
f = Ti.Filesystem.getFile(Titanium.Filesystem.resourcesDirectory,'Birds/images/' + media);
}
var imgBird = Ti.UI.createImageView({
image:f,
left:4,
height:50,
width:50
});
row.add(imgBird);
}else{
var f;
if (isAndroid){
f = '../images/no_bird.jpg';
}else{
f = f = Ti.Filesystem.getFile(Titanium.Filesystem.resourcesDirectory,'Birds/images/no_bird.jpg');
}
var imgBird = Ti.UI.createImageView({
image:f,
left:4,
height:50,
width:50
});
row.add(imgBird);
}
var lblBirdName = Ti.UI.createLabel({
text: dbrows.fieldByName('name'),
color: '#000000',
textAlign:'left',
left:60,
top:8,
height:20,
font:{fontWeight:'bold',fontSize:16}
});
row.add(lblBirdName);
var lblBirdScientificName = Ti.UI.createLabel({
text: dbrows.fieldByName('scientificname'),
color: '#000000',
textAlign:'left',
left:60,
top:26,
height:20,
font:{fontSize:11}
});
row.add(lblBirdScientificName);
birdRows[rowNumber] = row;
rowCount = rowCount + 1;
rowNumber = rowNumber + 1;
dbrows.next();
}
dbrows.close();
db.close();
if (rowCount == 20){
lastRow = lastRow + 20;
}else{
lastRow = lastRow + rowCount;
}
birdTableView.setData(birdRows);
birdTableView.index = index;
tsEnd = new Date;
duration = tsBegin.getTime() - tsEnd.getTime();
perfTableView.appendRow({title:"To loop through the DB rows and to create table rows took: " + duration + " ms"});
}
Have you tried unloading items at the top, as items are added to the bottom (and vice versa)? Doing something like this would mean there are never more than say 100 rows at any one time.
Also, if possible, use a standard row instead of a custom row. A standard row is MUCH more performant than a custom one.