Skip to content

Commit

Permalink
Merge pull request #584 from ghiscoding/feat/drag-to-scroll-view
Browse files Browse the repository at this point in the history
feat(selection): auto-scroll the viewport when dragging with selection
  • Loading branch information
ghiscoding authored Dec 20, 2021
2 parents 27c617e + 1405ac8 commit 941e99c
Show file tree
Hide file tree
Showing 20 changed files with 1,455 additions and 61 deletions.
1 change: 1 addition & 0 deletions examples/webpack-demo-vanilla-bundle/src/app-routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class AppRouting {
{ route: 'example14', name: 'example14', title: 'Example14', moduleId: './examples/example14' },
{ route: 'example15', name: 'example15', title: 'Example15', moduleId: './examples/example15' },
{ route: 'example16', name: 'example16', title: 'Example16', moduleId: './examples/example16' },
{ route: 'example17', name: 'example17', title: 'Example17', moduleId: './examples/example17' },
{ route: 'icons', name: 'icons', title: 'icons', moduleId: './examples/icons' },
{ route: '', redirect: 'example01' },
{ route: '**', redirect: 'example01' }
Expand Down
5 changes: 4 additions & 1 deletion examples/webpack-demo-vanilla-bundle/src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ <h4 class="title is-4 has-text-white">Slickgrid-Universal</h4>
</div>

<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false"
data-target="navbarBasicExample">
data-target="navbarBasicExample">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
Expand Down Expand Up @@ -75,6 +75,9 @@ <h4 class="title is-4 has-text-white">Slickgrid-Universal</h4>
<a class="navbar-item" onclick.delegate="loadRoute('example16')">
Example16 - Regular & Custom Tooltips
</a>
<a class="navbar-item" onclick.delegate="loadRoute('example17')">
Example17 - Auto-Scroll for Selector
</a>
</div>
</div>
</div>
Expand Down
56 changes: 56 additions & 0 deletions examples/webpack-demo-vanilla-bundle/src/examples/example17.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<h3 class="title is-3">Example 17 - Auto-Scroll with Range Selector
<span class="subtitle">(with Salesforce Theme)</span>
<div class="subtitle" style="float: right; margin-top: -20px">
<a class="is-size-5" target="_blank"
href="https://github.com/ghiscoding/slickgrid-universal/blob/master/examples/webpack-demo-vanilla-bundle/src/examples/example17.ts">
<span class="mdi mdi-link mdi-v-align-sub"></span> code
</a>
</div>
</h3>
<h6 class="title is-6 italic">
Dragging from 2nd column to make a selection, and the viewport will auto scroll.
</h6>

<div style="min-height: 975px">
<div class="row scroll-configs">
<span>
<label for="min-internal">MIN interval to show next cell (ms): </label>
<input id="min-internal" type="number" data-test="min-interval-input" value.bind="minInterval" />
<label for="max-internal" style="margin-left: 15px;">MAX delay to show next cell (ms): </label>
<input id="max-internal" type="number" data-test="max-interval-input" value.bind="maxInterval" />
<label for="delay-cursor" style="margin-left: 15px;">Delay when cursor outside 1px (ms): </label>
<input id="delay-cursor" type="number" data-test="delay-cursor-input" value.bind="delayCursor" />
</span>
</div>
<div class="row" style="margin-bottom: 15px;">
<label for="is-autoscroll">Auto Scroll: (need click Set Options): </label>
<input id="is-autoscroll" type="checkbox" data-test="is-autoscroll-chk" checked.bind="isAutoScroll" />

<span style="margin-left: 20px;">
<button class="btn btn-default btn-xs" data-test="set-options-btn" onclick.delegate="setOptions()">
Set Options
</button>
<button class="btn btn-default btn-xs" data-test="default-options-btn" onclick.delegate="setDefaultOptions()">
Set Default Options
</button>
<button class="btn btn-default btn-xs" data-test="set-clear-frozen-btn" onclick.delegate="toggleFrozen()">
Set/Clear Frozen
</button>
<button class="btn btn-default btn-xs" data-test="set-clear-grouping-btn" onclick.delegate="toggleGroup()">
Set/Clear Grouping by Duration
</button>
</span>
</div>

<h5 class="title is-5">Grid 1 - Using <code>SlickCellRangeSelector</code></h5>
<div class="grid17-1">
</div>

<div class="column is-half">
<hr style="margin: 16px 0" />
</div>

<h5 class="title is-5">Grid 2 - Using <code>SlickCellRangeSelector</code> and <code>SlickRowSelectionModel</code></h5>
<div class="grid17-2">
</div>
</div>
39 changes: 39 additions & 0 deletions examples/webpack-demo-vanilla-bundle/src/examples/example17.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
$control-height: 2.4em;
@import 'bulma/bulma';

:root {
--slick-header-row-count: 1;
--slick-header-column-height: 17px;
}

.scroll-configs input {
width: 50px;
}
.cell-effort-driven {
text-align: center;
}
.slick-group-title[level='0'] {
font-weight: bold;
}
.slick-group-title[level='1'] {
text-decoration: underline;
}
.slick-group-title[level='2'] {
font-style: italic;
}
.slick-row:not(.slick-group) >.cell-unselectable {
background: #ececec !important;
}
.slick-row .slick-cell.frozen:last-child,
.slick-header-column.frozen:last-child,
.slick-headerrow-column.frozen:last-child,
.slick-footerrow-column.frozen:last-child {
border-right: 1px solid red;
}

.slick-row.frozen:last-child .slick-cell {
border-bottom: 1px solid red;
}
.option-item {
padding: 6px;
}
193 changes: 193 additions & 0 deletions examples/webpack-demo-vanilla-bundle/src/examples/example17.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import { Aggregators, Column, Formatters, GridOption, Grouping, GroupTotalFormatters, SlickCellRangeSelector, SlickCellSelectionModel, SlickRowSelectionModel } from '@slickgrid-universal/common';
import { Slicker, SlickVanillaGridBundle } from '@slickgrid-universal/vanilla-bundle';
import { ExampleGridOptions } from './example-grid-options';

// use any of the Styling Theme
import '../material-styles.scss';
// import '../salesforce-styles.scss';
import './example17.scss';

const NB_ITEMS = 300;

export class Example17 {
gridOptions1: GridOption;
gridOptions2: GridOption;
columnDefinitions1: Column[];
columnDefinitions2: Column[];
dataset1: any[];
dataset2: any[];
sgb1: SlickVanillaGridBundle;
sgb2: SlickVanillaGridBundle;
isAutoScroll = true;
minInterval = 30;
maxInterval = 600;
delayCursor = 5;

attached() {
this.defineGrids();

// mock some data (different in each dataset)
this.dataset1 = this.mockData(NB_ITEMS);
this.dataset2 = this.mockData(NB_ITEMS);

this.sgb1 = new Slicker.GridBundle(document.querySelector<HTMLDivElement>(`.grid17-1`), this.columnDefinitions1, { ...ExampleGridOptions, ...this.gridOptions1 }, this.dataset1);
this.sgb2 = new Slicker.GridBundle(document.querySelector<HTMLDivElement>(`.grid17-2`), this.columnDefinitions2, { ...ExampleGridOptions, ...this.gridOptions2 }, this.dataset2);

this.setOptions();
}

dispose() {
this.sgb1?.dispose();
this.sgb2?.dispose();
}

/* Define grid Options and Columns */
defineGrids() {
this.columnDefinitions1 = [
{ id: 'sel', name: '#', field: 'id', cssClass: 'cell-unselectable', resizable: false, selectable: false, focusable: false, width: 40 },
{ id: 'title', name: 'Title', field: 'title', cssClass: 'cell-title', sortable: true, width: 90, filterable: true },
{ id: 'duration', name: 'Duration', field: 'duration', width: 90, sortable: true, filterable: true, groupTotalsFormatter: GroupTotalFormatters.sumTotals },
{ id: '%', name: '% Complete', field: 'percentComplete', width: 90, sortable: true, filterable: true, formatter: Formatters.percentCompleteBar },
{ id: 'start', name: 'Start', field: 'start', formatter: Formatters.dateIso, width: 90, exportWithFormatter: true, filterable: true },
{ id: 'finish', name: 'Finish', field: 'finish', formatter: Formatters.dateIso, width: 90, exportWithFormatter: true, filterable: true },
{ id: 'cost', name: 'Cost', field: 'cost', formatter: Formatters.dollar, width: 90, exportWithFormatter: true, filterable: true },
{ id: 'effort-driven', name: 'Effort Driven', field: 'effortDriven', cssClass: 'cell-effort-driven', width: 90, formatter: Formatters.checkmarkMaterial, sortable: true, filterable: true }
];

for (let i = 0; i < 30; i++) {
this.columnDefinitions1.push({ id: `mock${i}`, name: `Mock${i}`, field: `mock${i}`, width: 90 });
}

this.gridOptions1 = {
enableAutoResize: false,
enableAutoSizeColumns: false,
autoFitColumnsOnFirstLoad: false,
autosizeColumnsByCellContentOnFirstLoad: true,
enableAutoResizeColumnsByCellContent: true,
enableCellNavigation: true,
enableColumnReorder: false,
editable: true,
asyncEditorLoading: false,
autoEdit: false,
enableGrouping: true,
gridHeight: 350,
gridWidth: 800,
rowHeight: 35,
frozenColumn: -1,
frozenRow: -1,
// enableExcelCopyBuffer: true,
};

// copy the same Grid Options and Column Definitions to 2nd grid
this.columnDefinitions2 = this.columnDefinitions1.slice();
this.gridOptions2 = {
...this.gridOptions1,
...{
// enableCheckboxSelector: true,
}
};
}

mockData(count: number) {
// mock a dataset
const mockDataset = [];
for (let i = 0; i < count; i++) {
const someDates = ['2009-01-01', '2009-02-02', '2009-03-03'];
mockDataset[i] = {
id: i,
title: 'Task ' + i,
duration: i % 20,
percentComplete: Math.round(Math.random() * 100),
start: someDates[Math.floor((Math.random() * 2))],
finish: someDates[Math.floor((Math.random() * 2))],
cost: Math.round(Math.random() * 10000) / 100,
effortDriven: (i % 5 === 0)
};
for (let j = 0; j < 30; j++) {
mockDataset[i]['mock' + j] = j;
}
}

return mockDataset;
}

groupByDuration1() {
this.sgb1.dataView.setGrouping({
getter: 'duration',
formatter: (g) => `Duration: ${g.value} <span style="color:green">(${g.count} items)</span>`,
aggregators: [
new Aggregators.Avg('percentComplete'),
new Aggregators.Sum('cost')
],
aggregateCollapsed: false,
lazyTotalsCalculation: true
} as Grouping);
}

groupByDuration2() {
this.sgb2.dataView.setGrouping({
getter: 'duration',
formatter: (g) => `Duration: ${g.value} <span style="color:green">(${g.count} items)</span>`,
aggregators: [
new Aggregators.Avg('percentComplete'),
new Aggregators.Sum('cost')
],
aggregateCollapsed: false,
lazyTotalsCalculation: true
} as Grouping);
}

setDefaultOptions() {
this.isAutoScroll = true;
this.minInterval = 30;
this.maxInterval = 600;
this.delayCursor = 5;
this.setOptions();
}

setOptions() {
this.sgb1.slickGrid.setSelectionModel(new SlickCellSelectionModel({
selectActiveCell: true,
cellRangeSelector: new SlickCellRangeSelector({
selectionCss: {
border: '2px dashed #01b83b'
} as CSSStyleDeclaration,
autoScroll: this.isAutoScroll,
minIntervalToShowNextCell: +this.minInterval,
maxIntervalToShowNextCell: +this.maxInterval,
accelerateInterval: +this.delayCursor
})
}));

this.sgb2.slickGrid.setSelectionModel(new SlickRowSelectionModel({
cellRangeSelector: new SlickCellRangeSelector({
selectionCss: {
border: 'none'
} as CSSStyleDeclaration,
autoScroll: this.isAutoScroll,
minIntervalToShowNextCell: +this.minInterval,
maxIntervalToShowNextCell: +this.maxInterval,
accelerateInterval: +this.delayCursor
})
}));
this.sgb1.slickGrid.invalidate();
this.sgb2.slickGrid.invalidate();
}

toggleGroup() {
(this.sgb1.dataView.getGrouping() && this.sgb1.dataView.getGrouping().length > 0) ? this.sgb1.dataView.setGrouping([]) : this.groupByDuration1();
(this.sgb2.dataView.getGrouping() && this.sgb2.dataView.getGrouping().length > 0) ? this.sgb2.dataView.setGrouping([]) : this.groupByDuration2();
}

toggleFrozen() {
const option = this.sgb1.slickGrid.getOptions();
const frozenRow = option.frozenRow;
const frozenColumn = option.frozenColumn;
const newOption = {
frozenColumn: frozenColumn === -1 ? 1 : -1,
frozenRow: frozenRow === -1 ? 3 : -1
};
this.sgb1.slickGrid.setOptions(newOption);
this.sgb2.slickGrid.setOptions(newOption);
}
}
Loading

0 comments on commit 941e99c

Please sign in to comment.