@cdc/core 4.22.11 → 4.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import html2pdf from 'html2pdf.js'
|
|
3
|
+
import html2canvas from 'html2canvas'
|
|
4
|
+
|
|
5
|
+
const buttonText = {
|
|
6
|
+
pdf: 'Download PDF',
|
|
7
|
+
image: 'Download Image',
|
|
8
|
+
csv: 'Download Data (CSV)',
|
|
9
|
+
link: 'Link to Dataset'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const saveImageAs = (uri, filename) => {
|
|
13
|
+
const ie = navigator.userAgent.match(/MSIE\s([\d.]+)/)
|
|
14
|
+
const ie11 = navigator.userAgent.match(/Trident\/7.0/) && navigator.userAgent.match(/rv:11/)
|
|
15
|
+
const ieEdge = navigator.userAgent.match(/Edge/g)
|
|
16
|
+
const ieVer = ie ? ie[1] : ie11 ? 11 : ieEdge ? 12 : -1
|
|
17
|
+
|
|
18
|
+
if (ieVer > -1) {
|
|
19
|
+
const fileAsBlob = new Blob([uri], {
|
|
20
|
+
type: 'image/png'
|
|
21
|
+
})
|
|
22
|
+
window.navigator.msSaveBlob(fileAsBlob, filename)
|
|
23
|
+
} else {
|
|
24
|
+
const link = document.createElement('a')
|
|
25
|
+
if (typeof link.download === 'string') {
|
|
26
|
+
link.href = uri
|
|
27
|
+
link.download = filename
|
|
28
|
+
link.onclick = e => document.body.removeChild(e.target)
|
|
29
|
+
document.body.appendChild(link)
|
|
30
|
+
link.click()
|
|
31
|
+
} else {
|
|
32
|
+
window.open(uri)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const generateMedia = (state, type, elementToCapture) => {
|
|
38
|
+
// Identify Selector
|
|
39
|
+
const baseSvg = document.querySelector(`[data-download-id=${elementToCapture}]`)
|
|
40
|
+
|
|
41
|
+
// Handles different state title locations between components
|
|
42
|
+
// Apparently some packages use state.title where others use state.general.title
|
|
43
|
+
const handleFileName = state => {
|
|
44
|
+
// dashboard titles
|
|
45
|
+
if (state?.dashboard?.title) return state.dashboard.title.replace(/\s+/g, '-').toLowerCase() + '-' + date.getDate() + date.getMonth() + date.getFullYear()
|
|
46
|
+
|
|
47
|
+
// map titles
|
|
48
|
+
if (state?.general?.title) return state.general.title.replace(/\s+/g, '-').toLowerCase() + '-' + date.getDate() + date.getMonth() + date.getFullYear()
|
|
49
|
+
|
|
50
|
+
// chart titles
|
|
51
|
+
if (state?.title) return state.title.replace(/\s+/g, '-').toLowerCase() + '-' + date.getDate() + date.getMonth() + date.getFullYear()
|
|
52
|
+
|
|
53
|
+
return 'no-title'
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Construct filename with timestamp
|
|
57
|
+
const date = new Date()
|
|
58
|
+
const filename = handleFileName(state)
|
|
59
|
+
|
|
60
|
+
switch (type) {
|
|
61
|
+
case 'image':
|
|
62
|
+
html2canvas(baseSvg).then(canvas => {
|
|
63
|
+
saveImageAs(canvas.toDataURL(), filename + '.png')
|
|
64
|
+
})
|
|
65
|
+
return
|
|
66
|
+
case 'pdf':
|
|
67
|
+
let opt = {
|
|
68
|
+
margin: 0.2,
|
|
69
|
+
filename: filename + '.pdf',
|
|
70
|
+
image: { type: 'png' },
|
|
71
|
+
html2canvas: { scale: 2, logging: false },
|
|
72
|
+
jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
html2pdf()
|
|
76
|
+
.set(opt)
|
|
77
|
+
.from(baseSvg)
|
|
78
|
+
.save()
|
|
79
|
+
.then(() => {
|
|
80
|
+
generatedImage.remove() // Remove generated png
|
|
81
|
+
baseSvg.style.display = null // Re-display initial svg map
|
|
82
|
+
})
|
|
83
|
+
break
|
|
84
|
+
default:
|
|
85
|
+
console.warn("generateMedia param 2 type must be 'image' or 'pdf'")
|
|
86
|
+
break
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Handles different state theme locations between components
|
|
91
|
+
// Apparently some packages use state.headerColor where others use state.theme
|
|
92
|
+
const handleTheme = state => {
|
|
93
|
+
if (state?.headerColor) return state.headerColor // ie. maps
|
|
94
|
+
if (state?.theme) return state.theme // ie. charts
|
|
95
|
+
return 'theme-notFound'
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Download CSV
|
|
99
|
+
const Button = ({ state, text, type, title, elementToCapture }) => {
|
|
100
|
+
const buttonClasses = ['btn', 'btn-download', `${handleTheme(state)}`]
|
|
101
|
+
return (
|
|
102
|
+
<button className={buttonClasses.join(' ')} title={title} onClick={() => generateMedia(state, type, elementToCapture)} style={{ lineHeight: '1.4em' }}>
|
|
103
|
+
{buttonText[type]}
|
|
104
|
+
</button>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Link to CSV/JSON data
|
|
109
|
+
const Link = ({ config }) => {
|
|
110
|
+
// Handles Maps & Charts
|
|
111
|
+
if (config.dataFileSourceType === 'url' && config.dataFileName && config.table.showDownloadUrl) {
|
|
112
|
+
return (
|
|
113
|
+
<a href={config.dataFileName} title={buttonText.link} target='_blank'>
|
|
114
|
+
{buttonText.link}
|
|
115
|
+
</a>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Handles Dashboards
|
|
120
|
+
return config?.table?.showDownloadUrl && config.dataUrl ? (
|
|
121
|
+
<a href={config.dataUrl} title='Link to view full data set' target='_blank'>
|
|
122
|
+
{buttonText.link}
|
|
123
|
+
</a>
|
|
124
|
+
) : null
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// TODO: convert to standardized COVE section
|
|
128
|
+
const Section = ({ children, classes }) => {
|
|
129
|
+
return <section className={classes.join(' ')}>{children}</section>
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const CoveMediaControls = () => null
|
|
133
|
+
|
|
134
|
+
CoveMediaControls.Section = Section
|
|
135
|
+
CoveMediaControls.Link = Link
|
|
136
|
+
CoveMediaControls.Button = Button
|
|
137
|
+
CoveMediaControls.generateMedia = generateMedia
|
|
138
|
+
|
|
139
|
+
export default CoveMediaControls
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import Papa from 'papaparse'
|
|
2
2
|
|
|
3
|
-
export default async function (url) {
|
|
3
|
+
export default async function (url, visualizationType = '') {
|
|
4
4
|
try {
|
|
5
5
|
// Using URL Object to get pathname without URL paramaters on regex.
|
|
6
|
+
if (visualizationType === 'map') url = decodeURI(url)
|
|
7
|
+
|
|
6
8
|
url = new URL(url)
|
|
7
9
|
|
|
8
10
|
const path = url.pathname
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.23.1",
|
|
4
4
|
"description": "Core elements of the CDC Open Visualization project",
|
|
5
5
|
"author": "Daniel Immke <npm@daniel.do>",
|
|
6
6
|
"homepage": "https://github.com/CDCgov/cdc-open-viz#readme",
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
"react-dom": ">=16"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
+
"html2canvas": "^1.4.1",
|
|
24
|
+
"html2pdf.js": "^0.10.1",
|
|
23
25
|
"papaparse": "^5.3.0",
|
|
24
26
|
"prop-types": "^15.8.1",
|
|
25
27
|
"react-accessible-accordion": "^3.3.4",
|
|
@@ -30,5 +32,5 @@
|
|
|
30
32
|
"resolutions": {
|
|
31
33
|
"@types/react": "17.x"
|
|
32
34
|
},
|
|
33
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "58163844cc9ce2c379235413b19f49679eab4bef"
|
|
34
36
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// buttons that appear above data tables
|
|
2
|
+
.download-buttons {
|
|
3
|
+
display: flex;
|
|
4
|
+
justify-content: flex-end;
|
|
5
|
+
margin: 0 1em; // align w/ data table
|
|
6
|
+
|
|
7
|
+
.btn:not(:last-child) {
|
|
8
|
+
margin-right: 10px;
|
|
9
|
+
}
|
|
10
|
+
.btn-download {
|
|
11
|
+
float: unset;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// links that appear above data tables
|
|
16
|
+
.download-links {
|
|
17
|
+
padding: 0px 1em;
|
|
18
|
+
display: flex;
|
|
19
|
+
justify-content: flex-end;
|
|
20
|
+
|
|
21
|
+
a:not(:last-child) {
|
|
22
|
+
margin-right: 10px;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// odd wrapper thats different on dashboards
|
|
27
|
+
.cdc-dashboard-inner-container {
|
|
28
|
+
.download-links {
|
|
29
|
+
padding: unset;
|
|
30
|
+
margin-bottom: 5px;
|
|
31
|
+
}
|
|
32
|
+
.download-buttons {
|
|
33
|
+
margin: unset;
|
|
34
|
+
}
|
|
35
|
+
}
|
package/styles/_data-table.scss
CHANGED