Skip to content

Instantly share code, notes, and snippets.

@darshit-shah
Last active September 1, 2016 10:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darshit-shah/cbbe75ceb5f7a05ccba3417e1d8c969f to your computer and use it in GitHub Desktop.
Save darshit-shah/cbbe75ceb5f7a05ccba3417e1d8c969f to your computer and use it in GitHub Desktop.
CanvasGrid V2 - Dynamic Data - 1000000 Rows & 100 Columns
/*
// TODO
// 001 draw gridlines in initialStage
// 002 cell background and cell borders are to be drawn only if specified
// 003 Key down/up/left/right copy originalCanvas to new location and then render only required canvas
*/
var CanvasGrid = Object.create(HTMLElement.prototype);
CanvasGrid.createdCallback = function () {
var _this = this;
_this.props = {
'height': [['containerProperties', 'proposedHeight']], 'width': [['containerProperties', 'proposedWidth']], 'rows': [['gridProperties', 'rows']], 'cols': [['gridProperties', 'cols']], 'gridlinescolor': [['gridProperties', 'border', 'color']],
'colstartindex': [['dynamicProperties', 'colStartIndex']], 'rowstartindex': [['dynamicProperties', 'rowStartIndex']], 'rowheight': [['cellProperties', 'height']], 'colwidth': [['cellProperties', 'width']], 'backgroundcolor': [['gridProperties', 'background', 'color']],
'freezerowindex': [['dynamicProperties', 'freezeRowIndex']], 'freezecolindex': [['dynamicProperties', 'freezeColIndex']]
};
_this.state = CanvasGrid.getInitialState();
_this.callbackMethods = {};
var propNames = Object.keys(_this.props);
propNames.forEach(function (propName) {
var propValue = _this.getAttribute(propName);
CanvasGrid.updateProp(_this, propName, propValue)
});
//main container
_this.mainContainer = document.createElement('div');
_this.mainContainer.style.border = '1px solid #0F0F0F';
_this.mainContainer.style.position = 'relative';
_this.mainContainer.style.overflow = 'hidden';
_this.appendChild(_this.mainContainer);
//Canvas element
_this.mainGrid = document.createElement('canvas');
_this.mainGrid.style.position = 'absolute';
_this.mainGrid.style.left = 0;
_this.mainGrid.style.top = 0;
_this.mainCtx = _this.mainGrid.getContext('2d');
_this.mainContainer.appendChild(_this.mainGrid);
//Canvas element
_this.grid = document.createElement('canvas');
_this.grid.style.position = 'relative';
_this.grid.style.left = 0;
_this.grid.style.top = 0;
_this.ctx = _this.grid.getContext('2d');
//Canvas element for Cell
//_this.cell = document.createElement('canvas');
//_this.cell.style.position = 'relative';
//_this.cell.style.left = 0;
//_this.cell.style.top = 0;
//_this.cellCtx = _this.cell.getContext('2d');
_this.state.dynamicProperties.cacheImages = {};
////Canvas element for caching
//_this.cacheCell = document.createElement('canvas');
//_this.cacheCell.style.position = 'relative';
//_this.cacheCell.style.left = 0;
//_this.cacheCell.style.top = 0;
//_this.cacheCellCtx = _this.cell.getContext('2d');
//extra layer to handle events
_this.eventLayer = document.createElement('div');
_this.eventLayer.style.background = 'transparent';
_this.eventLayer.style.position = 'absolute';
_this.eventLayer.style.left = 0;
_this.eventLayer.style.top = 0;
_this.eventLayer.setAttribute('tabindex', "0");
_this.mainContainer.appendChild(_this.eventLayer);
_this.appendChild(_this.mainContainer);
//bind events
CanvasGrid.bindEvents(_this);
//finally render canvas
CanvasGrid.render(_this);
};
CanvasGrid.bindEvents = function (_this) {
//scroll events
_this.eventLayer.addEventListener('wheel', function (e) {
//console.log(e.wheelDeltaX, e.wheelDeltaY);
var deltaX = -e.wheelDeltaX;
var deltaY = -e.wheelDeltaY;
var xDir = deltaX <= 0 ? -1 : 1;
var yDir = deltaY <= 0 ? -1 : 1;
var deltaRows = 0, deltaCols = 0;
if (deltaX != 0 && Math.abs(deltaX) > Math.abs(deltaY)) {
deltaCols = Math.ceil(deltaX * xDir / _this.state.cellProperties.width);
}
else if (deltaY != 0) {
deltaRows = Math.ceil(deltaY * yDir / _this.state.cellProperties.height);
}
updateStartRowCol(_this, deltaRows * yDir, deltaCols * xDir);
});
//touch events
var touchStart = null;
var touchEnd = null;
var touchStartTime = 0;
var touchEndTime = 1000;
var touchSpeed = 10;
d3.select(_this.eventLayer).on('touchstart', function (e) {
d3.event.preventDefault();
var coordinates = d3.touches(this);
touchStart = coordinates[0];
touchStartTime = new Date().getTime();
touchEnd = null;
});
d3.select(_this.eventLayer).on('touchmove', function (e) {
d3.event.preventDefault();
if (touchStart === null)
return;
var coordinates = d3.touches(this);
touchEnd = coordinates[0];
var deltaX = touchStart[0] - touchEnd[0];
var deltaY = touchStart[1] - touchEnd[1];
var xDir = deltaX <= 0 ? -1 : 1;
var yDir = deltaY <= 0 ? -1 : 1;
var gridWidth = _this.state.containerProperties.width;
var gridHeight = _this.state.containerProperties.height;
if (deltaY < 0) {
//console.log(deltaY);
_this.mainCtx.clearRect(0, _this.state.dynamicProperties.freezeY, gridWidth, _this.state.dynamicProperties.freezeY - deltaY);
var diffY = 0;
var shiftY = 0;
if ((gridHeight * 3 + deltaY) > ((gridHeight * 2) + _this.state.dynamicProperties.freezeY)) {
shiftY = gridHeight * 3 + deltaY;
}
else {
shiftY = ((gridHeight * 2) + _this.state.dynamicProperties.freezeY);
diffY = ((gridHeight * 2) + _this.state.dynamicProperties.freezeY) - (gridHeight * 3 + deltaY);
}
_this.mainCtx.drawImage(_this.grid, 0, shiftY, gridWidth, diffY - deltaY, 0, _this.state.dynamicProperties.freezeY + diffY, gridWidth, diffY - deltaY);
_this.mainCtx.drawImage(_this.grid, 0, _this.state.dynamicProperties.freezeY, gridWidth, gridHeight, 0, _this.state.dynamicProperties.freezeY - deltaY, gridWidth, gridHeight);
}
else {
_this.mainCtx.drawImage(_this.grid, 0, _this.state.dynamicProperties.freezeY + deltaY, gridWidth, gridHeight, 0, _this.state.dynamicProperties.freezeY, gridWidth, gridHeight);
}
});
d3.select(_this.eventLayer).on('touchend', function (e) {
d3.event.preventDefault();
var gridWidth = _this.state.containerProperties.width;
var gridHeight = _this.state.containerProperties.height;
if (touchEnd === null) {
return;
}
var deltaX = touchEnd[0] - touchStart[0];
var deltaY = touchEnd[1] - touchStart[1];
if (deltaY < 0) {
var newRowIndex = _this.state.dynamicProperties.rowStartIndex;
var newDelta = 0;
for (rIndex = newRowIndex; rIndex < _this.state.dynamicProperties.currRowsWithHeight.length && deltaY < 0; rIndex++) {
if (0 < deltaY * -1) {
newRowIndex++;
deltaY += _this.state.dynamicProperties.currRowsWithHeight[rIndex];
newDelta += _this.state.dynamicProperties.currRowsWithHeight[rIndex];
}
else {
break;
}
}
if (newRowIndex != _this.state.dynamicProperties.rowStartIndex) {
internalTimer(deltaY * 1.5, function (perc) {
_this.mainCtx.drawImage(_this.grid, 0, _this.state.dynamicProperties.freezeY + ((newDelta - deltaY) + (deltaY * perc)), gridWidth, gridHeight, 0, _this.state.dynamicProperties.freezeY, gridWidth, gridHeight);
if (perc === 1) {
CanvasGrid.updateProp(_this, "rowStartIndex", newRowIndex);
}
});
}
else {
console.log("This should never happen if we scroll only up");
internalTimer(100, function (perc) {
_this.mainCtx.drawImage(_this.grid, 0, _this.state.dynamicProperties.freezeY - deltaY + (deltaY * perc), gridWidth, gridHeight, 0, _this.state.dynamicProperties.freezeY, gridWidth, gridHeight);
});
}
}
else {
var newRowIndex = _this.state.dynamicProperties.rowStartIndex;
var newDelta = 0;
console.log(deltaY);
for (rIndex = newRowIndex - 1; rIndex >= _this.state.dynamicProperties.freezeRowIndex && deltaY > 0; rIndex--) {
if (0 > deltaY * -1) {
newRowIndex--;
deltaY -= _this.state.dynamicProperties.currRowsWithHeight[rIndex];
newDelta += _this.state.dynamicProperties.currRowsWithHeight[rIndex];
}
else {
break;
}
}
if (newRowIndex != _this.state.dynamicProperties.rowStartIndex) {
internalTimer(-deltaY * 1.5, function (perc) {
var diff = 0;
var shift = 0;
if ((gridHeight * 3 - newDelta) > ((gridHeight * 2) + _this.state.dynamicProperties.freezeY)) {
shift = gridHeight * 3 - newDelta;
}
else {
shift = ((gridHeight * 2) + _this.state.dynamicProperties.freezeY);
diff = ((gridHeight * 2) + _this.state.dynamicProperties.freezeY) - (gridHeight * 3 - newDelta);
}
//console.log(shift, newDelta, diff, deltaY);
_this.mainCtx.drawImage(_this.grid, 0, shift - deltaY + (deltaY * perc), gridWidth, newDelta, 0, _this.state.dynamicProperties.freezeY, gridWidth, newDelta);
_this.mainCtx.drawImage(_this.grid, 0, _this.state.dynamicProperties.freezeY, gridWidth, gridHeight, 0, _this.state.dynamicProperties.freezeY + (newDelta + deltaY) - (deltaY * perc), gridWidth, gridHeight);
if (perc === 1) {
CanvasGrid.updateProp(_this, "rowStartIndex", newRowIndex);
}
});
}
else {
console.log("This should never happen if we scroll only up");
internalTimer(100, function (perc) {
_this.mainCtx.drawImage(_this.grid, 0, _this.state.dynamicProperties.freezeY, gridWidth, gridHeight, 0, _this.state.dynamicProperties.freezeY + deltaY - (deltaY * perc), gridWidth, gridHeight);
});
}
}
//if (deltaX < 0) {
// var newColIndex = _this.state.dynamicProperties.colStartIndex;
// var newDeltaX = 0;
// for (cIndex = newColIndex; cIndex < _this.state.dynamicProperties.currColumnsWithWidth.length && deltaX < 0; cIndex++) {
// if (0 < deltaX * -1) {
// newColIndex++;
// deltaX += _this.state.dynamicProperties.currColumnsWithWidth[cIndex];
// newDeltaX += _this.state.dynamicProperties.currColumnsWithWidth[cIndex];
// }
// else {
// break;
// }
// }
// if (newColIndex != _this.state.dynamicProperties.colStartIndex) {
// internalTimer(deltaX * 1.5, function (perc) {
// _this.mainCtx.drawImage(_this.grid, _this.state.dynamicProperties.freezeX + ((newDeltaX - deltaX) + (deltaX * perc)), 0, gridWidth, gridHeight, _this.state.dynamicProperties.freezeX, 0, gridWidth, gridHeight);
// if (perc === 1) {
// CanvasGrid.updateProp(_this, "colStartIndex", newColIndex);
// }
// });
// }
// else {
// console.log("This should never happen if we scroll only up");
// internalTimer(100, function (perc) {
// _this.mainCtx.drawImage(_this.grid, _this.state.dynamicProperties.freezeX - deltaX + (deltaX * perc), 0, gridWidth, gridHeight, _this.state.dynamicProperties.freezeX, 0, gridWidth, gridHeight);
// });
// }
//}
//else {
// var newColIndex = _this.state.dynamicProperties.colStartIndex;
// var newDeltaX = 0;
// //debugger;
// for (cIndex = newColIndex; cIndex > _this.state.dynamicProperties.freezeColIndex && deltaX > 0; cIndex--) {
// if (0 > deltaX * -1) {
// newColIndex--;
// deltaX -= _this.state.dynamicProperties.currColumnsWithWidth[cIndex];
// newDeltaX += _this.state.dynamicProperties.currColumnsWithWidth[cIndex];
// }
// else {
// break;
// }
// }
// if (newColIndex != _this.state.dynamicProperties.colStartIndex) {
// internalTimer(-deltaX * 1.5, function (perc) {
// var diffX = 0;
// var shiftX = 0;
// if ((gridWidth * 3 - newDeltaX) > ((gridWidth * 2) + _this.state.dynamicProperties.freezeX)) {
// shiftX = gridWidth * 3 - newDeltaX;
// }
// else {
// shiftX = ((gridWidth * 2) + _this.state.dynamicProperties.freezeX);
// diffX = ((gridWidth * 2) + _this.state.dynamicProperties.freezeX) - (gridWidth * 3 - newDeltaX);
// }
// console.log(shiftX, diffX, newDeltaX);
// _this.mainCtx.drawImage(_this.grid, shiftX + newDeltaX - (newDeltaX * perc), 0, diffX + newDeltaX, gridHeight, _this.state.dynamicProperties.freezeX + diffX, 0, diffX + newDeltaX, gridHeight);
// _this.mainCtx.drawImage(_this.grid, _this.state.dynamicProperties.freezeX, 0, gridWidth, gridHeight, _this.state.dynamicProperties.freezeX + newDeltaX + deltaX - (deltaX * perc), 0, gridWidth, gridHeight);
// if (perc === 1) {
// CanvasGrid.updateProp(_this, "colStartIndex", newColIndex);
// }
// });
// }
// else {
// console.log("This should never happen if we scroll only up");
// internalTimer(100, function (perc) {
// _this.mainCtx.drawImage(_this.grid, _this.state.dynamicProperties.freezeX, 0, gridWidth, gridHeight, _this.state.dynamicProperties.freezeX + deltaX - (deltaX * perc), 0, gridWidth, gridHeight);
// });
// }
//}
});
function internalTimer(timerMilliSecond, cb) {
d3.timer(function (x) {
if (x > timerMilliSecond) {
cb(1);
return true;
}
else {
cb(x / timerMilliSecond);
return false;
}
}, 0, +new Date());
}
//Key events
var keyDownLock = false;
_this.eventLayer.addEventListener('keydown', function (e) {
if (keyDownLock === true)
return;
var deltaRows = 0;
var deltaCols = 0;
//down
if (e.keyCode === 40) {
deltaRows = 1;
}
//up
else if (e.keyCode === 38) {
deltaRows = -1;
}
//right
else if (e.keyCode === 39) {
deltaCols = 1;
}
//left
else if (e.keyCode === 37) {
deltaCols = -1;
}
//page down
else if (e.keyCode === 34) {
deltaRows = (_this.state.dynamicProperties.rowEndIndex - _this.state.dynamicProperties.rowStartIndex) + 1;
}
//page up
else if (e.keyCode === 33) {
deltaRows = -((_this.state.dynamicProperties.rowEndIndex - _this.state.dynamicProperties.rowStartIndex) + 1);
}
//end
else if (e.keyCode === 35) {
deltaCols = -_this.state.dynamicProperties.colStartIndex;
}
//home
else if (e.keyCode === 36) {
deltaCols = -_this.state.dynamicProperties.colStartIndex;
}
else {
console.log(e.keyCode);
}
if (deltaCols != 0 || deltaRows != 0) {
keyDownLock = true;
setTimeout(function () {
keyDownLock = false;
}, 0);
updateStartRowCol(_this, deltaRows, deltaCols);
e.preventDefault();
}
});
var updateStartRowColLock = false;
function updateStartRowCol(_this, deltaRows, deltaCols) {
if (updateStartRowColLock === true)
return;
//console.log(_this.state.dynamicProperties.rowStartIndex, _this.state.dynamicProperties.rowEndIndex, deltaRows);
var needUpdate = false;
if (deltaRows != 0) {
var newPos = _this.state.dynamicProperties.rowStartIndex;
if (deltaRows > 0) {
if (deltaRows + _this.state.dynamicProperties.rowEndIndex > ((+_this.state.gridProperties.rows) - 1)) {
deltaRows = ((+_this.state.gridProperties.rows) - 1) - _this.state.dynamicProperties.rowEndIndex;
}
}
else if (deltaRows < 0) {
if (newPos + deltaRows < _this.state.dynamicProperties.freezeRowIndex) {
deltaRows = _this.state.dynamicProperties.freezeRowIndex - newPos;
}
}
if (_this.state.dynamicProperties.rowStartIndex != newPos + deltaRows) {
_this.state.dynamicProperties.rowStartIndex = newPos + deltaRows;
needUpdate = true;
}
}
if (deltaCols != 0) {
var newPos = _this.state.dynamicProperties.colStartIndex;
if (deltaCols > 0) {
if (deltaCols + _this.state.dynamicProperties.colEndIndex > ((+_this.state.gridProperties.cols) - 1)) {
deltaCols = ((+_this.state.gridProperties.cols) - 1) - _this.state.dynamicProperties.colEndIndex;
}
}
else if (deltaCols < 0) {
if (newPos + deltaCols < _this.state.dynamicProperties.freezeColIndex) {
deltaCols = _this.state.dynamicProperties.freezeColIndex - newPos;
}
}
if (_this.state.dynamicProperties.colStartIndex != newPos + deltaCols) {
_this.state.dynamicProperties.colStartIndex = newPos + deltaCols;
needUpdate = true;
}
}
if (needUpdate === true)
CanvasGrid.render(_this);
}
};
CanvasGrid.updateProp = function (_this, propName, propValue) {
propName = propName.toLowerCase();
if (propValue != null) {
if (!isNaN(+propValue))
propValue = +propValue;
_this.props[propName].forEach(function (propIndex, index) {
var s = _this.state;
var status = _this.props[propName][index].every(function (child, childIndex) {
if (s.hasOwnProperty(child)) {
if (childIndex === (_this.props[propName][index].length - 1)) {
s[child] = propValue;
}
else {
s = s[child];
}
return true;
}
return false;
});
if (status === false) {
console.error("Invalid Property : " + propName);
}
});
}
if (_this.state.dynamicProperties.renderTimeoutInterval != null) {
clearInterval(_this.state.dynamicProperties.renderTimeoutInterval);
}
_this.state.dynamicProperties.renderTimeoutInterval = setTimeout(function () {
CanvasGrid.render(_this);
}, 1);
}
CanvasGrid.attributeChangedCallback = function (attrName, oldVal, newVal) {
var _this = this;
//console.log(attrName, oldVal, newVal, this.state);
CanvasGrid.updateProp(_this, attrName, newVal);
}
CanvasGrid.render = function (_this) {
_this.state.dynamicProperties.rowStartIndex = +_this.state.dynamicProperties.rowStartIndex;
_this.state.dynamicProperties.colStartIndex = +_this.state.dynamicProperties.colStartIndex;
if (_this.state.dynamicProperties.colStartIndex < _this.state.dynamicProperties.freezeColIndex)
_this.state.dynamicProperties.colStartIndex = _this.state.dynamicProperties.freezeColIndex;
if (_this.state.dynamicProperties.rowStartIndex < _this.state.dynamicProperties.freezeRowIndex)
_this.state.dynamicProperties.rowStartIndex = _this.state.dynamicProperties.freezeRowIndex;
_this.state.dynamicProperties.rowEndIndex = +_this.state.dynamicProperties.rowEndIndex;
_this.state.dynamicProperties.colEndIndex = +_this.state.dynamicProperties.colEndIndex;
if (_this.state.containerProperties.proposedHeight !== _this.state.containerProperties.height) {
_this.mainContainer.style.height = _this.state.containerProperties.proposedHeight;
_this.state.containerProperties.height = _this.mainContainer.offsetHeight;
_this.state.containerProperties.proposedHeight = _this.state.containerProperties.height;
}
if (_this.state.containerProperties.proposedWidth !== _this.state.containerProperties.width) {
_this.mainContainer.style.width = _this.state.containerProperties.proposedWidth;
_this.state.containerProperties.width = _this.mainContainer.offsetWidth;
_this.state.containerProperties.proposedWidth = _this.state.containerProperties.width;
}
var gridWidth = _this.state.containerProperties.width;
var gridHeight = _this.state.containerProperties.height;
if (_this.state.gridProperties.width !== gridWidth) {
_this.state.gridProperties.width = gridWidth;
_this.grid.width = _this.state.gridProperties.width * 3;
//_this.cell.width = _this.state.gridProperties.width * 3;
//_this.cacheCell.width = _this.state.cellProperties.width;
_this.mainGrid.width = _this.state.gridProperties.width;
_this.eventLayer.style.width = _this.state.gridProperties.width + 'px';
}
if (_this.state.gridProperties.height !== gridHeight) {
_this.state.gridProperties.height = gridHeight;
_this.grid.height = _this.state.gridProperties.height * 3;
//_this.cell.height = _this.state.gridProperties.height * 3;
//_this.cacheCell.height = _this.state.cellProperties.height;
_this.mainGrid.height = _this.state.gridProperties.height;
_this.eventLayer.style.height = _this.state.gridProperties.height + 'px';
}
CanvasGrid.renderGrid(_this);
};
CanvasGrid.renderGrid = function (_this) {
var gridWidth = _this.state.containerProperties.width;
var gridHeight = _this.state.containerProperties.height;
//_this.ctx.beginPath();
//_this.ctx.rect(0, 0, _this.state.gridProperties.width * 3, _this.state.gridProperties.height * 3);
//_this.ctx.fillStyle = _this.state.cellProperties.background.color;
//_this.ctx.fill();
//_this.cellCtx.beginPath();
//_this.cellCtx.rect(0, 0, _this.state.gridProperties.width * 3, _this.state.gridProperties.height * 3);
//_this.cellCtx.fillStyle = _this.state.cellProperties.background.color;
//_this.cellCtx.fill();
//_this.cacheCellCtx.beginPath();
//_this.cacheCellCtx.rect(0, 0, _this.state.cellProperties.width, _this.state.cellProperties.height);
//_this.cacheCellCtx.fillStyle = _this.state.cellProperties.background.color;
//_this.cacheCellCtx.fill();
var rowNumberColWidth = 0;
var currX = 0, currY = 0;
var startX = 0, startY = 0;
var gridDataStartX = 0, gridDataStartY = 0;
var endX = 0, endY = 0;
if (_this.state.dynamicProperties.currRowsWithHeight == undefined)
_this.state.dynamicProperties.currRowsWithHeight = [];
if (_this.state.dynamicProperties.currColumnsWithWidth == undefined)
_this.state.dynamicProperties.currColumnsWithWidth = [];
var requestedData = [];
var redraw = false;
var nullValues = {};
var availableValues = {};
function renderCell(currRow, currCol, isExtraRow, isReverseRow, isExtraCol, isReverseCol) {
if (currY === 0) {
_this.ctx.beginPath();
_this.ctx.moveTo(Math.floor(currX + _this.state.dynamicProperties.currColumnsWithWidth[currCol]) + 0.5, Math.floor(0) + 0.5);
_this.ctx.lineTo(Math.floor(currX + _this.state.dynamicProperties.currColumnsWithWidth[currCol]) + 0.5, Math.floor(gridHeight * 3) + 0.5);
_this.ctx.strokeStyle = _this.state.gridProperties.border.color;
_this.ctx.lineWidth = _this.state.gridProperties.border.width;
_this.ctx.lineCap = 'round';
_this.ctx.stroke();
}
if (isExtraRow !== true) {
_this.state.dynamicProperties.rowEndIndex = currRow - 1;
}
if (isExtraCol !== true) {
_this.state.dynamicProperties.colEndIndex = currCol - 1;
}
_this.state.dynamicProperties.rowEndIndexExtra = currRow - 1;
_this.state.dynamicProperties.colEndIndexExtra = currRow - 1;
var cellValue = null;
var cellProperties = _this.state.cellProperties;
if (availableValues.hasOwnProperty(currRow) && availableValues[currRow][currCol] != null) {
cellValue = availableValues[currRow][currCol];
}
else if (_this.callbackMethods['getCellValue']) {
cellValue = _this.callbackMethods['getCellValue'].callback(currRow, currCol);
}
if (cellValue == null) {
if (!nullValues.hasOwnProperty(currRow)) {
nullValues[currRow] = {};
}
nullValues[currRow][currCol] = null;
}
if (cellValue != null && typeof cellValue == 'object' && cellValue.hasOwnProperty('cellProperties')) {
cellProperties = utilLibrary.extend(true, {}, _this.state.cellProperties);
cellProperties = utilLibrary.extend(true, cellProperties, cellValue.cellProperties);
cellValue = cellValue.text;
}
if (_this.state.dynamicProperties.currRowsWithHeight[currRow] == undefined || _this.state.dynamicProperties.currRowsWithHeight[currRow] < cellProperties.height) {
_this.state.dynamicProperties.currRowsWithHeight[currRow] = cellProperties.height;
redraw = true;
}
if (_this.state.dynamicProperties.currColumnsWithWidth[currCol] == undefined && _this.callbackMethods['getColumnWidth']) {
_this.state.dynamicProperties.currColumnsWithWidth[currCol] = _this.callbackMethods['getColumnWidth'].callback(currCol);
}
if (_this.state.dynamicProperties.currColumnsWithWidth[currCol] == undefined || _this.state.dynamicProperties.currColumnsWithWidth[currCol] < cellProperties.width) {
_this.state.dynamicProperties.currColumnsWithWidth[currCol] = cellProperties.width;
redraw = true;
}
var updatedStats = CanvasGrid.drawCell(_this, currX, currY, currX + _this.state.dynamicProperties.currColumnsWithWidth[currCol], currY + _this.state.dynamicProperties.currRowsWithHeight[currRow], cellValue, cellProperties, true);
if (updatedStats != null) {
if (updatedStats[0] > _this.state.dynamicProperties.currColumnsWithWidth[currCol]) {
_this.state.dynamicProperties.currColumnsWithWidth[currCol] = updatedStats[0];
redraw = true;
}
if (updatedStats[1] > _this.state.dynamicProperties.currRowsWithHeight[currRow]) {
_this.state.dynamicProperties.currRowsWithHeight[currRow] = updatedStats[1];
redraw = true;
}
}
if (isReverseCol === true) {
currX -= _this.state.dynamicProperties.currColumnsWithWidth[currCol];
}
else {
currX += _this.state.dynamicProperties.currColumnsWithWidth[currCol];
}
}
function renderRow(currRow, isExtraRow, isReverseRow, isExtraCol, isReverseCol) {
//console.log('Rendering row', currRow);
currX = 0;
if (currX === 0) {
_this.ctx.beginPath();
_this.ctx.moveTo(Math.floor(0) + 0.5, Math.floor(currY + _this.state.dynamicProperties.currRowsWithHeight[currRow]) + 0.5);
_this.ctx.lineTo(Math.floor(gridWidth * 3) + 0.5, Math.floor(currY + _this.state.dynamicProperties.currRowsWithHeight[currRow]) + 0.5);
_this.ctx.strokeStyle = _this.state.gridProperties.border.color;
_this.ctx.lineWidth = _this.state.gridProperties.border.width;
_this.ctx.lineCap = 'round';
_this.ctx.stroke();
}
if (_this.state.dynamicProperties.currRowsWithHeight[currRow] == undefined && _this.callbackMethods['getRowHeight']) {
_this.state.dynamicProperties.currRowsWithHeight[currRow] = _this.callbackMethods['getRowHeight'].callback(currRow);
}
for (var currCol = 0; currCol < _this.state.dynamicProperties.freezeColIndex && currX <= gridWidth; currCol++) {
renderCell(currRow, currCol, isExtraRow, isReverseRow, isExtraCol, isReverseCol);
}
if (_this.state.dynamicProperties.freezeX < currX) {
_this.state.dynamicProperties.freezeX = currX;
}
for (var currCol = _this.state.dynamicProperties.colStartIndex; currCol < _this.state.gridProperties.cols && currX <= gridWidth; currCol++) {
renderCell(currRow, currCol, isExtraRow, isReverseRow, isExtraCol, isReverseCol);
}
if (isExtraRow === true) {
for (; currCol < _this.state.gridProperties.cols && currX <= gridWidth * 2; currCol++) {
renderCell(currRow, currCol, isExtraRow, isReverseRow, true, false);
}
if (_this.state.dynamicProperties.currColumnsWithWidth[_this.state.dynamicProperties.colStartIndex - 1] != undefined) {
currX = gridWidth * 3 - _this.state.dynamicProperties.currColumnsWithWidth[_this.state.dynamicProperties.colStartIndex - 1];
}
else {
currX = gridWidth * 3;
}
for (currCol = _this.state.dynamicProperties.colStartIndex - 1; currCol >= _this.state.dynamicProperties.freezeColIndex && currX > gridWidth * 2; currCol--) {
renderCell(currRow, currCol, isExtraRow, isReverseRow, true, true);
}
}
if (isReverseRow === true) {
currY -= _this.state.dynamicProperties.currRowsWithHeight[currRow - 1];
}
else {
currY += _this.state.dynamicProperties.currRowsWithHeight[currRow];
}
}
function renderAllRows() {
var fullRedraw = true;
var rowStart = _this.state.dynamicProperties.rowStartIndex;
var startY = 0;
//if (_this.state.dynamicProperties.rowStartIndex != _this.state.dynamicProperties.rowStartIndexOld || _this.state.dynamicProperties.colStartIndex != _this.state.dynamicProperties.colStartIndexOld) {
// var copyStartX = 0;
// var copyStartY = _this.state.dynamicProperties.freezeY;
// if (_this.state.dynamicProperties.rowStartIndex > _this.state.dynamicProperties.rowStartIndexOld && _this.state.dynamicProperties.rowStartIndex <= _this.state.dynamicProperties.rowEndIndexOld) {
// var rIndex = 0;
// for (rIndex = _this.state.dynamicProperties.rowStartIndexOld; rIndex < _this.state.dynamicProperties.rowStartIndex; rIndex++) {
// copyStartY += _this.state.dynamicProperties.currRowsWithHeight[rIndex];
// }
// rowStart = _this.state.dynamicProperties.rowEndIndexExtra;
// var imgData = _this.ctx.getImageData(copyStartX, copyStartY, _this.state.gridProperties.width * 2 - copyStartX, _this.state.gridProperties.height * 2 - copyStartY);
// _this.ctx.putImageData(imgData, copyStartX, _this.state.dynamicProperties.freezeY);
// //_this.mainCtx.drawImage(_this.grid, 0, 0, gridWidth, gridHeight, 0, 0, gridWidth, gridHeight);
// startY = _this.state.gridProperties.height * 2 - copyStartY;
// fullRedraw = false;
// //// save canvas image as data url (png format by default)
// //var dataURL = _this.grid.toDataURL();
// //// set canvasImg image src to dataURL
// //// so it can be saved as an image
// //document.getElementById('canvasImg').src = dataURL;
// //return;
// }
// else {
// }
//}
redraw = false;
currY = startY;
if (fullRedraw === true) {
_this.ctx.beginPath();
_this.ctx.rect(0, 0, _this.state.gridProperties.width * 3, _this.state.gridProperties.height * 3);
_this.ctx.fillStyle = _this.state.gridProperties.background.color;
_this.ctx.fill();
_this.ctx.strokeStyle = _this.state.gridProperties.border.color;
_this.ctx.lineWidth = _this.state.gridProperties.border.width;
_this.ctx.lineCap = 'round';
_this.ctx.stroke();
_this.state.dynamicProperties.freezeX = 0;
_this.state.dynamicProperties.freezeY = 0;
var currRow = 0
for (currRow = 0; currRow < _this.state.dynamicProperties.freezeRowIndex && currY <= gridHeight; currRow++) {
renderRow(currRow);
}
if (_this.state.dynamicProperties.freezeY < currY) {
_this.state.dynamicProperties.freezeY = currY;
}
}
for (currRow = rowStart; currRow < _this.state.gridProperties.rows && currY <= gridHeight; currRow++) {
renderRow(currRow);
}
if (redraw == false) {
_this.mainCtx.drawImage(_this.grid, 0, 0, gridWidth, gridHeight, 0, 0, gridWidth, gridHeight);
if (_this.state.dynamicProperties.extraRowsRenderTimeoutInterval != null) {
clearInterval(_this.state.dynamicProperties.extraRowsRenderTimeoutInterval);
}
_this.state.dynamicProperties.extraRowsRenderTimeoutInterval = setTimeout(function () {
var currRow = 0
currY = startY;
if (fullRedraw === true) {
_this.ctx.beginPath();
_this.ctx.rect(0, 0, _this.state.gridProperties.width * 3, _this.state.gridProperties.height * 2);
_this.ctx.fillStyle = _this.state.gridProperties.background.color;
_this.ctx.fill();
console.log("Rendering extra row/cols");
for (currRow = 0; currRow < _this.state.dynamicProperties.freezeRowIndex && currY <= gridHeight; currRow++) {
renderRow(currRow, true, false);
}
}
for (currRow = rowStart; currRow < _this.state.gridProperties.rows && currY <= gridHeight; currRow++) {
renderRow(currRow, true, false);
}
for (; currRow < _this.state.gridProperties.rows && currY <= gridHeight * 2; currRow++) {
renderRow(currRow, true, false);
}
if (fullRedraw === true) {
_this.ctx.beginPath();
_this.ctx.rect(0, _this.state.gridProperties.height * 2, _this.state.gridProperties.width * 3, _this.state.gridProperties.height);
_this.ctx.fillStyle = _this.state.gridProperties.background.color;
_this.ctx.fill();
}
//if (_this.state.dynamicProperties.currRowsWithHeight[_this.state.dynamicProperties.rowStartIndex - 1] != undefined) {
// currY = gridHeight * 3 - _this.state.dynamicProperties.currRowsWithHeight[_this.state.dynamicProperties.rowStartIndex - 1];
//}
//else {
// currY = gridHeight * 3;
//}
//for (currRow = _this.state.dynamicProperties.rowStartIndex - 1; currRow >= _this.state.dynamicProperties.freezeRowIndex && currY >= gridHeight * 2; currRow--) {
// renderRow(currRow, true, true);
//}
_this.ctx.beginPath();
_this.ctx.rect(0, 0, _this.state.gridProperties.width * 3, _this.state.gridProperties.height * 3);
_this.ctx.strokeStyle = _this.state.gridProperties.border.color;
_this.ctx.lineWidth = _this.state.gridProperties.border.width;
_this.ctx.lineCap = 'round';
_this.ctx.stroke();
_this.state.dynamicProperties.rowStartIndexOld = _this.state.dynamicProperties.rowStartIndex;
_this.state.dynamicProperties.colStartIndexOld = _this.state.dynamicProperties.colStartIndex;
_this.state.dynamicProperties.rowEndIndexOld = _this.state.dynamicProperties.rowEndIndex;
_this.state.dynamicProperties.colEndIndexOld = _this.state.dynamicProperties.colEndIndex;
//// save canvas image as data url (png format by default)
//var dataURL = _this.grid.toDataURL();
//// set canvasImg image src to dataURL
//// so it can be saved as an image
//document.getElementById('canvasImg').src = dataURL;
if (Object.keys(nullValues).length > 0 && _this.callbackMethods['getData']) {
_this.callbackMethods['getData'].counter++;
//console.log("Calling Get Data for ", _this.callbackMethods['getData'].counter);
setTimeout(function () {
_this.callbackMethods['getData'].callback(_this.callbackMethods['getData'].counter, nullValues, function (counter, data) {
//console.log("returned Get Data", counter);
if (_this.callbackMethods['getData'].counter === counter) {
availableValues = data;
nullValues = {};
renderAllRows();
data = null;
}
});
}, 100);
}
}, 100);
_this.eventLayer.focus();
}
else {
renderAllRows();
}
}
renderAllRows();
//if (Object.keys(nullValues).length > 0 && _this.callbackMethods['getData']) {
// _this.callbackMethods['getData'].counter++;
// //console.log("Calling Get Data for ", _this.callbackMethods['getData'].counter);
// setTimeout(function () {
// _this.callbackMethods['getData'].callback(_this.callbackMethods['getData'].counter, nullValues, function (counter, data) {
// //console.log("returned Get Data", counter);
// if (_this.callbackMethods['getData'].counter === counter) {
// nullValues = data;
// renderAllRows();
// data = null;
// }
// });
// }, 10);
//}
return;
};
CanvasGrid.drawCell = function (_this, x0, y0, x1, y1, cellValue, cellProperties) {
var drawBackground = true;
//if (_this.state.dynamicProperties.cacheImages.hasOwnProperty(JSON.stringify(cellProperties) + "_" + (x1 - x0) + "_" + (y1 - y0))) {
// _this.ctx.putImageData(_this.state.dynamicProperties.cacheImages[JSON.stringify(cellProperties) + "_" + (x1 - x0) + "_" + (y1 - y0)], x0, y0);
// drawBackground = false;
//}
if (drawBackground === true) {
if (cellProperties.hasOwnProperty('background') && cellProperties.background.hasOwnProperty('color')) {
// clear cell
_this.ctx.beginPath();
_this.ctx.rect(x0 + (_this.state.gridProperties.border.width / 2), y0 + (_this.state.gridProperties.border.width / 2), (x1 - x0) - (_this.state.gridProperties.border.width), (y1 - y0) - (_this.state.gridProperties.border.width));
_this.ctx.fillStyle = cellProperties.background.color;
_this.ctx.fill();
}
// border left
if (cellProperties.hasOwnProperty('border') && cellProperties.border.hasOwnProperty('left')) {
_this.ctx.beginPath();
_this.ctx.moveTo(Math.floor(x0) + 0.5, Math.floor(y1) + 0.5);
_this.ctx.lineTo(Math.floor(x0) + 0.5, Math.floor(y0) + 0.5);
_this.ctx.strokeStyle = cellProperties.border.left.color;
_this.ctx.lineWidth = cellProperties.border.left.width;
_this.ctx.lineCap = 'round';
_this.ctx.stroke();
}
// border top
if (cellProperties.hasOwnProperty('border') && cellProperties.border.hasOwnProperty('top')) {
_this.ctx.beginPath();
_this.ctx.moveTo(Math.floor(x0) + 0.5, Math.floor(y0) + 0.5);
_this.ctx.lineTo(Math.floor(x1) + 0.5, Math.floor(y0) + 0.5);
_this.ctx.strokeStyle = cellProperties.border.top.color;
_this.ctx.lineWidth = cellProperties.border.top.width;
_this.ctx.lineCap = 'round';
_this.ctx.stroke();
}
// border right
if (cellProperties.hasOwnProperty('border') && cellProperties.border.hasOwnProperty('right')) {
_this.ctx.beginPath();
_this.ctx.moveTo(Math.floor(x1) + 0.5, Math.floor(y0) + 0.5);
_this.ctx.lineTo(Math.floor(x1) + 0.5, Math.floor(y1) + 0.5);
_this.ctx.strokeStyle = cellProperties.border.right.color;
_this.ctx.lineWidth = cellProperties.border.right.width;
_this.ctx.lineCap = 'round';
_this.ctx.stroke();
}
// border bottom
if (cellProperties.hasOwnProperty('border') && cellProperties.border.hasOwnProperty('bottom')) {
_this.ctx.beginPath();
_this.ctx.moveTo(Math.floor(x1) + 0.5, Math.floor(y1) + 0.5);
_this.ctx.lineTo(Math.floor(x0) + 0.5, Math.floor(y1) + 0.5);
_this.ctx.strokeStyle = cellProperties.border.bottom.color;
_this.ctx.lineWidth = cellProperties.border.bottom.width;
_this.ctx.lineCap = 'round';
_this.ctx.stroke();
}
}
var matrix = null;
if (cellValue == null) {
cellValue = '?';
}
if (cellValue != null && (typeof cellValue != 'string' || cellValue.trim() != '')) {
matrix = CanvasGrid.drawText(_this, x0, y0, x1, y1, cellValue, cellProperties.textStyle);
x1 = matrix[0] + x0;
y1 = matrix[1] + y0;
}
if (cellProperties != null && cellProperties.background != null && cellProperties.background.img != null) {
CanvasGrid.drawImage(_this, x0, y0, x1, y1, cellProperties.background.img);
}
return matrix;
}
CanvasGrid.measureText = function (_this, text, textStyle) {
_this.ctx.textAlign = textStyle.textAlign;
_this.ctx.textBaseline = textStyle.textBaseline;
var fontText = '';
fontText += textStyle.size + 'pt ';
fontText += textStyle.family + ' ';
if (textStyle.bold)
fontText += 'bold ';
if (textStyle.italics)
fontText += 'italic ';
_this.ctx.font = fontText;
return _this.ctx.measureText(text);
}
CanvasGrid.drawImage = function (_this, x0, y0, x1, y1, image) {
var tmpStartRow = _this.state.dynamicProperties.rowStartIndex;
var tmpStartCol = _this.state.dynamicProperties.colStartIndex;
var imageObj = new Image();
imageObj.onload = function () {
if (tmpStartRow === _this.state.dynamicProperties.rowStartIndex && tmpStartCol === _this.state.dynamicProperties.colStartIndex) {
_this.mainCtx.drawImage(imageObj, x0, y0, x1 - x0, y1 - y0);
_this.ctx.drawImage(imageObj, x0, y0, x1 - x0, y1 - y0);
}
};
imageObj.src = image.url;//'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
//var imageObj = new Image();
//imageObj.onload = function () {
// if (tmpStartRow === _this.state.dynamicProperties.rowStartIndex && tmpStartCol === _this.state.dynamicProperties.colStartIndex) {
// _this.mainCtx.drawImage(imageObj, x0, y0, x1 - x0, y1 - y0);
// _this.ctx.drawImage(imageObj, x0, y0, x1 - x0, y1 - y0);
// }
//};
//imageObj.src = "thumbnail.png";//'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
}
CanvasGrid.drawText = function (_this, x0, y0, x1, y1, cellValue, textStyle) {
_this.ctx.textAlign = textStyle.textAlign;
_this.ctx.textBaseline = textStyle.textBaseline;
var fontText = '';
fontText += textStyle.size + 'pt ';
fontText += textStyle.family + ' ';
if (textStyle.bold)
fontText += 'bold ';
if (textStyle.italics)
fontText += 'italic ';
_this.ctx.font = fontText;
var text = cellValue;
var offsetX = 0;
var offsetY = 0;
_this.ctx.fillStyle = textStyle.color;
if (textStyle.wrap === 0) {
if (_this.ctx.textAlign == 'left') {
offsetX = 5;
}
else if (_this.ctx.textAlign == 'right') {
offsetX = (x1 - x0) - 5;
}
else if (_this.ctx.textAlign == 'center') {
offsetX = ((x1 - x0) / 2);
}
if (_this.ctx.textBaseline == 'bottom') {
offsetY = (y1 - y0) - 1;
}
else if (_this.ctx.textBaseline == 'top') {
offsetY = 1;
}
else if (_this.ctx.textBaseline == 'middle') {
offsetY = ((y1 - y0) / 2);
}
_this.ctx.fillText(text, x0 + offsetX, y0 + offsetY);
}
else if (textStyle.wrap === 2) {
var measure = _this.ctx.measureText(text);
var currWidth = measure.width + 10;
if (currWidth > _this.state.gridProperties.width - _this.state.dynamicProperties.freezeX) {
currWidth = _this.state.gridProperties.width - _this.state.dynamicProperties.freezeX;
}
var maxWidth = (x1 - x0);
if (maxWidth < currWidth) {
maxWidth = currWidth;
x1 = (maxWidth + x0);
}
if (_this.ctx.textAlign == 'left') {
offsetX = 5;
}
else if (_this.ctx.textAlign == 'right') {
offsetX = (x1 - x0) - 5;
}
else if (_this.ctx.textAlign == 'center') {
offsetX = ((x1 - x0) / 2);
}
if (_this.ctx.textBaseline == 'bottom') {
offsetY = (y1 - y0) - 1;
}
else if (_this.ctx.textBaseline == 'top') {
offsetY = 1;
}
else if (_this.ctx.textBaseline == 'middle') {
offsetY = ((y1 - y0) / 2);
}
_this.ctx.fillText(text, x0 + offsetX, y0 + offsetY);
}
else {
var finalLines = [];
var words = text.split(' ');
var currText = '';
var maxWidth = (x1 - x0) - 10;;
var maxHeight = textStyle.size + parseInt(textStyle.size / 2.5);
words.forEach(function (word) {
var measure = _this.ctx.measureText(currText + word);
var currWidth = measure.width;
var currHeight = measure.height;
if (currHeight > maxHeight)
maxHeight = currHeight;
if (maxWidth < currWidth) {
for (var c = 0; c < word.length; c++) {
var char = word[c];
measure = _this.ctx.measureText(currText + char);
currWidth = measure.width;
currHeight = measure.height;
if (currHeight > maxHeight)
maxHeight = currHeight;
if (maxWidth < currWidth) {
finalLines.push(currText);
currText = '';
}
currText += char;
}
word = '';
}
currText += word + ' ';
});
finalLines.push(currText);
currText = '';
var finalMaxHeight = maxHeight * finalLines.length;
if (finalMaxHeight > _this.state.gridProperties.height - _this.state.gridProperties.freezeY) {
finalMaxHeight = _this.state.gridProperties.height - _this.state.gridProperties.freezeY;
}
if ((y1 - y0) < (finalMaxHeight))
y1 = finalMaxHeight + y0;
if (_this.ctx.textAlign == 'left') {
offsetX = 5;
}
else if (_this.ctx.textAlign == 'right') {
offsetX = (x1 - x0) - 5;
}
else if (_this.ctx.textAlign == 'center') {
offsetX = ((x1 - x0) / 2);
}
if (_this.ctx.textBaseline == 'bottom') {
offsetY = ((y1 - y0) - 1) - ((finalLines.length - 1) * maxHeight);
}
else if (_this.ctx.textBaseline == 'top') {
offsetY = 1;
}
else if (_this.ctx.textBaseline == 'middle') {
offsetY = ((y1 - y0) / 2) - ((finalLines.length - 1) / 2 * maxHeight);
}
finalLines.forEach(function (singleLine, index) {
_this.ctx.fillText(singleLine, x0 + offsetX, y0 + offsetY + (index * maxHeight));
});
}
return [x1 - x0, y1 - y0];
}
CanvasGrid.setCallbackMethod = function (eventName, cb) {
var _this = this;
_this.callbackMethods[eventName] = { callback: cb, counter: 0 };
}
CanvasGrid.getInitialState = function () {
var defaultBackground = {
color: '#FCFCFC',
img: null
};
var defaultBorderSingle = {
width: 1,
style: 'solid',
color: 'black'
};
var defaultBorder = {
left: utilLibrary.extend(true, {}, defaultBorderSingle),
right: utilLibrary.extend(true, {}, defaultBorderSingle),
top: utilLibrary.extend(true, {}, defaultBorderSingle),
bottom: utilLibrary.extend(true, {}, defaultBorderSingle)
}
var containerProperties = {
proposedHeight: 500,
proposedWidth: 500,
height: 0,
width: 0,
background: utilLibrary.extend(true, {}, defaultBackground),
border: utilLibrary.extend(true, {}, defaultBorder)
}
var defaultTextStyle = {
textAlign: 'center',
textBaseline: 'middle',
size: 11,
family: 'Calibri',
bold: false,
italics: false,
color: 'black',
wrap: 0 // 0-> no wrap, 1-> wrap text, 2-> auto fit
};
var gridProperties = {
height: 0,
width: 0,
rows: 1,
cols: 1,
background: utilLibrary.extend(true, {}, defaultBackground),
border: utilLibrary.extend(true, {}, defaultBorderSingle)
}
var cellProperties = {
height: 18,
width: 100,
//background: utilLibrary.extend(true, {}, defaultBackground),
//border: utilLibrary.extend(true, {}, defaultBorder),
textStyle: utilLibrary.extend(true, {}, defaultTextStyle)
}
//var headerProperties = {
// height: 18,
// width: 100,
// background: utilLibrary.extend(true, utilLibrary.extend(true, {}, defaultBackground), { color: '#EFEFEF' }),
// border: utilLibrary.extend(true, {}, defaultBorder),
// textStyle: utilLibrary.extend(true, utilLibrary.extend(true, {}, defaultTextStyle), { textAlign: 'center' })
//}
var dynamicProperties = {
//lastRowStartIndex: -1,
//lastRolStartIndex: -1,
//lastCowEndIndex: -1,
//lastColEndIndex: -1,
//lastFreezeRowIndex: -1,
//lastFreezeColIndex: -1,
rowStartIndex: 0,
colStartIndex: 0,
rowEndIndex: 0,
colEndIndex: 0,
freezeRowIndex: 0,
freezeColIndex: 0
}
var defaultState = {
containerProperties: containerProperties,
gridProperties: gridProperties,
cellProperties: cellProperties,
dynamicProperties: dynamicProperties
}
return utilLibrary.extend(true, {}, defaultState);
}
document.registerElement('canvas-grid', {
prototype: CanvasGrid
});
var utilLibrary = {
extend: function () {
var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false,
toString = Object.prototype.toString,
hasOwn = Object.prototype.hasOwnProperty,
push = Array.prototype.push,
slice = Array.prototype.slice,
trim = String.prototype.trim,
indexOf = Array.prototype.indexOf,
class2type = {
"[object Boolean]": "boolean",
"[object Number]": "number",
"[object String]": "string",
"[object Function]": "function",
"[object Array]": "array",
"[object Date]": "date",
"[object RegExp]": "regexp",
"[object Object]": "object"
},
jQ = {
isFunction: function (obj) {
return jQ.type(obj) === "function"
},
isArray: Array.isArray ||
function (obj) {
return jQ.type(obj) === "array"
},
isWindow: function (obj) {
return obj != null && obj == obj.window
},
isNumeric: function (obj) {
return !isNaN(parseFloat(obj)) && isFinite(obj)
},
type: function (obj) {
return obj == null ? String(obj) : class2type[toString.call(obj)] || "object"
},
isPlainObject: function (obj) {
if (!obj || jQ.type(obj) !== "object" || obj.nodeType) {
return false
}
try {
if (obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
return false
}
} catch (e) {
return false
}
var key;
for (key in obj) { }
return key === undefined || hasOwn.call(obj, key)
}
};
if (typeof target === "boolean") {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (typeof target !== "object" && !jQ.isFunction(target)) {
target = {}
}
if (length === i) {
target = this;
--i;
}
for (i; i < length; i++) {
if ((options = arguments[i]) != null) {
for (name in options) {
src = target[name];
copy = options[name];
if (target === copy) {
continue
}
if (deep && copy && (jQ.isPlainObject(copy) || (copyIsArray = jQ.isArray(copy)))) {
if (copyIsArray) {
copyIsArray = false;
clone = src && jQ.isArray(src) ? src : []
} else {
clone = src && jQ.isPlainObject(src) ? src : {};
}
// WARNING: RECURSION
target[name] = utilLibrary.extend(deep, clone, copy);
} else if (copy !== undefined) {
target[name] = copy;
}
}
}
}
return target;
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0">
<title>Title of the document</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/0.7.22/webcomponents-lite.min.js"></script>
<script src="//d3js.org/d3.v3.js"></script>
<script src="CanvasGrid.v2.js"></script>
<script>
function setEventCallback(gridSelector) {
var grid = document.querySelector(gridSelector);
var numRows = 1000000;
var numCols = 100;
var data = new Array(numRows);
//grid.setCallbackMethod('getCellValue', function (rowNumber, colNumber) {
// if (data != undefined && data[rowNumber] != undefined && data[rowNumber][colNumber] != undefined) {
// //return data[rowNumber][colNumber];
// return rowNumber+"_"+colNumber;
// }
// return null;
//});
grid.setCallbackMethod('getData', function (ref, nullValues, cb) {
var rows = Object.keys(nullValues);
rows.forEach(function (rowIndex) {
var cols = Object.keys(nullValues[rowIndex]);
cols.forEach(function (colIndex) {
var value = null;
if (rowIndex == 0) {
if (colIndex == 0) {
value = {
text: "",
cellProperties: {
background: { color: '#EFEFEF' },
textStyle: { textAlign: 'center', wrap: 2 }
}
};
}
else {//Column Header AZ
value = {
text: getAlphaColumnHeader(colIndex - 1, ""),
cellProperties: {
background: { color: '#EFEFEF' },
textStyle: { textAlign: 'center', wrap: 2 }
}
};
}
}
else if (rowIndex == 1) {
if (colIndex == 0) {
value = {
text: "",
cellProperties: {
background: { color: '#EFEFEF' },
textStyle: { textAlign: 'center', wrap: 2 }
}
};
}
else {//Column Name
value = {
text: "Column " + (colIndex),
cellProperties: {
background: { color: '#EFEFEF' },
textStyle: { textAlign: 'center', wrap: 2 }
}
}
}
}
else {
//Row Header
if (colIndex == 0) {
value = {
text: (rowIndex - 1).toString(),
cellProperties: {
background: { color: '#EFEFEF' },
textStyle: { textAlign: 'center', wrap: 2 }
}
}
}
else {
value = {
//text: "Column value for " + (rowIndex - 1).toString() + "_" + (colIndex).toString(),
text: (rowIndex - 1).toString() + "_" + (colIndex).toString(),
//text: "the nexus 5 is the best phone in this price range, it does come with a small battery & the camera is not the best considering other flagship models but the fact that you get the latest chipset from qualcomm & the adreno 330 gpu along with 2gb ram & most important of all updates from google for the next 18 months at least makes this phone a value for money product, another stand out feature for me is corning gorilla glass 3 which means a screen guard is not required for the screen however some may disagree.",
cellProperties: {
//height: 20 + (5 * (rowIndex - 1)),
//width: 50 + (20 * (colIndex)),
//background: { color: '#FCFCFC', img: null },
border: (colIndex % 3 == 1 && rowIndex % 3 == 1) ? {
left: { width: 1, style: 'solid', color: 'blue' },
right: { width: 1, style: 'solid', color: 'green' },
top: { width: 1, style: 'solid', color: 'red' },
bottom: { width: 1, style: 'solid', color: 'cyan' }
} : {},
textStyle: {
textAlign: (colIndex < 5 ? 'center' : colIndex < 10 ? 'left' : 'right'),
textBaseline: (colIndex < 5 ? 'middle' : colIndex < 10 ? 'top' : 'bottom'),
size: (colIndex < 5 ? 8 : colIndex < 10 ? 11 : 15),
//family: 'Calibri',
//bold: (colIndex < 10 ? false : true),
//italics: (colIndex < 10 ? false : true),
color: (colIndex < 5 ? 'black' : colIndex < 10 ? 'green' : 'blue'),
wrap: (colIndex < 2 ? 0 : colIndex < 15 ? 1 : 2)
}
}
}
}
}
nullValues[rowIndex][colIndex] = value;
if (data[rowIndex] == null) {
data[rowIndex] = new Array(numCols);
}
data[rowIndex][colIndex] = value;
});
});
setTimeout(function () {
cb(ref, nullValues);
}, 10);
});
//grid.setCallbackMethod('getRowHeight', function (rowIndex) {
// if (rowIndex % 5 === 0) {
// return 50;
// }
// else {
// return 10;
// }
//});
//grid.setCallbackMethod('getColumnWidth', function (colIndex) {
// if (colIndex % 2 === 0) {
// return 50;
// }
// else {
// return 25;
// }
//});
grid.setCallbackMethod('getCellValue', function (rowIndex, colIndex) {
var value = null;
if (rowIndex === 0) {
if (colIndex === 0) {
value = {
text: "",
cellProperties: {
background: { color: '#EFEFEF' },
textStyle: { textAlign: 'center', wrap: 2 }
}
};
}
else {//Column Header AZ
value = {
text: getAlphaColumnHeader(colIndex - 1, ""),
cellProperties: {
background: { color: '#EFEFEF' },
textStyle: { textAlign: 'center', wrap: 2 }
}
};
}
}
else if (rowIndex === 1) {
if (colIndex === 0) {
value = {
text: "",
cellProperties: {
background: { color: '#EFEFEF' },
textStyle: { textAlign: 'center', wrap: 2 }
}
};
}
else {//Column Name
value = {
text: "Column " + (colIndex),
cellProperties: {
background: { color: '#EFEFEF' },
textStyle: { textAlign: 'center', wrap: 2 }
}
}
}
}
else {
//Row Header
if (colIndex === 0) {
value = {
text: (rowIndex - 1).toString(),
cellProperties: {
background: { color: '#EFEFEF' },
textStyle: { textAlign: 'center', wrap: 2 }
}
}
}
else if (data != undefined && data[rowIndex] != undefined && data[rowIndex][colIndex] != undefined) {
value = data[rowIndex][colIndex];
//value = null;
//value = rowIndex + "_" + colIndex
}
}
return value;
});
grid.setAttribute('rows', numRows);
grid.setAttribute('cols', numCols);
//debugger;
grid.setAttribute('width', (window.innerWidth - 20) + 'px');
grid.setAttribute('height', (window.innerHeight - 20) + 'px');
}
var getAlphaColumnHeader = function (i, s) {
var rem = i % 26;
s = String.fromCharCode(65 + rem) + s;
i = i / 26 - 1;
return i < 0 ? s : getAlphaColumnHeader(i, s);
}
setTimeout(function () {
setEventCallback('#grid1');
}, 1);
function clearContent() {
d3.selectAll('#events *').remove();
}
</script>
</head>
<body>
<canvas-grid id="grid1" width="500px" height="200px" gridlinescolor="#000000" backgroundcolor="#FFFFFF" rowstartindex="0" colstartindex="0" rowheight="22" colwidth="20" rows="0" cols="0" freezerowindex="2" freezecolindex="1"></canvas-grid>
<!--<img id="canvasImg" alt="Right click to save me!" style="margin-top:20px; border:2px">-->
<!--<div>
<canvas-grid id="grid2" width="800px" height="300px" rows="50" cols="50" gridlinescolor="green"></canvas-grid>
</div>-->
<!--<input type="button" onclick="clearContent()" value="clear" />
<div id="events">
</div>-->
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment