From 28995d4f3ba66253c60ee965cdb6513c4f3b6b50 Mon Sep 17 00:00:00 2001 From: Tony Germaneri Date: Sat, 3 Dec 2016 20:57:46 -0800 Subject: [PATCH] clip input, changed selection behavior to more closely match expected --- README.md | 2 + bower.json | 2 +- lib/main.js | 134 +++++++++++++++++++++++++++++++------------------ package.json | 2 +- sample/main.js | 3 +- 5 files changed, 90 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 15531605..e4661750 100644 --- a/README.md +++ b/README.md @@ -852,3 +852,5 @@ Changing a style will automatically call `draw`. | rowHeaderCellHoverBackgroundColor | rgba(181, 201, 223, 1) | | rowHeaderCellSelectedColor | rgba(43, 48, 153, 1) | | rowHeaderCellSelectedBackgroundColor | rgba(182, 205, 250, 1) | +| scrollBarWidth | 14 | +| scrollDivOverlap | 1.6 | diff --git a/bower.json b/bower.json index 33277ba2..1a0d8a1c 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "canvas-datagrid", "main": "lib/main.js", - "version": "0.9.7", + "version": "0.9.8", "ignore": [ "**/.*", "node_modules", diff --git a/lib/main.js b/lib/main.js index ce6acc3b..396185e3 100644 --- a/lib/main.js +++ b/lib/main.js @@ -33,6 +33,8 @@ define([], function context() { ['showRowHeaders', true] ], defaultStyles = [ + ['scrollBarWidth', 14], + ['scrollDivOverlap', 1.6], ['filterTextPrefix', '(filtered)'], ['editCellFontSize', '16px'], ['editCellFontFamily', 'sans-serif'], @@ -353,23 +355,21 @@ define([], function context() { }); return m; } - function setScrollHeight() { + function setScrollArea() { var cellBorder = style.cellBorderWidth * 2, - headerCellHeight = sizes.rows[-1] || style.headerCellHeight; + headerCellBorder = style.headerCellBorderWidth * 2; scrollHeight = data.reduce(function reduceData(accumulator, row) { return accumulator + (sizes.rows[row[uniqueId]] || style.cellHeight) + cellBorder; }, 0) || 0; scrollWidth = (schema || tempSchema).reduce(function reduceSchema(accumulator, column) { - return accumulator + column.width + cellBorder; + if (column.hidden) { return accumulator; } + return accumulator + (sizes.columns[column.name] || column.width || style.columnWidth) + cellBorder; }, 0) || 0; if (attributes.showNewRow) { scrollHeight += style.cellHeight + cellBorder; } - style.headerRowWidth = findColumnMaxTextLength('cornerCell'); - scrollBox.style.height = container.offsetHeight - headerCellHeight - (style.headerCellBorderWidth * 2) + 'px'; - scrollBox.style.top = headerCellHeight + (style.headerCellBorderWidth * 2) + 'px'; - scrollArea.style.height = headerCellHeight + scrollHeight + 'px'; - scrollArea.style.width = scrollWidth + 'px'; + scrollArea.style.height = scrollHeight - headerCellBorder + style.scrollDivOverlap + 'px'; + scrollArea.style.width = scrollWidth - style.scrollBarWidth + 'px'; } function draw() { if (!container.parentNode @@ -379,7 +379,8 @@ define([], function context() { } var checkScrollHeight, borderWidth, rowHeaderCell, p, cx, cy, cellHeight, cornerCell, y, x, c, h, w, s, r, rd, l = data.length, - headerCellHeight = sizes.rows[-1] || style.headerCellHeight; + headerCellHeight = sizes.rows[-1] || style.headerCellHeight, + headerCellWidth = sizes.columns.cornerCell || style.headerRowWidth; if (attributes.showPerformance) { p = performance.now(); } @@ -391,7 +392,6 @@ define([], function context() { y = scrollBox.scrollTop * -1 + headerCellHeight + scrollPixelTop; h = canvas.height = height; w = canvas.width = width; - ctx.textBaseline = 'alphabetic'; ctx.fillStyle = style.backgroundColor; ctx.fillRect(0, 0, w, h); function drawCell(d, rowIndex) { @@ -531,7 +531,7 @@ define([], function context() { } cellHeight = sizes.rows[rd[uniqueId]] || style.cellHeight; if (attributes.showRowHeaders) { - x = sizes.columns.cornerCell || style.headerRowWidth; + x = headerCellWidth; } s.forEach(drawCell(rd, r)); drawRowHeader(rd, r); @@ -540,7 +540,7 @@ define([], function context() { } if (attributes.showNewRow) { if (attributes.showRowHeaders) { - x = sizes.columns.cornerCell || style.headerRowWidth; + x = headerCellWidth; } s.forEach(function forEachHeader(header, index) { drawCell(newRow, data.length)(header, index); @@ -550,7 +550,7 @@ define([], function context() { y = 0; if (attributes.showHeaders) { if (attributes.showRowHeaders) { - x = sizes.columns.cornerCell || style.headerRowWidth; + x = headerCellWidth; } s.forEach(function forEachHeader(header, index) { var d = { @@ -581,16 +581,67 @@ define([], function context() { } } if (checkScrollHeight) { - setScrollHeight(); + setScrollArea(); } if (attributes.showPerformance) { ctx.fillStyle = 'black'; ctx.strokeStyle = 'white'; p = (performance.now() - p).toFixed(2) + 'ms'; ctx.font = '33px sans-serif'; - ctx.fillText(p, w - 200, h - 50); - ctx.strokeText(p, w - 200, h - 50); + ctx.fillText(p, w - (w / 5), h - (h / 10)); + ctx.strokeText(p, w - (w / 5), h - (h / 10)); + } + } + function resize() { + var h, + headerCellHeight = sizes.rows[-1] || style.headerCellHeight, + headerCellWidth = sizes.columns.cornerCell || style.headerRowWidth, + headerCellBorder = style.headerCellBorderWidth * 2; + h = (attributes.height === undefined ? + Math.min(container.parentNode.offsetHeight, window.innerHeight) : attributes.height); + if (attributes.maxHeight !== undefined && h > attributes.maxHeight) { + h = attributes.maxHeight; + } + if (h < style.minHeight) { + h = style.minHeight; } + if (fire('resize', [h, width], intf)) { return false; } + container.style.height = h + 'px'; + height = container.offsetHeight; + width = container.offsetWidth; + scrollBox.style.width = container.offsetWidth - headerCellWidth + 'px'; + scrollBox.style.height = container.offsetHeight - headerCellHeight - headerCellBorder + + style.scrollDivOverlap + 'px'; + scrollBox.style.top = headerCellHeight + headerCellBorder + - style.scrollDivOverlap + 'px'; + scrollBox.style.left = headerCellWidth + 'px'; + draw(); + return true; + } + function clipInput() { + var clipRect = { + x: 0, + y: 0, + h: 0, + w: 0 + }, + headerCellHeight = sizes.rows[-1] || style.headerCellHeight, + headerCellWidth = sizes.columns.cornerCell || style.headerRowWidth; + clipRect.h = input.offsetHeight; + clipRect.w = input.offsetWidth; + input.style.top = scrollEdit.inputTop + + (scrollEdit.scrollTop - scrollBox.scrollTop) + 'px'; + input.style.left = scrollEdit.inputLeft + + (scrollEdit.scrollLeft - scrollBox.scrollLeft) + 'px'; + clipRect.x = (input.offsetLeft * -1) + headerCellWidth; + clipRect.y = (input.offsetTop * -1) + headerCellHeight; + debugmessage = (input.offsetLeft + ', ' + JSON.stringify(clipRect)); + input.style.clipPath = 'polygon(' + + clipRect.x + 'px ' + clipRect.y + 'px,' + + clipRect.x + 'px ' + clipRect.h + 'px,' + + clipRect.w + 'px ' + clipRect.h + 'px,' + + clipRect.w + 'px ' + clipRect.y + 'px' + + ')'; } function scroll() { var cellBorder = style.cellBorderWidth * 2; @@ -605,10 +656,7 @@ define([], function context() { ellipsisCache = {}; draw(); if (input) { - input.style.top = scrollEdit.inputTop - + (scrollEdit.scrollTop - scrollBox.scrollTop) + 'px'; - input.style.left = scrollEdit.inputLeft - + (scrollEdit.scrollLeft - scrollBox.scrollLeft) + 'px'; + clipInput(); } } function getHeaderByName(name) { @@ -717,16 +765,17 @@ define([], function context() { } if (selecting && o.context === 'cell' - && o.data - && (dragStartObject.rowIndex !== o.rowIndex - || dragStartObject.columnIndex !== o.columnIndex)) { - ignoreNextClick = true; + && o.data) { dragBounds = { top: Math.min(dragStartObject.rowIndex, o.rowIndex), left: Math.min(dragStartObject.columnIndex, o.columnIndex), bottom: Math.max(dragStartObject.rowIndex, o.rowIndex), right: Math.max(dragStartObject.columnIndex, o.columnIndex) }; + if (dragStartObject.rowIndex !== o.rowIndex + || dragStartObject.columnIndex !== o.columnIndex) { + ignoreNextClick = true; + } if (!selectionBounds || (dragBounds.top !== selectionBounds.top || dragBounds.left !== selectionBounds.left || dragBounds.bottom !== selectionBounds.bottom @@ -780,7 +829,7 @@ define([], function context() { data = originalData.filter(function (row) { return currentFilter(row[filterBy], filterValue); }); - setScrollHeight(); + setScrollArea(); draw(); } function contextmenu(e) { @@ -890,6 +939,9 @@ define([], function context() { }); } }); + filterInput.addEventListener('dblclick', function (e) { + e.stopPropagation(); + }); filterInput.addEventListener('click', function (e) { e.stopPropagation(); }); @@ -986,7 +1038,7 @@ define([], function context() { function addRow(d) { originalData.push(d); setFilter(filterBy, filterValue); - setScrollHeight(); + setScrollArea(); } function endEdit(abort) { var cell = input.editCell, @@ -1046,6 +1098,7 @@ define([], function context() { input.style.zIndex = '2'; input.value = cell.value; input.editCell = cell; + clipInput(); input.focus(); input.addEventListener('keydown', function (e) { var nx = cell.columnIndex, @@ -1199,10 +1252,11 @@ define([], function context() { ellipsisCache = {}; } function stopDragResize() { - setScrollHeight(); + setScrollArea(); document.body.removeEventListener('mousemove', dragResizeColumn, false); document.body.removeEventListener('mouseup', stopDragResize, false); setStorageData(); + draw(); ignoreNextClick = true; } function mousedown(e) { @@ -1215,6 +1269,7 @@ define([], function context() { dragStartObject = getCellAt(dragStart.x, dragStart.y); if (resizeMode === 'cell') { selecting = true; + mousemove(e); } if (['ns-resize', 'ew-resize'].indexOf(resizeMode) !== -1) { resizingItem = resizeItem; @@ -1331,28 +1386,6 @@ define([], function context() { defaults(style, args.style || {}, i[0], i[1]); }); } - function resize() { - var h, headerCellHeight = sizes.rows[-1] || style.headerCellHeight; - h = (attributes.height === undefined ? - Math.min(container.parentNode.offsetHeight, window.innerHeight) : attributes.height); - if (attributes.maxHeight !== undefined && h > attributes.maxHeight) { - h = attributes.maxHeight; - } - if (h < style.minHeight) { - h = style.minHeight; - } - if (fire('resize', [h, width], intf)) { return false; } - container.style.height = h + 'px'; - // this has to be done in this strange order because altering scrollBox changes the width of container - scrollBox.style.height = container.offsetHeight - headerCellHeight - (style.headerCellBorderWidth * 2) + 'px'; - scrollBox.style.width = container.offsetWidth + 'px'; - height = container.offsetHeight; - width = container.offsetWidth; - scrollBox.style.top = headerCellHeight + (style.headerCellBorderWidth * 2) + 'px'; - scrollBox.style.left = '0px'; - draw(); - return true; - } function autosize(colName) { getVisibleSchema().forEach(function (col) { if (col.name === colName || colName === undefined) { @@ -1418,6 +1451,7 @@ define([], function context() { scrollArea = document.createElement('div'); canvas = document.createElement('canvas'); ctx = canvas.getContext('2d'); + ctx.textBaseline = 'alphabetic'; container.className = 'canvas-datagrid'; scrollBox.className = 'canvas-datagrid-scrollBox'; [scrollBox, canvas, controlInput].forEach(function eachEle(el) { @@ -1642,7 +1676,7 @@ define([], function context() { && storedSettings === undefined) { autosize(); } - setScrollHeight(); + setScrollArea(); if (!resize()) { draw(); } } }); diff --git a/package.json b/package.json index e0fad64a..47e89779 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "canvas-datagrid", - "version": "0.9.7", + "version": "0.9.8", "description": "Canvas based data grid", "main": "./lib/main.js", "scripts": { diff --git a/sample/main.js b/sample/main.js index 00485daa..2954b11d 100644 --- a/sample/main.js +++ b/sample/main.js @@ -63,7 +63,8 @@ document.addEventListener('DOMContentLoaded', function () { ctx.strokeStyle = 'red'; } if (/Elend/.test(cell.value) && cell.style !== 'headerCell') { - ctx.fillStyle = 'red'; + ctx.strokeStyle = 'red'; + ctx.fillStyle = 'pink'; } }); grid.addEventListener('click', function (e, cell, menuItems, menuElement) {