Skip to content

Instantly share code, notes, and snippets.

@mattborn
Last active June 26, 2020 23:12
Show Gist options
  • Save mattborn/8c0a2a4e6f74beef81eed98b6174c4fc to your computer and use it in GitHub Desktop.
Save mattborn/8c0a2a4e6f74beef81eed98b6174c4fc to your computer and use it in GitHub Desktop.
Pivot Prototype
<!doctype html>
<html>
<head>
<title>Pivot Prototype</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Faker/3.1.0/faker.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>
<script src="https://unpkg.com/moment"></script>
<script src="https://unpkg.com/@ag-grid-enterprise/all-modules/dist/ag-grid-enterprise.min.noStyle.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@ag-grid-community/all-modules/dist/styles/ag-grid.css">
<link rel="stylesheet" href="https://unpkg.com/@ag-grid-community/all-modules/dist/styles/ag-theme-alpine.css">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="Page-Section">
<h2>Example 1</h2>
<p>Many time periods per client, many trends per row group</p>
<div id="Example-1" class="ag-theme-alpine"></div>
</div>
<div class="Page-Section">
<h2>Example Data Quality Pivot Table</h2>
<p>Four dimensions: service month, paid month, carrier name, and tie out measures (sum claims, count distinct members)</p>
<div id="Reconcile" class="ag-theme-alpine"></div>
</div>
<script src="scripts.js"></script>
</body>
</html>
// wrap all direct body children innerHTML with div.Center
Array.from(document.body.children).forEach(child => {
const div = document.createElement('div')
div.className = 'Center'
while (child.firstChild) div.appendChild(child.firstChild)
child.appendChild(div)
})
const MONTHS = 12
const gridOptions_Shared = {
defaultColDef: {
flex: 1,
// enableRowGroup: true,
// enablePivot: true,
// filter: 'agTextColumnFilter',
resizable: true,
sortable: true,
},
autoGroupColumnDef: {
cellRendererParams: {
suppressCount: true,
},
minWidth: 200,
},
domLayout: 'autoHeight',
enableRangeSelection: true,
// floatingFilter: true,
// masterDetail: true,
onFirstDataRendered: (params) => params.api.sizeColumnsToFit(),
sideBar: 'columns',
}
const gridOptions_Reconcile = Object.assign({
columnDefs: [
{headerName: 'Service Month', field: 'service_month', comparator: dateComparator, rowGroup: true, enableRowGroup: true},
{headerName: 'Paid Month', field: 'paid_month', comparator: dateComparator, pivotComparator: dateComparator, rowGroup: true, enableRowGroup: true, enablePivot: true},
{headerName: 'Carrier', field: 'carrier', enablePivot: true},
{headerName: 'Employer Paid (Med)', field: 'dollars', aggFunc: 'sum'},
],
rowData: _.range(MONTHS * MONTHS).map(makeRow), // number of service months
}, gridOptions_Shared)
new agGrid.Grid(document.querySelector('#Reconcile'), gridOptions_Reconcile)
// functions
function makeRow(obj, i) {
const carriers = []
const serviceDate = moment().subtract(Math.ceil((i + 1) / MONTHS), 'month').valueOf()
return Object.assign(obj, {
service_month: moment(serviceDate).format('MMM YYYY'),
paid_month: moment().subtract(i % MONTHS + 1, 'month').format('MMM YYYY'),
// paid_month: moment(serviceDate + Math.random() * (moment().valueOf() - serviceDate)).format('MMM YYYY'),
carrier: faker.random.boolean() ? 'Aetna' : 'Cigna',
// sum: faker.phone.phoneNumber('#########'),
dollars: faker.random.number()
})
}
function dateComparator(date1, date2) {
var a = moment(date1, 'MMM YYYY').valueOf()
var b = moment(date2, 'MMM YYYY').valueOf()
if (a === null && b === null) return 0
if (a === null) return -1
if (b === null) return 1
return a - b
}
// simulate interactions
// gridOptions_Reconcile.columnApi.setPivotMode(true)
gridOptions_Reconcile.columnApi.setPivotColumns(['paid_month','carrier'])
gridOptions_Reconcile.columnApi.setRowGroupColumns(['service_month'])
// Example 1
const gridOptions_Example_1 = Object.assign({
columnDefs: [
{headerName: 'Client(s)', field: 'client', rowGroup: true, enableRowGroup: true},
{headerName: 'Time Period', field: 'time_period', rowGroup: true, enableRowGroup: true, enablePivot: true},
{headerName: 'Measure', field: 'measure', rowGroup: true, enableRowGroup: true},
{headerName: 'Data Category', field: 'category'},
{headerName: 'Trend', field: 'trend', aggFunc: 'first', hide: true},
],
rowData: [
{
client: 'Client A',
time_period: 'TP1 – TP2',
measure: 'Allowed Amount',
category: 'Overall Trend',
trend: '-0.5%',
},
{
client: 'Client A',
time_period: 'TP1 – TP2',
measure: 'Allowed Amount',
category: 'Medical Trend',
trend: '-0.6%',
},
{
client: 'Client A',
time_period: 'TP1 – TP2',
measure: 'Allowed Amount',
category: 'Pharmacy Trend',
trend: '-0.3%',
},
{
client: 'Client A',
time_period: 'TP1 – TP2',
measure: 'Member Cost Sharing',
category: 'Overall Trend',
trend: '-0.5%',
},
{
client: 'Client A',
time_period: 'TP1 – TP2',
measure: 'Member Cost Sharing',
category: 'Medical Trend',
trend: '-0.1%',
},
{
client: 'Client A',
time_period: 'TP1 – TP2',
measure: 'Member Cost Sharing',
category: 'Pharmacy Trend',
trend: '-3.4%',
},
{
client: 'Client A',
time_period: 'TP1 – TP2',
measure: 'Net Pay',
category: 'Overall Trend',
trend: '-0.1%',
},
{
client: 'Client A',
time_period: 'TP1 – TP2',
measure: 'Net Pay',
category: 'Medical Trend',
trend: '0.1%',
},
{
client: 'Client A',
time_period: 'TP1 – TP2',
measure: 'Net Pay',
category: 'Pharmacy Trend',
trend: '-0.7%',
},
{
client: 'Client A',
time_period: 'TP2 – TP3',
measure: 'Allowed Amount',
category: 'Overall Trend',
trend: '4.8%',
},
{
client: 'Client A',
time_period: 'TP2 – TP3',
measure: 'Allowed Amount',
category: 'Medical Trend',
trend: '4.7%',
},
{
client: 'Client A',
time_period: 'TP2 – TP3',
measure: 'Allowed Amount',
category: 'Pharmacy Trend',
trend: '5.1%',
},
{
client: 'Client A',
time_period: 'TP2 – TP3',
measure: 'Member Cost Sharing',
category: 'Overall Trend',
trend: '5.1%',
},
{
client: 'Client A',
time_period: 'TP2 – TP3',
measure: 'Member Cost Sharing',
category: 'Medical Trend',
trend: '4.7%',
},
{
client: 'Client A',
time_period: 'TP2 – TP3',
measure: 'Member Cost Sharing',
category: 'Pharmacy Trend',
trend: '7.6%',
},
{
client: 'Client A',
time_period: 'TP2 – TP3',
measure: 'Net Pay',
category: 'Overall Trend',
trend: '4.8%',
},
{
client: 'Client A',
time_period: 'TP2 – TP3',
measure: 'Net Pay',
category: 'Medical Trend',
trend: '4.9%',
},
{
client: 'Client A',
time_period: 'TP2 – TP3',
measure: 'Net Pay',
category: 'Pharmacy Trend',
trend: '4.3%',
},
{
client: 'Client A',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Allowed Amount',
category: 'Overall Trend',
trend: '2.1%',
},
{
client: 'Client A',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Allowed Amount',
category: 'Medical Trend',
trend: '2.0%',
},
{
client: 'Client A',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Allowed Amount',
category: 'Pharmacy Trend',
trend: '2.4%',
},
{
client: 'Client A',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Member Cost Sharing',
category: 'Overall Trend',
trend: '2.3%',
},
{
client: 'Client A',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Member Cost Sharing',
category: 'Medical Trend',
trend: '2.3%',
},
{
client: 'Client A',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Member Cost Sharing',
category: 'Pharmacy Trend',
trend: '1.9%',
},
{
client: 'Client A',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Net Pay',
category: 'Overall Trend',
trend: '2.3%',
},
{
client: 'Client A',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Net Pay',
category: 'Medical Trend',
trend: '2.5%',
},
{
client: 'Client A',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Net Pay',
category: 'Pharmacy Trend',
trend: '1.8%',
},
{
client: 'BoB',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Allowed Amount',
category: 'Overall Trend',
trend: '3.6%',
},
{
client: 'BoB',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Allowed Amount',
category: 'Medical Trend',
trend: '3.8%',
},
{
client: 'BoB',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Allowed Amount',
category: 'Pharmacy Trend',
trend: '2.6%',
},
{
client: 'BoB',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Member Cost Sharing',
category: 'Overall Trend',
trend: '1.1%',
},
{
client: 'BoB',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Member Cost Sharing',
category: 'Medical Trend',
trend: '3.1%',
},
{
client: 'BoB',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Member Cost Sharing',
category: 'Pharmacy Trend',
trend: '-5.5%',
},
{
client: 'BoB',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Net Pay',
category: 'Overall Trend',
trend: '3.6%',
},
{
client: 'BoB',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Net Pay',
category: 'Medical Trend',
trend: '3.7%',
},
{
client: 'BoB',
time_period: 'TP1 – TP3 (Annualized)',
measure: 'Net Pay',
category: 'Pharmacy Trend',
trend: '3.5%',
},
],
}, gridOptions_Shared)
new agGrid.Grid(document.querySelector('#Example-1'), gridOptions_Example_1)
gridOptions_Example_1.columnApi.setPivotMode(true)
gridOptions_Example_1.columnApi.setPivotColumns(['client','time_period'])
gridOptions_Example_1.columnApi.setRowGroupColumns(['measure', 'category'])
gridOptions_Example_1.api.forEachNode((node) => node.setExpanded(true))
@import url('https://yourlifechurch.org/assets/fontawesome-pro-5/css/all.min.css');
/* cascade */
:focus {
outline: 1px solid #36fc;
outline-offset: 2px;
}
:disabled {
cursor: not-allowed;
opacity: .3;
}
:disabled:hover { transform: none; }
body {
-webkit-font-smoothing: antialiased;
background: #fff;
color: #234;
font: 500 15px/1.5 'SF Pro Text', -apple-system, BlinkMacSystemFont, sans-serif;
/* letter-spacing: -.02em; */
margin: 0;
}
button {
border-radius: 4px;
box-shadow: 1px 2px 4px #0124;
cursor: pointer;
line-height: 24px;
padding: 4px 12px;
}
button:hover { transform: translateY(-1px); }
button:active { transform: none; }
button i {
font-size: 14px;
margin-right: 4px;
}
h1 {
font: bold 48px/48px 'SF Pro Display', sans-serif;
letter-spacing: -0.03em;
}
input {
font-weight: 600;
line-height: 1;
}
/* stop padding from being added to width or height */
/* { box-sizing: border-box; } */
/* reset */
a {
color: #28f;
text-decoration: none;
}
button,
input {
background: #fff;
border: none;
color: inherit;
cursor: pointer;
font: inherit;
}
input { padding: 0; }
input:focus { outline: none; }
label { cursor: pointer; }
h2 {
font-size: 16px;
line-height: 16px;
margin: 0 0 16px;
}
/* layout helpers */
.Center {
margin: 0 auto;
max-width: 944px;
}
.Encapsulate { position: relative; }
.Flex,
.Justify {
align-items: center;
display: flex;
}
.Justify { justify-content: space-between; }
/* components: demo only */
/* components: table examples */
.Page-Section { padding: 48px 0 24px; }
.Page-Section:nth-child(odd) { background: #f1f3f5; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment