crf-heat-map
Advanced tools
Comparing version 1.2.1 to 1.3.0
{ | ||
"name": "crf-heat-map", | ||
"description": "Heat Map showing database form status at different levels", | ||
"version": "1.2.1", | ||
"version": "1.3.0", | ||
"author": "Rho, Inc.", | ||
"license": "MIT", | ||
"homepage": "https://github.com/rhoinc/crf-heat-map#readme", | ||
"main": "./build/crfHeatMap.js", | ||
"main": "./crfHeatMap.js", | ||
"module": "./src/wrapper.js", | ||
@@ -20,8 +20,8 @@ "keywords": [ | ||
"scripts": { | ||
"build": "npm audit fix && npm run bundle && npm run format && npm run build-md", | ||
"build-md": "node ./scripts/configuration-markdown.js", | ||
"build": "npm audit fix && npm run bundle && npm run format && npm run build-wiki", | ||
"build-wiki": "node ./scripts/configuration-markdown.js", | ||
"bundle": "rollup -c", | ||
"format": "npm run format-src && npm run format-build", | ||
"format": "npm run format-src && npm run format-bundle", | ||
"format-src": "prettier --print-width=100 --tab-width=4 --single-quote --write \"src/**/!(*defineLayout|*defineStyles).js\"", | ||
"format-build": "prettier --print-width=100 --tab-width=4 --single-quote --write build/crfHeatMap.js", | ||
"format-bundle": "prettier --print-width=100 --tab-width=4 --single-quote --write ./crfHeatMap.js", | ||
"test-page": "start chrome ./test-page/index.html && start firefox ./test-page/index.html && start iexplore file://%CD%/test-page/index.html", | ||
@@ -28,0 +28,0 @@ "watch": "rollup -c -w" |
@@ -6,67 +6,4 @@ The most straightforward way to customize the CRF Heat Map is by using a configuration object whose properties describe the behavior and appearance of the table. Since the CRF Heat Map is a Webcharts `table` object, many default Webcharts settings are set in the [webchartsSettings.js file](https://github.com/RhoInc/crf-heat-map/blob/master/src/configuration/webchartsSettings.js) as [described below](#webcharts-settings). Refer to the [Webcharts documentation](https://github.com/RhoInc/Webcharts/wiki/Chart-Configuration) for more details on these settings. | ||
# Renderer-specific settings | ||
The sections below describe each crf-heat-map setting as of version 1.2.0. | ||
The sections below describe each crf-heat-map setting as of version 1.3.0. | ||
## settings.site_col | ||
`string` | ||
Specifies variable for use as site ID | ||
**default:** `"sitename"` | ||
## settings.id_col | ||
`string` | ||
Specifies variable for use as subject ID | ||
**default:** `"subjectnameoridentifier"` | ||
## settings.visit_col | ||
`string` | ||
Specifies variable for use as Visit ID | ||
**default:** `"folderinstancename"` | ||
## settings.visit_order_col | ||
`string` | ||
Specifies variable for determining order of Visit ID | ||
**default:** `"folder_ordinal"` | ||
## settings.form_col | ||
`string` | ||
Specifies variable for use as Form ID | ||
**default:** `"ecrfpagename"` | ||
## settings.id_freeze_col | ||
`string` | ||
Specifies variable for subject-level freeze status | ||
**default:** `"subjfreezeflg"` | ||
## settings.id_status_col | ||
`string` | ||
Specifies variable for subject status | ||
**default:** `"status"` | ||
## settings.nestings | ||
@@ -82,9 +19,2 @@ `array` | ||
### settings.nestings[].settings_col | ||
`string` | ||
Settings Column | ||
**default:** none | ||
### settings.nestings[].value_col | ||
@@ -111,4 +41,11 @@ `string` | ||
### settings.nestings[].role | ||
`string` | ||
Specify Optional Role | ||
**default:** none | ||
## settings.value_cols | ||
@@ -171,4 +108,50 @@ `array` | ||
### settings.filter_cols[].value_col | ||
`string` | ||
Variable Name | ||
**default:** none | ||
### settings.filter_cols[].label | ||
`string` | ||
Label | ||
**default:** none | ||
### settings.filter_cols[].multiple | ||
`boolean` | ||
Multi-select | ||
**default:** none | ||
### settings.filter_cols[].subject_export | ||
`boolean` | ||
Include variable in subject-level export | ||
**default:** none | ||
## settings.visit_order_col | ||
`string` | ||
Specifies variable for determining order of ID with Visit role | ||
**default:** `"folder_ordinal"` | ||
## settings.form_order_col | ||
`string` | ||
Specifies variable for determining order of ID with Form role | ||
**default:** `"form_ordinal"` | ||
## settings.display_cell_annotations | ||
@@ -208,4 +191,13 @@ `boolean` | ||
## settings.nesting_filters | ||
`boolean` | ||
Adds filters for each of the nesting variables | ||
**default:** `true` | ||
# Webcharts settings | ||
The object below contains each Webcharts setting as of version 1.2.0. | ||
The object below contains each Webcharts setting as of version 1.3.0. | ||
@@ -212,0 +204,0 @@ ``` |
@@ -5,47 +5,5 @@ { | ||
"overview": "The most straightforward way to customize the CRF Heat Map is by using a configuration object whose properties describe the behavior and appearance of the table. Since the CRF Heat Map is a Webcharts `table` object, many default Webcharts settings are set in the [webchartsSettings.js file](https://github.com/RhoInc/crf-heat-map/blob/master/src/configuration/webchartsSettings.js) as [described below](#webcharts-settings). Refer to the [Webcharts documentation](https://github.com/RhoInc/Webcharts/wiki/Chart-Configuration) for more details on these settings.\nIn addition to the standard Webcharts settings several custom settings not available in the base Webcharts library have been added to the CRF Heat Map to facilitate data mapping and other custom functionality. These custom settings are described in detail below and are set in the [rendererSettings.js file](https://github.com/RhoInc/crf-heat-map/blob/master/src/configuration/rendererSettings.js). All defaults can be overwritten by the passed configuration object.", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"type": "object", | ||
"properties": { | ||
"site_col" : { | ||
"title": "Site Column", | ||
"description": "Specifies variable for use as site ID", | ||
"type": "string", | ||
"default": "sitename" | ||
}, | ||
"id_col" : { | ||
"title": "Subject ID Column", | ||
"description": "Specifies variable for use as subject ID", | ||
"type": "string", | ||
"default": "subjectnameoridentifier" | ||
}, | ||
"visit_col" : { | ||
"title": "Visit Column", | ||
"description": "Specifies variable for use as Visit ID", | ||
"type": "string", | ||
"default": "folderinstancename" | ||
}, | ||
"visit_order_col" : { | ||
"title": "Visit Order Column", | ||
"description": "Specifies variable for determining order of Visit ID", | ||
"type": "string", | ||
"default": "folder_ordinal" | ||
}, | ||
"form_col" : { | ||
"title": "Form Column", | ||
"description": "Specifies variable for use as Form ID", | ||
"type": "string", | ||
"default": "ecrfpagename" | ||
}, | ||
"id_freeze_col" : { | ||
"title": "Subject Freeze Column", | ||
"description": "Specifies variable for subject-level freeze status", | ||
"type": "string", | ||
"default": "subjfreezeflg" | ||
}, | ||
"id_status_col" : { | ||
"title": "Subject Status Column", | ||
"description": "Specifies variable for subject status", | ||
"type": "string", | ||
"default": "status" | ||
}, | ||
"nestings": { | ||
@@ -58,6 +16,2 @@ "title": "Data Nesting", | ||
"properties":{ | ||
"settings_col":{ | ||
"title":"Settings Column", | ||
"type":"string" | ||
}, | ||
"value_col":{ | ||
@@ -74,2 +28,6 @@ "title":"Value Column", | ||
"type":"boolean" | ||
}, | ||
"role":{ | ||
"title":"Specify Optional Role", | ||
"type":"string" | ||
} | ||
@@ -80,24 +38,24 @@ } | ||
{ | ||
"settings_col": "site_col", | ||
"value_col" : null, | ||
"value_col" : "sitename", | ||
"label": "Site", | ||
"default_nesting": true | ||
"default_nesting": true, | ||
"role": "site_col" | ||
}, | ||
{ | ||
"settings_col": "id_col", | ||
"value_col" : null, | ||
"value_col" : "subjectnameoridentifier", | ||
"label": "Subject ID", | ||
"default_nesting": true | ||
"default_nesting": true, | ||
"role": "id_col" | ||
}, | ||
{ | ||
"settings_col": "visit_col", | ||
"value_col" : null, | ||
"value_col" : "folderinstancename", | ||
"label": "Folder", | ||
"default_nesting": false | ||
"default_nesting": false, | ||
"role": "visit_col" | ||
}, | ||
{ | ||
"settings_col": "form_col", | ||
"value_col" : null, | ||
"value_col" : "ecrfpagename", | ||
"label": "Form", | ||
"default_nesting": false | ||
"default_nesting": false, | ||
"role": "form_col" | ||
} | ||
@@ -151,12 +109,60 @@ ] | ||
"items": { | ||
"title": "Variable Name", | ||
"description": "the name of the filter variable", | ||
"type": "string" | ||
"type": "object", | ||
"properties":{ | ||
"value_col":{ | ||
"title":"Variable Name", | ||
"type":"string" | ||
}, | ||
"label":{ | ||
"title":"Label", | ||
"type":"string" | ||
}, | ||
"multiple":{ | ||
"title":"Multi-select", | ||
"type": "boolean" | ||
}, | ||
"subject_export":{ | ||
"title":"Include variable in subject-level export", | ||
"type":"boolean" | ||
} | ||
} | ||
}, | ||
"default": [ | ||
"subset1", | ||
"subset2", | ||
"subset3" | ||
{ | ||
"value_col": "subset1", | ||
"label": "Subset 1" | ||
}, | ||
{ | ||
"value_col": "subset2", | ||
"label": "Subset 2" | ||
}, | ||
{ | ||
"value_col": "subset3", | ||
"label": "Subset 3" | ||
}, | ||
{ | ||
"value_col": "subjfreezeflg", | ||
"label": "Subject Freeze Status", | ||
"subject_export" : true | ||
}, | ||
{ | ||
"value_col": "status", | ||
"label": "Subject Status", | ||
"multiple": true, | ||
"subject_export" : true | ||
} | ||
] | ||
}, | ||
"visit_order_col" : { | ||
"title": "Visit Order Column", | ||
"description": "Specifies variable for determining order of ID with Visit role", | ||
"type": "string", | ||
"default": "folder_ordinal" | ||
}, | ||
"form_order_col" : { | ||
"title": "Form Order Column", | ||
"description": "Specifies variable for determining order of ID with Form role", | ||
"type": "string", | ||
"default": "form_ordinal" | ||
}, | ||
"display_cell_annotations": { | ||
@@ -185,4 +191,10 @@ "title": "Display Cell Annotations", | ||
"default": 10000 | ||
}, | ||
"nesting_filters": { | ||
"title": "Enable Nesting Variables Filters", | ||
"description": "Adds filters for each of the nesting variables", | ||
"type": "boolean", | ||
"default": true | ||
} | ||
} | ||
} |
export default function rendererSettings() { | ||
return { | ||
site_col: 'sitename', | ||
id_col: 'subjectnameoridentifier', | ||
visit_col: 'folderinstancename', | ||
visit_order_col: 'folder_ordinal', | ||
form_col: 'ecrfpagename', | ||
id_freeze_col: 'subjfreezeflg', | ||
id_status_col: 'status', | ||
nestings: [ | ||
{ | ||
settings_col: 'site_col', | ||
value_col: null, // set in syncSettings() | ||
value_col: 'sitename', | ||
label: 'Site', | ||
default_nesting: true | ||
default_nesting: true, | ||
role: 'site_col' | ||
}, | ||
{ | ||
settings_col: 'id_col', | ||
value_col: null, // set in syncSettings() | ||
value_col: 'subjectnameoridentifier', | ||
label: 'Subject ID', | ||
default_nesting: true | ||
default_nesting: true, | ||
role: 'id_col' | ||
}, | ||
{ | ||
settings_col: 'visit_col', | ||
value_col: null, // set in syncSettings(0 | ||
value_col: 'folderinstancename', | ||
label: 'Folder', | ||
default_nesting: false | ||
default_nesting: false, | ||
role: 'visit_col' | ||
}, | ||
{ | ||
settings_col: 'form_col', | ||
value_col: null, // set in syncSettings() | ||
value_col: 'ecrfpagename', | ||
label: 'Form', | ||
default_nesting: false | ||
default_nesting: false, | ||
role: 'form_col' | ||
} | ||
@@ -89,8 +82,35 @@ ], | ||
], | ||
filter_cols: ['subset1', 'subset2', 'subset3'], | ||
filter_cols: [ | ||
{ | ||
value_col: 'subset1', | ||
label: 'Subset 1' | ||
}, | ||
{ | ||
value_col: 'subset2', | ||
label: 'Subset 2' | ||
}, | ||
{ | ||
value_col: 'subset3', | ||
label: 'Subset 3' | ||
}, | ||
{ | ||
value_col: 'subjfreezeflg', | ||
label: 'Subject Freeze Status', | ||
subject_export: true | ||
}, | ||
{ | ||
value_col: 'status', | ||
label: 'Subject Status', | ||
multiple: true, | ||
subject_export: true | ||
} | ||
], | ||
visit_order_col: 'folder_ordinal', | ||
form_order_col: 'form_ordinal', | ||
display_cell_annotations: true, | ||
expand_all: false, | ||
sliders: false, | ||
max_rows_warn: 10000 | ||
max_rows_warn: 10000, | ||
nesting_filters: true | ||
}; | ||
} |
@@ -5,16 +5,8 @@ import controlInputs from './controlInputs'; | ||
const defaultControls = controlInputs(); | ||
const labels = {}; | ||
labels[settings.site_col] = 'Site'; | ||
labels[settings.id_freeze_col] = 'Subject Freeze Status'; | ||
labels[settings.id_status_col] = 'Subject Status'; | ||
settings.filter_cols.forEach((filter_col, i) => { | ||
const filter = { | ||
type: 'subsetter', | ||
value_col: filter_col, | ||
label: labels[filter_col] | ||
? labels[filter_col] | ||
: /^subset\d$/.test(filter_col) | ||
? filter_col.replace(/^s/, 'S').replace(/(\d)/, ' $1') | ||
: filter_col.label || filter_col.value_col || filter_col, | ||
multiple: filter_col == settings.id_status_col ? true : false | ||
value_col: filter_col.value_col, | ||
label: filter_col.label ? filter_col.label : filter_col.value_col, | ||
multiple: filter_col.multiple ? filter_col.multiple : false | ||
}; | ||
@@ -21,0 +13,0 @@ defaultControls.splice(i, 0, filter); |
export default function syncSettings(settings) { | ||
//Sync nestings with data variable settings. | ||
const settingsKeys = Object.keys(settings); | ||
const settingsCols = settingsKeys.filter(settingsKey => /_col$/.test(settingsKey)); | ||
settings.nestings.forEach(nesting => { | ||
nesting.value_col = | ||
nesting.value_col || | ||
settings[settingsCols.find(settingsCol => settingsCol === nesting.settings_col)]; | ||
}); | ||
// sort value_cols so that crfs come before query cols regardless of order in rendererSettings | ||
@@ -16,2 +7,7 @@ settings.value_cols.sort(function(a, b) { | ||
// Assign nest variables with specfic roles to specific settings | ||
settings.nestings.map(function(d) { | ||
if (typeof d.role != 'undefined') settings[d.role] = d.value_col; | ||
}); | ||
//Define initial nesting variables. | ||
@@ -26,9 +22,23 @@ settings.id_cols = settings.nestings | ||
// Define nesting filters | ||
var nest_settings = []; | ||
if (settings.nesting_filters === true) { | ||
settings.nestings.forEach(setting => | ||
nest_settings.push({ | ||
value_col: setting.value_col, | ||
label: setting.label | ||
}) | ||
); | ||
} | ||
//Define filter variables. | ||
settings.filter_cols = Array.isArray(settings.filter_cols) | ||
? [settings.site_col, settings.id_freeze_col, settings.id_status_col].concat( | ||
settings.filter_cols | ||
) | ||
: [settings.site_col, settings.id_freeze_col, settings.id_status_col]; | ||
? nest_settings.concat(settings.filter_cols) | ||
: nest_settings; | ||
//Define cols to include in subject level export | ||
settings.subject_export_cols = settings.filter_cols.filter( | ||
filter => filter.subject_export == true | ||
); | ||
// add labels specified in rendererSettings as headers | ||
@@ -35,0 +45,0 @@ settings.headers = settings.value_cols.map(d => d.label); |
@@ -10,3 +10,5 @@ import createNestControls from './defineLayout/createNestControls'; | ||
.append('div') | ||
.attr('id', 'crf-heat-map'), | ||
.datum(this) | ||
.classed('crf-heat-map', true) | ||
.attr('id', `crf-heat-map${document.querySelectorAll('.crf-heat-map').length}`) | ||
}; | ||
@@ -16,6 +18,8 @@ | ||
if (isIE) { | ||
this.containers.main.append("p").style({'color':'red','font-size':'20px','padding':'20px'}).text("Internet Explorer use is not recommended with the CRF Heat Map. You are likely to experience slower loading times.") | ||
this.containers.main | ||
.append('p') | ||
.classed('chm-ie-sucks', true) | ||
.text('Internet Explorer use is not recommended with the CRF Heat Map. You are likely to experience slower loading times.') | ||
} | ||
/**-------------------------------------------------------------------------------------------\ | ||
@@ -22,0 +26,0 @@ Left column |
import redraw from '../onLayout/customizeFilters/redraw'; | ||
import customizeNestOptions from './createNestControls/customizeNestOptions'; | ||
import customizeNestSelects from './createNestControls/customizeNestSelects'; | ||
@@ -14,3 +16,3 @@ export default function createNestControls() { | ||
.text(''); | ||
var idNote = this.containers.nestControls.append('span').attr('class', 'span-description'); | ||
// var idNote = this.containers.nestControls.append('span').attr('class', 'span-description'); | ||
var idSelects = this.containers.nestControls | ||
@@ -47,2 +49,5 @@ .selectAll('select') | ||
//ensure natural nest control options and behavior | ||
customizeNestOptions.call(this, config.id_cols); | ||
idSelects.on('change', function() { | ||
@@ -74,5 +79,11 @@ //indicate loading | ||
// Enforce Select Logic | ||
customizeNestSelects.call(context, idSelects); | ||
//Update nesting variables. | ||
context.table.config.id_cols = uniqueLevels; | ||
//Maintain nest options logic | ||
customizeNestOptions.call(context, uniqueLevels); | ||
//Summarize filtered data and redraw table. | ||
@@ -79,0 +90,0 @@ redraw.call(context.table); |
@@ -34,3 +34,3 @@ export const firstColumnWidth = 16; | ||
'}', | ||
'body #crf-heat-map {' + | ||
'body .crf-heat-map {' + | ||
' font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;' + | ||
@@ -40,8 +40,8 @@ ' font-size: 16px;' + | ||
'}', | ||
'#crf-heat-map {' + | ||
'.crf-heat-map {' + | ||
'}', | ||
'#crf-heat-map div {' + | ||
'.crf-heat-map div {' + | ||
' box-sizing: content-box;' + | ||
'}', | ||
'#crf-heat-map select {' + | ||
'.crf-heat-map select {' + | ||
' font-size: 12px;' + | ||
@@ -52,2 +52,7 @@ '}', | ||
'}', | ||
'.chm-ie-sucks {' + | ||
' color: red;', | ||
' font-size: 20px;', | ||
' padding: 20px;', | ||
'}', | ||
'.chm-column {' + | ||
@@ -122,8 +127,7 @@ ' display: inline-block;' + | ||
'#chm-controls .control-group > * {' + | ||
' display: inline-block !important;' + | ||
' margin: 0;' + | ||
' display: block;' + | ||
' width: auto;' + | ||
'}', | ||
'#chm-controls .wc-control-label {' + | ||
' width: 58%;' + | ||
' text-align: right;' + | ||
' text-align: center;' + | ||
'}', | ||
@@ -133,10 +137,42 @@ '#chm-controls .span-description {' + | ||
'#chm-controls select.changer {' + | ||
' width: 40%;' + | ||
' float: right;' + | ||
' overflow-y: auto;' + | ||
' margin: 0 auto;' + | ||
'}', | ||
'#chm-controls input.changer {' + | ||
' margin-left: 2% !important;' + | ||
'.chm-control-grouping {' + | ||
' display: inline-block;' + | ||
'}', | ||
'.chm-control-grouping .control-group .wc-control-label {' + | ||
' text-align: center;' + | ||
'}', | ||
'.chm-control-grouping--label {' + | ||
' text-align: center;' + | ||
' width: 100%;' + | ||
' font-size: 20px;' + | ||
'}', | ||
'.chm-other-controls {' + | ||
' border-bottom: 1px solid lightgray;' + | ||
' padding-bottom: 7px;' + | ||
'}', | ||
'.chm-nesting-filters {' + | ||
' display: flex;' + | ||
' flex-wrap: wrap ;' + | ||
' margin-top: 10px;' + | ||
' justify-content: space-evenly;' + | ||
'}', | ||
'.chm-nesting-filter {' + | ||
' width : 100px !important;' + | ||
' display : block !important;' + | ||
'}', | ||
//checkboxes | ||
'.chm-checkbox {' + | ||
' display: inline-flex !important;' + | ||
' justify-content: center;' + | ||
'}', | ||
'.chm-checkbox .wc-control-label {' + | ||
' margin-right: 5px;' + | ||
'}', | ||
'.chm-checkbox .changer {' + | ||
' margin-top: 5px !important;' + | ||
'}', | ||
/***--------------------------------------------------------------------------------------\ | ||
@@ -171,3 +207,10 @@ Right column | ||
` padding-left: ${paddingLeft}px;` + | ||
' min-width : 100px;' + | ||
'}', | ||
'.chm-nest-control.chm-hide {' + | ||
' float: left;' + | ||
' display: none;' + | ||
' clear: left;' + | ||
` padding-left: ${paddingLeft}px;` + | ||
'}', | ||
'#chm-nest-control--1 {' + | ||
@@ -367,3 +410,3 @@ ' margin-left: 0;' + | ||
'}', | ||
'.wc-table table tbody tr.grayParent td:not(:first-child) {' + | ||
'.wc-table table tbody tr.grayParent td:not(:first-child) {' + | ||
' background: #CCCCCC;' + | ||
@@ -375,4 +418,8 @@ ' color: black;' + | ||
'.chm-cell--id {' + ' background: white;' + '}', | ||
'.chm-cell--id {' + ' background: white;' + | ||
' text-overflow: ellipsis;' + | ||
' white-space: nowrap;' + | ||
' overflow: hidden;' + | ||
' max-width: 0px;' + | ||
'}' , | ||
'.chm-table-row--expandable .chm-cell--id {' + | ||
@@ -379,0 +426,0 @@ ' color: blue;' + |
@@ -9,6 +9,7 @@ export default function checkRequiredVariables() { | ||
this.settings.synced.value_cols.map(d => d.col), | ||
this.settings.synced.filter_cols | ||
this.settings.synced.filter_cols.map(filter => filter.value_col) | ||
]) | ||
) | ||
.values(); | ||
const missingVariables = requiredVariables.filter( | ||
@@ -18,3 +19,3 @@ variable => this.data.variables.indexOf(variable.split(' (')[0]) < 0 | ||
if (missingVariables.length) | ||
alert( | ||
console.log( | ||
`The data are missing ${ | ||
@@ -21,0 +22,0 @@ missingVariables.length === 1 ? 'this variable' : 'these variables' |
@@ -7,2 +7,3 @@ import customizeRows from './onDraw/customizeRows'; | ||
import toggleCellAnnotations from './onDraw/toggleCellAnnotations'; | ||
import addIdHover from './onDraw/addIdHover'; | ||
import dataExport from './onDraw/dataExport'; | ||
@@ -44,2 +45,3 @@ import flagParentRows from './onDraw/flagParentRows'; | ||
toggleCellAnnotations.call(this); | ||
addIdHover.call(this); | ||
dataExport.call(this); | ||
@@ -46,0 +48,0 @@ flagParentRows.call(this); |
@@ -9,5 +9,4 @@ export default function addInfoBubbles() { | ||
.data(chart.initial_config.value_cols) | ||
.append('span') | ||
.html(' ⓘ') | ||
.attr('title', d => d.description); | ||
.attr('title', d => d.description) | ||
.style('cursor', 'help'); | ||
} |
import customizeRows from '../customizeRows'; | ||
import customizeCells from '../customizeCells'; | ||
import toggleCellAnnotations from '../toggleCellAnnotations'; | ||
import addIdHover from '../addIdHover'; | ||
import flagParentRows from '../flagParentRows'; | ||
@@ -105,3 +106,6 @@ | ||
toggleCellAnnotations.call(chart); | ||
// maintain display cell annotations setting since we are not drawing | ||
addIdHover.call(chart); | ||
} | ||
} |
@@ -43,5 +43,5 @@ export default function customizeCells(chart, cells) { | ||
? d.text | ||
: String(Math.floor(d.text * 100)) + '%' | ||
: d3.format('%')(d.text) | ||
: d.text | ||
); | ||
} |
@@ -52,3 +52,3 @@ export default function csv() { | ||
['N/A', ''].indexOf(d[col]) < 0 | ||
? Math.floor(d[col] * 100) | ||
? d[col] * 100 | ||
: d[col]; | ||
@@ -55,0 +55,0 @@ |
@@ -22,19 +22,30 @@ export default function deriveData() { | ||
if (subject_id_col) { | ||
//Add headers. | ||
this.export.headers.push('Site', 'Subject Status', 'Subject Freeze Status'); | ||
//Add headers and columns | ||
if (this.config.site_col) { | ||
this.export.headers.push('Site'); | ||
this.export.cols.push('site'); | ||
} | ||
//Add columns. | ||
this.export.cols.push('site', 'status', 'freeze'); | ||
if (this.config.subject_export_cols) { | ||
this.config.subject_export_cols.forEach(function(d) { | ||
table.export.headers.push(d.label); | ||
table.export.cols.push(d.value_col); | ||
}); | ||
} | ||
// build look up for subject | ||
var subjects = d3.set(table.data.initial.map(d => d[this.config.id_col])).values(); | ||
var subjectMap = subjects.reduce((acc, cur) => { | ||
var subjectDatum = this.data.initial.find(d => d[this.config.id_col] === cur); | ||
acc[cur] = { | ||
site: subjectDatum[this.config.site_col], | ||
status: subjectDatum[this.config.id_status_col], | ||
freeze: subjectDatum[this.config.id_freeze_col] | ||
}; | ||
return acc; | ||
}, {}); | ||
if (this.config.site_col || this.config.subject_export_cols) { | ||
var subjects = d3.set(table.data.initial.map(d => d[this.config.id_col])).values(); | ||
var subjectMap = subjects.reduce((acc, cur) => { | ||
var subjectDatum = this.data.initial.find(d => d[this.config.id_col] === cur); | ||
acc[cur] = {}; | ||
if (this.config.site_col) acc[cur]['site'] = subjectDatum[this.config.site_col]; | ||
if (this.config.subject_export_cols) { | ||
this.config.subject_export_cols.forEach(function(d) { | ||
acc[cur][d.value_col] = subjectDatum[d.value_col]; | ||
}); | ||
} | ||
return acc; | ||
}, {}); | ||
} | ||
} | ||
@@ -58,3 +69,3 @@ | ||
// Now "join" subject level information to export data | ||
if (subject_id_col) { | ||
if ((this.config.site_col || this.config.subject_export_cols) && this.config.id_col) { | ||
const subjectID = d[`Nest ${subject_id_col_index + 1}: ${this.config.id_col}`]; | ||
@@ -61,0 +72,0 @@ Object.assign(d, subjectMap[subjectID]); |
@@ -10,12 +10,3 @@ export default function xlsx() { | ||
}; | ||
const arrayOfArrays = this.export.data.map(d => | ||
this.export.cols.map( | ||
col => | ||
value_cols.indexOf(col) > -1 && | ||
context.typeDict[col] == 'crfs' && | ||
['N/A', ''].indexOf(d[col]) < 0 | ||
? Math.floor(d[col] * 100) / 100 | ||
: d[col] | ||
) | ||
); // convert data from array of objects to array of arrays. | ||
const arrayOfArrays = this.export.data.map(d => this.export.cols.map(col => d[col])); // convert data from array of objects to array of arrays. | ||
const workbook = { | ||
@@ -22,0 +13,0 @@ SheetNames: [sheetName, 'Current Filters'], |
import summarizeData from './onInit/summarizeData'; | ||
import removeFilters from './onInit/removeFilters'; | ||
import removeSubjectExportCols from './onInit/removeSubjectExportCols'; | ||
@@ -7,2 +9,8 @@ export default function onInit() { | ||
//remove subject-level export columns that have multiple values within a subject | ||
removeSubjectExportCols.call(this); | ||
//remove single-level or dataless filters | ||
removeFilters.call(this); | ||
//Summarize raw data. | ||
@@ -9,0 +17,0 @@ summarizeData.call(this); |
import calculateStatistics from './summarizeData/calculateStatistics'; | ||
import sortRows from './summarizeData/sortRows'; | ||
@@ -37,4 +38,2 @@ export default function summarizeData() { | ||
} | ||
// console.log(d) | ||
}); | ||
@@ -45,41 +44,5 @@ | ||
// if there is a visit order column specificed in settings and it's present in the data use it to sort the folder rows | ||
if ( | ||
this.initial_config.visit_order_col && | ||
Object.keys(this.data.initial[0]).includes(this.initial_config.visit_order_col) | ||
) { | ||
//Collapse array of arrays to array of objects. | ||
this.data.summarized = d3.merge(this.data.summaries).sort(function(a, b) { | ||
const visitIndex = context.config.id_cols.indexOf(context.initial_config.visit_col); | ||
if (visitIndex > -1) { | ||
var aIds = a.id.split(' |'); | ||
var bIds = b.id.split(' |'); | ||
var i; | ||
for (i = 0; i < context.config.id_cols.length; i++) { | ||
if (aIds[i] === bIds[i]) { | ||
continue; | ||
} else { | ||
// because the visit_order variable is numeric we want to treat it differently | ||
if (i === visitIndex) { | ||
return typeof aIds[i] == 'undefined' | ||
? -1 | ||
: parseFloat(a.folder_ordinal) < parseFloat(b.folder_ordinal) | ||
? -1 | ||
: 1; | ||
} else { | ||
return typeof aIds[i] === 'undefined' ? -1 : aIds[i] < bIds[i] ? -1 : 1; | ||
} | ||
} | ||
} | ||
} else { | ||
return a.id < b.id ? -1 : 1; | ||
} | ||
}); | ||
} else { | ||
// otherwise sort alphabetically | ||
this.data.summarized = d3.merge(this.data.summaries).sort((a, b) => (a.id < b.id ? -1 : 1)); | ||
} | ||
// sort rows | ||
sortRows.call(this); | ||
// this.data.raw = this.data.summarized; | ||
//end performance test | ||
@@ -86,0 +49,0 @@ var t1 = performance.now(); |
@@ -44,11 +44,20 @@ export default function calculateStatistics(onInit = true) { | ||
context.initial_config.value_cols.forEach(value_col => { | ||
const count = d3.sum(d, di => di[value_col.col]); | ||
var count; | ||
if (typeof value_col.denominator === 'undefined') { | ||
count = d3.sum(d, di => di[value_col.col]); | ||
} else { | ||
// ensure numerator is subsetted in the event that an error is made | ||
// and an ID has a value of 1 and a denominator value of 0. | ||
var subset = d.filter(row => row[value_col.denominator] === '1'); | ||
count = d3.sum(subset, di => di[value_col.col]); | ||
} | ||
summary[value_col.col] = | ||
crfsNoDenominator.map(m => m.col).indexOf(value_col.col) > -1 | ||
? summary.nForms | ||
? count / summary.nForms | ||
? Math.floor(count / summary.nForms * 100) / 100 | ||
: 'N/A' | ||
: crfsDenominator.map(m => m.col).indexOf(value_col.col) > -1 | ||
? summary['n' + value_col.denominator] | ||
? count / summary['n' + value_col.denominator] | ||
? Math.floor(count / summary['n' + value_col.denominator] * 100) / | ||
100 | ||
: 'N/A' | ||
@@ -61,3 +70,4 @@ : queries.map(m => m.col).indexOf(value_col.col) > -1 | ||
summary.parents = d[0].parents; | ||
summary.folder_ordinal = d[0].folder_ordinal; | ||
summary.visit_order = d[0][context.initial_config.visit_order_col]; | ||
summary.form_order = d[0][context.initial_config.form_order_col]; | ||
return summary; | ||
@@ -76,3 +86,4 @@ }) | ||
d.parents = d.values.parents; | ||
d.folder_ordinal = d.values.folder_ordinal; | ||
d.visit_order = d.values.visit_order; | ||
d.form_order = d.values.form_order; | ||
@@ -79,0 +90,0 @@ delete d.values; |
import customizeFilters from './onLayout/customizeFilters'; | ||
import tweakMultiSelects from './onLayout/tweakMultiSelects'; | ||
import customizeCheckboxes from './onLayout/customizeCheckboxes'; | ||
import moveExportButtons from './onLayout/moveExportButtons'; | ||
//import moveExportButtons from './onLayout/moveExportButtons'; | ||
import addColumnControls from './onLayout/addColumnControls'; | ||
import formatControls from './onLayout/formatControls'; | ||
@@ -13,2 +14,3 @@ export default function onLayout() { | ||
addColumnControls.call(this); | ||
formatControls.call(this); | ||
} |
import update from './update'; | ||
import filterData from '../filterData'; | ||
export default function onInput(filter) { | ||
export default function addEventListeners(filter) { | ||
const context = this; | ||
@@ -9,3 +9,3 @@ | ||
filter.inputBoxes = filter.div.selectAll('.range-value').on('change', function(d) { | ||
const loadingdiv = d3.select('#chm-loading'); | ||
const loadingdiv = context.parent.containers.main.select('#chm-loading'); | ||
@@ -12,0 +12,0 @@ loadingdiv.classed('chm-hidden', false); |
import update from './update'; | ||
import filterData from '../filterData'; | ||
export default function onInput(filter) { | ||
export default function addEventListeners(filter) { | ||
const context = this; | ||
@@ -9,3 +9,3 @@ | ||
filter.sliders = filter.div.selectAll('.range-slider').on('change', function(d) { | ||
const loadingdiv = d3.select('#chm-loading'); | ||
const loadingdiv = context.parent.containers.main.select('#chm-loading'); | ||
@@ -12,0 +12,0 @@ loadingdiv.classed('chm-hidden', false); |
@@ -29,3 +29,3 @@ import toggleCellAnnotations from './../onDraw/toggleCellAnnotations'; | ||
} else { | ||
var loadingdiv = d3.select('#chm-loading'); // fix this later due to confirm box | ||
var loadingdiv = context.parent.containers.main.select('#chm-loading'); // fix this later due to confirm box | ||
@@ -74,3 +74,3 @@ loadingdiv.classed('chm-hidden', false); | ||
var loadingdiv = d3.select('#chm-loading'); | ||
var loadingdiv = context.parent.containers.main.select('#chm-loading'); | ||
@@ -77,0 +77,0 @@ loadingdiv.classed('chm-hidden', false); |
@@ -25,3 +25,3 @@ import redraw from './customizeFilters/redraw'; | ||
//Update filter object. | ||
//Update filter val | ||
context.filters.find(filter => filter.col === di.value_col).val = this | ||
@@ -35,2 +35,8 @@ .multiple | ||
//Update filter index | ||
context.filters.find(filter => filter.col === di.value_col).index = this | ||
.multiple | ||
? null | ||
: dropdown.selectAll('option:checked').property('index'); | ||
//Filter data. | ||
@@ -41,3 +47,3 @@ context.data.initial_filtered = context.data.initial; | ||
filter => | ||
filter.val !== 'All' && | ||
!(filter.all === true && filter.index === 0) && | ||
!( | ||
@@ -44,0 +50,0 @@ Array.isArray(filter.val) && |
@@ -122,1 +122,54 @@ if (typeof Object.assign != 'function') { | ||
} | ||
if (!Array.prototype.includes) { | ||
Object.defineProperty(Array.prototype, 'includes', { | ||
value: function(valueToFind, fromIndex) { | ||
if (this == null) { | ||
throw new TypeError('"this" is null or not defined'); | ||
} | ||
// 1. Let O be ? ToObject(this value). | ||
var o = Object(this); | ||
// 2. Let len be ? ToLength(? Get(O, "length")). | ||
var len = o.length >>> 0; | ||
// 3. If len is 0, return false. | ||
if (len === 0) { | ||
return false; | ||
} | ||
// 4. Let n be ? ToInteger(fromIndex). | ||
// (If fromIndex is undefined, this step produces the value 0.) | ||
var n = fromIndex | 0; | ||
// 5. If n = 0, then | ||
// a. Let k be n. | ||
// 6. Else n < 0, | ||
// a. Let k be len + n. | ||
// b. If k < 0, let k be 0. | ||
var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); | ||
function sameValueZero(x, y) { | ||
return ( | ||
x === y || | ||
(typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)) | ||
); | ||
} | ||
// 7. Repeat, while k < len | ||
while (k < len) { | ||
// a. Let elementK be the result of ? Get(O, ! ToString(k)). | ||
// b. If SameValueZero(valueToFind, elementK) is true, return true. | ||
if (sameValueZero(o[k], valueToFind)) { | ||
return true; | ||
} | ||
// c. Increase k by 1. | ||
k++; | ||
} | ||
// 8. Return false | ||
return false; | ||
} | ||
}); | ||
} |
@@ -16,2 +16,3 @@ //utility functions | ||
import onDraw from './onDraw'; | ||
import onDestroy from './onDestroy'; | ||
@@ -63,3 +64,8 @@ import init from './init'; | ||
crfHeatMap.table.on('draw', onDraw); | ||
crfHeatMap.table.on('destroy', onDestroy); | ||
crfHeatMap.destroy = () => { | ||
crfHeatMap.table.destroy(); | ||
}; | ||
//stylesheet | ||
@@ -66,0 +72,0 @@ defineStyles.call(crfHeatMap); |
d3.csv( | ||
'https://raw.githubusercontent.com/RhoInc/data-library/master/data/clinical-trials/data-cleaning/dmc_datapage.csv', | ||
function(d) { | ||
'https://raw.githubusercontent.com/RhoInc/data-library/master/data/clinical-trials/data-cleaning/forms.csv', | ||
function(d,i) { | ||
return d; | ||
}, | ||
function(error, data) { | ||
if (error) | ||
console.log(error); | ||
function(data) { | ||
var instance = crfHeatMap( | ||
'#container' | ||
'#container', // element | ||
{ | ||
} // settings | ||
); | ||
instance.init(data); | ||
instance.init(data); | ||
destroyToggle //test destruction | ||
.on('click', function() { | ||
instance.destroy() | ||
}); | ||
} | ||
@@ -34,1 +37,8 @@ ); | ||
}); | ||
//Add button that toggles DESTRUCTION | ||
const destroyToggle = d3.select('#title') | ||
.append('button') | ||
.attr('id', 'destroy-toggle') | ||
.style('float', 'right') | ||
.text('Destroy'); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
254505
73
5835
1