Skip to content

Commit

Permalink
aggregation state summary
Browse files Browse the repository at this point in the history
  • Loading branch information
sgratzl committed Dec 27, 2018
1 parent 8c843e7 commit 4ac544f
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 76 deletions.
3 changes: 1 addition & 2 deletions src/provider/ADataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,7 @@ abstract class ADataProvider extends AEventDispatcher implements IDataProvider {
this.fire([ADataProvider.EVENT_GROUP_AGGREGATION_CHANGED, ADataProvider.EVENT_DIRTY_VALUES, ADataProvider.EVENT_DIRTY], ranking, group, value);
}

aggregateAllOf(ranking: Ranking, aggregateAll: boolean | number | EAggregationState) {
aggregateAllOf(ranking: Ranking, aggregateAll: boolean | number | EAggregationState, groups = ranking.getGroups()) {
let v: number;
if (typeof aggregateAll === 'boolean') {
v = aggregateAll ? 0 : -1;
Expand All @@ -767,7 +767,6 @@ abstract class ADataProvider extends AEventDispatcher implements IDataProvider {
v = aggregateAll;
}

const groups = ranking.getGroups();
for(const group of groups) {
this.unaggregateParents(ranking, group);
const current = this.getTopNAggregated(ranking, group);
Expand Down
2 changes: 1 addition & 1 deletion src/provider/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export interface IDataProvider extends AEventDispatcher {

getAggregationState(ranking: Ranking, group: IGroup): EAggregationState;

aggregateAllOf(ranking: Ranking, aggregateAll: boolean | number | EAggregationState): void;
aggregateAllOf(ranking: Ranking, aggregateAll: boolean | number | EAggregationState, groups?: IGroup[]): void;

getTopNAggregated(ranking: Ranking, group: IGroup): number;

Expand Down
111 changes: 45 additions & 66 deletions src/renderer/AggregateGroupRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {IDataRow, IGroup, Column, AggregateGroupColumn, EAggregationState, IOrderedGroup} from '../model';
import {IDataRow, Column, AggregateGroupColumn, EAggregationState, IOrderedGroup} from '../model';
import {AGGREGATE, CANVAS_HEIGHT, cssClass} from '../styles';
import {IRenderContext, ICellRendererFactory} from './interfaces';
import {groupParents, toItemMeta} from '../model/internal';
Expand All @@ -8,23 +8,27 @@ function preventDefault(event: Event) {
event.stopPropagation();
}

function matchNodes(node: HTMLElement, group: IOrderedGroup, relativeIndex: number, col: AggregateGroupColumn) {
const parents = groupParents(group, relativeIndex >= 0 ? toItemMeta(relativeIndex, group) : 'first last');
function matchNodes(node: HTMLElement, length: number, clazz = 'agg-level') {
const doc = node.ownerDocument!;
const children = <HTMLElement[]>Array.from(node.children);
// add missing
for (let i = children.length; i < parents.length; ++i) {
for (let i = children.length; i < length; ++i) {
const child = doc.createElement('div');
child.classList.add(cssClass('agg-level'));
child.classList.add(cssClass(clazz));
children.push(child);
node.appendChild(child);
}
// remove too many
for (const r of children.splice(parents.length, children.length - parent.length)) {
for (const r of children.splice(length, children.length - length)) {
r.remove();
}
return children;
}

function renderGroups(node: HTMLElement, group: IOrderedGroup, relativeIndex: number, col: AggregateGroupColumn) {
const parents = groupParents(group, relativeIndex >= 0 ? toItemMeta(relativeIndex, group) : 'first last');
const children = matchNodes(node, parents.length);

// correct match
for (let i = 0; i < parents.length; ++i) {
const parent = parents[i];
const child = children[i];
Expand All @@ -38,7 +42,7 @@ function matchNodes(node: HTMLElement, group: IOrderedGroup, relativeIndex: numb
const isCollapsed = parent.meta === 'first last';
child.classList.toggle(cssClass('agg-expand'), isFirst);
child.classList.toggle(cssClass('agg-collapse'), isCollapsed);
child.title = isFirst ? 'Expand Group' : '';
child.title = isFirst ? (isCollapsed ? 'Expand Group' : 'Collapse Group') : '';

child.onclick = !isFirst ? null : (evt) => {
preventDefault(evt);
Expand All @@ -55,84 +59,59 @@ export default class AggregateGroupRenderer implements ICellRendererFactory {
return col instanceof AggregateGroupColumn;
}

create(col: AggregateGroupColumn, context: IRenderContext) {
const width = context.colWidth(col);
create(col: AggregateGroupColumn) {
return {
template: `<div><div class="${cssClass('agg-level')}"></div></div>`,
update(node: HTMLElement, _row: IDataRow, i: number, group: IOrderedGroup) {
matchNodes(node, group, i, col);
renderGroups(node, group, i, col);
},
render(ctx: CanvasRenderingContext2D, _row: IDataRow, _i: number, _group: IGroup) {
render(ctx: CanvasRenderingContext2D, _row: IDataRow, i: number, group: IOrderedGroup) {
const parents = groupParents(group, toItemMeta(i, group));
ctx.fillStyle = AGGREGATE.color;
// TODO draw all lines
ctx.fillRect(width - AGGREGATE.width, 0, AGGREGATE.strokeWidth, CANVAS_HEIGHT);
return Boolean(false);
for (let i = 0; i < parents.length; ++i) {
ctx.fillRect(AGGREGATE.levelWidth * i + AGGREGATE.levelOffset, 0, AGGREGATE.strokeWidth, CANVAS_HEIGHT);
}
return parents.some((d) => d.meta != null);
}
};
}

createGroup(col: AggregateGroupColumn, context: IRenderContext) {
const _showMore = context.provider.getShowTopN() > 0;
createGroup(col: AggregateGroupColumn) {
// const _showMore = context.provider.getShowTopN() > 0;
return {
template: `<div><div class="${cssClass('agg-level')}"></div></div>`,
update(node: HTMLElement, group: IOrderedGroup) {
matchNodes(node, group, -1, col);

// const children = <HTMLElement[]>Array.from(node.children);

// const toggleMore = children.pop()!;
renderGroups(node, group, -1, col);

// toggleMore.onclick = (event) => {
// preventDefault(event);
// col.setAggregated(group, isShowAll ? EAggregationState.EXPAND_TOP_N : EAggregationState.EXPAND);
// };

// const isGroupOnly = meta === 'first last';
// const isTopX = meta === 'first top';
// const isShowAll = !isGroupOnly && !isTopX;

// toggleMore.title = isTopX ? 'Show All' : 'Show Top';
// toggleMore.style.display = isGroupOnly || !showMore ? 'none' : null;
// toggleMore.classList.toggle(cssClass('agg-compress'), isShowAll);

// const toggleAggregate = children.pop()!;
// toggleAggregate.title = isGroupOnly ? 'Expand Group' : 'Collapse Group';
// toggleAggregate.classList.toggle(cssClass('agg-collapse'), isGroupOnly);
// toggleAggregate.onclick = (event) => {
// preventDefault(event);
// col.setAggregated(group, isGroupOnly ? EAggregationState.EXPAND_TOP_N: EAggregationState.COLLAPSE);
// };

// // multi level TODO
// {
// let g = group;
// while (g.parent && g.parent.subGroups[0] === g) {
// g = g.parent;
// const a = children.length > 0 ? children.pop()! : node.ownerDocument!.createElement('div');
// a.title = isGroupOnly ? 'Expand Group' : 'Collapse Group';
// a.classList.add(cssClass('agg-expand'));
// a.classList.toggle(cssClass('agg-collapse'), isGroupOnly);
// a.onclick = (event) => {
// preventDefault(event);
// col.setAggregated(g, isGroupOnly ? EAggregationState.EXPAND_TOP_N : EAggregationState.COLLAPSE);
// };
// node.insertAdjacentElement('afterbegin', a);
// }

// for(const child of children) {
// child.remove();
// }
// }
// TODO show all / show top behavior again
}
};
}

createSummary(col: AggregateGroupColumn, context: IRenderContext) {
return {
template: `<div><div class="${cssClass('agg-expand')}" title="Expand All Groups"></div><div class="${cssClass('agg-all')}" title="Show All"></div></div>`,
template: `<div><div class="${cssClass('agg-expand')}" title="Expand All Groups"></div></div>`,
update: (node: HTMLElement) => {
// const ranking = col.findMyRanker()!;
// const groups = ranking.getGroups();
const ranking = col.findMyRanker()!;
const groups = ranking.getGroups();
const gparents = groups.map((group) => groupParents(group, 'first last'));

const max = gparents.reduce((a, b) => Math.max(a, b.length), Number.NEGATIVE_INFINITY);
const children = matchNodes(node, max, 'agg-expand');

for (let i = 0; i < max; ++i) {
const child = children[i];
const subGroups = <IOrderedGroup[]>gparents.map((d) => d[i] ? d[i].group : null).filter((d) => d != null);

const isCollapsed = subGroups.every((d) => context.provider.getAggregationState(ranking, d) === EAggregationState.COLLAPSE);
child.classList.toggle(cssClass('agg-collapse'), isCollapsed);
child.title = isCollapsed ? 'Expand Group' : 'Collapse Group';

child.onclick = (evt) => {
preventDefault(evt);
context.provider.aggregateAllOf(ranking, isCollapsed ? EAggregationState.EXPAND : EAggregationState.COLLAPSE, subGroups);
};
}

// const toggleAggregate = <HTMLElement>node.firstElementChild!;
// const toggleMore = <HTMLElement>node.lastElementChild!;
Expand Down
2 changes: 2 additions & 0 deletions src/styles/_vars.scss
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ $lu_side_panel_font_size: 14px !default;
$lu_side_panel_toolbar_font_size: 9pt !default;
$lu_side_panel_separator_color: #dedede !default;

$lu_aggregate_level_offset: 2px !default;
$lu_aggregate_level_width: 22px !default;
$lu_aggregate_square_bracket_width: 8px !default;
$lu_aggregate_square_bracket_stroke_color: #000 !default;
$lu_aggregate_square_bracket_stroke_width: 2px !default;
Expand Down
6 changes: 4 additions & 2 deletions src/styles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ export const BOX_PLOT = {
/** @internal */
export const AGGREGATE = {
width: parseInt(getStyle('lu_aggregate_square_bracket_width', '4px'), 10),
strokeWidth: parseInt(getStyle('lu_aggregate_square_bracket_stroke_width', '1px'), 10),
color: getStyle('lu_aggregate_square_bracket_stroke_color', '#000')
strokeWidth: parseInt(getStyle('lu_aggregate_square_bracket_stroke_width', '2px'), 10),
color: getStyle('lu_aggregate_square_bracket_stroke_color', '#000'),
levelOffset: parseInt(getStyle('lu_aggregate_level_offset', '2px'), 10),
levelWidth: parseInt(getStyle('lu_aggregate_level_width', '22px'), 10)
};
/** @internal */
export const SLOPEGRAPH_WIDTH = parseInt(getStyle('lu_slope_width', '200px'), 10);
Expand Down
10 changes: 5 additions & 5 deletions src/styles/renderer/_aggregate.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@
}

.#{$lu_css_prefix}-agg-level {
flex: 0 0 1.4em;
position: relative;

// square bracket around
flex: 0 0 $lu_aggregate_level_width;
position: relative; // square bracket around
&::after {
content: '';
pointer-events: none;
position: absolute;
left: 2px;
left: $lu_aggregate_level_offset;
bottom: 0;
width: $lu_aggregate_square_bracket_width;
border-left: $lu_aggregate_square_bracket_stroke_width solid $lu_aggregate_square_bracket_stroke_color;
Expand All @@ -35,6 +33,8 @@
}

.#{$lu_css_prefix}-agg-expand {
flex: 0 0 $lu_aggregate_level_width;
position: relative;
color: $lu_toolbar_color_base;

&::before {
Expand Down

0 comments on commit 4ac544f

Please sign in to comment.