Interactive canvas vs render table in html. Which way is faster? - javascript

Which way will be faster and use less memory?
For now i have rendered dynamic <table> by jQuery. Sometimes it has around few thousand cells and it is working so slowly when i do events on it. Html2Canvas is taking alot time to render this table as image. So i wonder about use interactive canvas.
Here is fiddle with script for generating table http://fiddle.jshell.net/j6G66/

I created two examples,
One that mirrors the way you're creating your table
and that's by creating and appending jQuery object elements on every loop iteration:
function createDynamicTable(rows, cols) {
var table = $('<table />');
for(var i=0; i<rows; i++){ // noprotect
var row = $('<tr />');
for(var j=0; j<cols; j++){
var cell = $('<td />');
cell.text("R"+i+"-C"+j);
cell.appendTo( row ); // Appends here....
}
row.appendTo( table ); // Appends here....
}
$('#tableContainer').append( table ); // Appends here....
}
The second one uses a different way of creating a table, that is based instead on the principle of
concatenating a HTML String representation of the needed elements:
function createDynamicTable(rows, cols) {
var table = "<table>";
for(var i=0; i<rows; i++){
var row = "<tr>";
for(var j=0; j<cols; j++){
var cell = "<td>R"+i+"-C"+j+"</td>";
row += cell;
}
row += "</tr>";
table += row;
}
table += "</table>"
$('#tableContainer').append( table ); // Append only once!
}
Now let's be humans and exaggerate a bit creating a table with 1000 rows and 10 cells in each running:
var start = new Date().getTime();
createDynamicTable(1000, 10);
var total = new Date().getTime() - start;
And let's see the results:
IN-LOOP jQuery OBJECTS/EL. CREATION vs. IN-LOOP STRING CONCATENATION
~920 ms ~130 ms
jsBin demo 1 jsBin demo 2
A (logical) side-note on the string concatenation:
you'll not be able to keep copies of alive Objects inside data-* attributes like i.e:
cell = "<td data-objectcopy='"+ myObject +"'>...</td>"
cause the object will result in String "[object Object]", in contrast to jQuery's .data():
cell = $("<td />", {html:"..."}).data("objectcopy", myObject );
where any further change to the object like: $(td).eq(0).data().objectcopy.someProperty = "new value"; will keep it's reference to the original myObject object alive.

Related

JavaScript create appropriate number of rows and columns based off of list length

I've been struggling with converting the following C# code into something I can use in JavaScript:
var g = Model.List.GroupBy(r => Model.List.IndexOf(r) / 3).ToList();
It's use was to create the appropriate number of rows, with the appropriate number of columns within them. So for example if the list had 6 elements it would allow me to create 3 rows with 2 columns in it, this was all done in razor pages using the above GroupBy and the below code:
foreach (var parent in g)
{
#Html.Raw("<div class='row'>");
foreach (var item in parent)
{
// populate contents of row
}
#Html.Raw("</div>");
}
However for certain reasons I can't do this in Razor and need to create an alternative in JavaScript but I'm struggling to figure out a way to do this.
Primarily because I don't understand entirely how 'GroupBy' creates the list of groups and what would be a suitable alternative.
Any help, or pointing in the right direction would be great. I've tried a few solutions I found online for creating 'GroupBys' but I couldn't get them to work the way I was expecting. I also thought maybe I could split the original list into a list of dictionaries, but again had little success. I'm possibly missing something obvious.
In the end it turns out I was just missing the obvious answer, I found this excellent SO answer. I had looked at slice but couldn't quite visualise how to use it for my problem (obviously been a long day).
The post showed this snippet:
var i,j,temparray,chunk = 10;
for (i=0,j=array.length; i<j; i+=chunk) {
temparray = array.slice(i,i+chunk);
// do whatever
}
In the end my JavaScript code looked something like this:
var listdata = await octokit.repos.listForUser({ "username": "", "type": "owner" });
var chunk = 2;
var loop = 0;
var tempArray = [];
for (var s = 0; s < listdata.data.length; s += chunk) {
tempArray[loop] = listdata.data.slice(s, s + chunk);
loop++;
}
var htmlString = "";
for (var t = 0; t < tempArray.length; t++) {
htmlString += "<div class='row'>";
var innerArray = tempArray[t];
for (var r = 0; r < innerArray.length; r++) {
var repo = innerArray[r];
htmlString +=
"<div class=\"col-md-6 col-sm-6 col-xs-12\">" +
"<div>" + repocontent + "</div>" +
"</div>"
}
htmlString += "</div>";
}
So with a list that's 6 items long, it gets split into an array that contains 3 lists of 2 items. Then I just create the html string using two for loops to create the outer bootstrap rows and the inner column classes. There's probably a more efficient way to do this but this worked a treat.

creating dynamic grid in javascript

I'm trying to create a dynamic grid in javascript.
Once I'm able to create the two-dimensional grid I'm going to input variables into my functions so they can accept any numerical inputs. For now, I'm just trying to get the grid the render both vertically and horizontally.
My second function is only allowing me to add cells to the same column instead of appending them horizontally. How can get the new columns to shift horizontally?
Here is my code:
function makeCell() {
const canvas = document.getElementById('pixelCanvas')
const newTable = document.createElement('table')
const tr = document.createElement('tr')
const td = document.createElement('td')
canvas.appendChild(newTable);
newTable.appendChild(tr);
tr.appendChild(td);
}
function makeLine() {
let em = ''
for (let i = 0; i < 2; i++) {
em += makeCell()
}
return em
}
function makeGrid() {
let en = ''
for (let i = 1; i <= 4; i++) {
en += makeLine()
}
return en + '\n'
}
makeGrid();
If you mentally run through the code you'll see where you went wrong in your logic.
MakeGrid fires, you go into the first for loop, makeLine fires, you go into the second inner for loop, makeCell fires, here you select the control with id='pixelCanvas', create a new table, create a new tr and create a new td. Then you append the table to the canvas, the tr to the table and lastly the td to the tr.
That's great for the first cell, but now you want the second... Here's the problem, makeCell completed and we go through round two of the for loop in makeLine. It's the same logic, however, so it creates a new table, but because the id is the same it doesn't overwrite anything. Then, it creates a new tr and a new td and appends those. That's why you end up with just one column, each iteration you're created a new row.
Solution:
So how do you fix that? Well, you've probably realized by now you need to create a new row and then iterate through all the cells you want to add to that row BEFORE you append that row to your table.
Modifying your code, this might look like so:
function makeCell(tr) {
// Create new td.
const td = document.createElement('td');
// Append td to tr.
tr.appendChild(td);
// return tr object with appended td.
return tr;
}
function makeLine(newTable) {
// Create new tr.
var tr = document.createElement('tr');
// Loop through number of cells.
for (let i = 0; i < 2; i++) {
// Overwrite tr object with each new cell added.
tr = makeCell(tr);
}
// Append new tr to table.
newTable.appendChild(tr);
// Return the table with the new tr.
return newTable;
}
function makeGrid() {
// Select canvas element.
const canvas = document.getElementById('pixelCanvas');
// Create new table.
var newTable = document.createElement('table');
// Loop through the rows, note use var so that I can pass the
// newTable object in to our function and overwrite it each loop.
for (let i = 1; i <= 4; i++) {
// Overwrite with each appended tr.
newTable = makeLine(newTable)
}
// Append completed object to canvas.
canvas.appendChild(newTable);
}
makeGrid();
Note the use of var instead of let, so the object can be overwritten with the new object on each iteration.
Hope that helps!

Issue with array.length and setInterval()

Background information: I'm retrieving an XML file every minute, parsing it, and appending the contents to an html table.
Here's the setInterval function
setInterval(function(){
data.length = 0;
deleteRows();
ajaxGet('rest/room/wakeup/?type=pending', parsePending);
appendAll();
console.log("refreshed");
}, 60000);
Data is an array of arrays. Each sub array contains a row of the table I'd like to append. Data is declared globally.
ajaxGet retrieves the XML file and calls the parsing function to process and pushes each row array into the data array. The parsing function logs each row to the console so I know it's working correctly.
Now here's where things go wrong.
function appendAll(){
for (var i = 0; i < data.length; i++){
var row = "<tr>";
console.log("row appended");
for (var key in data[i]){
row = row + "<td>" + data[i][key] + "</td>";
console.log("appended" + data[i][key]);
}
row = row + "</tr>";
$("#pending_wakeups tbody").append(row);
}
console.log("appended");
}
If any function within setInterval clears data before appendAll(), data.length will return 0. Despite the parsing function returning a full array to the console one call before appendAll(), it refuses to work for me.

Dynamic Javascript Table

Does anybody know how to convert my data to table by using Javascript or JQuery, I got this data for example:
var data1 = ["1","3","5"]
var data2 = ["a","b","c"]
Once the data1 and data2 value is updated then the rows and columns are also automatic updated.
result:
etc:
No. Alphabet
1 a
3 b
5 c
In your .html file
<table class="myTable"></table>
In your .js file
function generateTable(data1, data2){
var $table = $('.myTable');
for (var i = 0; i < data1.length; i++){
var $aSingleContent = '<tr><td>'+data1[i]+'</td><td>'+data2[i]+'</td></tr>';
$table.append($aSingleContent);
}
}
function modifyData() {
var data1 = ["1","3","5"];
var data2 = ["a","b","c"];
generateTable(data1, data2);
}
--------------------------------Update-------
I put the code in jsfiddle
http://jsfiddle.net/ronansmith/daLf9t85/
remember to add External Resources of jQuery
I like the idea of creating a function to dynamically set the innerHTML of a div, propagating it with a table.
It should look something like this:
function generate_table(array1, array2) {
var html = '<table>';
// cycles through all the elements in the array
for (var i = 0; i < array1.length; i++) {
html += '<tr><td>' + array1[i] + '</td><td>' + array2[i] + '</td></tr>';
}
html += '</table>';
// places the table in the element
document.getElementById('content').innerHTML = html;
}
generate_table() takes in the two arrays and constructs a String, propagating it with the contents of the array in a for loop. Then it gets a div named content and sets its innerHTML to create the table.
In your webpage, be sure to include the div to which the table will be inserted:
<div id="content"></div>
You can also call generate_table() every time your array refreshes, and the table will update.
I hope this helps you!
there are two ways you can do this. one, you wrap a function/class around your data and have a "changedata" method that changes the data and updates the html or you have a setInterval that listens for changes to those variables and serves the changes to you markup. the former is much better than the latter in my opinion

Parsing google trends - JS object

I'm trying to get the search terms and their values in the rising table here:
http://www.google.com/trends/explore#cat=0-14&date=today%207-d&cmpt=q
I can't work out what html tag/class/path they're in. How can I work it out? I tried looking at the source code but it wasn't much help.
Any help is really appreciated - Thx! Antoine
The following snippet will return an array of arrays (the overarching array contains values for each table in the page). Each array element has an array where each table row is an object, broken down into it's 'term' and 'value'.
var tableValues = [];
var t = document.querySelectorAll(".trends-table-data");
if(t.length>0){
var rows, row, cells, values;
for(var i=0; i<t.length; i++){
values = [];
rows = t[i].getElementsByTagName("tr");
for(var r=0; r<rows.length; r++){
row = rows[r];
if(row.className.indexOf('trends-table-row')===-1) continue;
cells = row.getElementsByTagName("td");
values.push({
term: cells[0].innerText.replace(/^\s+|\s+$/g, ''),
value: cells[1].innerText.replace(/^\s+|\s+$/g, '')
});
}
tableValues[i] = values;
}
console.log(tableValues);
}
Since there are two tables on the page, the output for the page you're referencing is:
tableValues = [[{"term":"friv","value":"100"},{"term":"baby","value":"55"},{"term":"hot","value":"50"},{"term":"girls","value":"45"},{"term":"games","value":"45"},{"term":"juegos","value":"30"},{"term":"العاب","value":"25"},{"term":"love","value":"25"},{"term":"bible","value":"20"},{"term":"india","value":"20"}],[{"term":"sophiya haque","value":"Breakout"},{"term":"temple run 2","value":"+3,200%"},{"term":"крещение","value":"+700%"},{"term":"dear abby","value":"+450%"},{"term":"temple run","value":"+200%"},{"term":"amber heard","value":"+130%"},{"term":"plein champ","value":"+130%"},{"term":"paranormal activity 4","value":"+90%"},{"term":"scientology","value":"+70%"},{"term":"mama","value":"+60%"}]]

Categories