visualifyjs 2.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. package/.github/workflows/static.yml.bak +51 -0
  2. package/LICENSE +674 -0
  3. package/README.md +59 -0
  4. package/config-overrides.js +31 -0
  5. package/dist/visualify.js +188 -0
  6. package/docs/.nojekyll +0 -0
  7. package/docs/docs/CLI.md +34 -0
  8. package/docs/docs/README.md +65 -0
  9. package/docs/docs/Rechart/bar.md +190 -0
  10. package/docs/docs/Rechart/funnel.md +193 -0
  11. package/docs/docs/Rechart/geo.md +0 -0
  12. package/docs/docs/Rechart/line.md +355 -0
  13. package/docs/docs/Rechart/liquidfill.md +0 -0
  14. package/docs/docs/Rechart/pie.md +225 -0
  15. package/docs/docs/Rechart/polar.md +0 -0
  16. package/docs/docs/Rechart/radar.md +253 -0
  17. package/docs/docs/Rechart/sankey.md +0 -0
  18. package/docs/docs/Rechart/scatter.md +0 -0
  19. package/docs/docs/Rechart/sunburst.md +0 -0
  20. package/docs/docs/Rechart/tree.md +0 -0
  21. package/docs/docs/Rechart/wordcloud.md +0 -0
  22. package/docs/docs/_404.md +52 -0
  23. package/docs/docs/_coverpage.md +11 -0
  24. package/docs/docs/_sidebar.md +43 -0
  25. package/docs/docs/components/dotBio.md +34 -0
  26. package/docs/docs/components/echart.md +82 -0
  27. package/docs/docs/components/html.md +34 -0
  28. package/docs/docs/components/macaron.md +145 -0
  29. package/docs/docs/components/markdown.md +0 -0
  30. package/docs/docs/components/more.md +142 -0
  31. package/docs/docs/components/plotly.md +62 -0
  32. package/docs/docs/components/scatterL.md +70 -0
  33. package/docs/docs/components/visium.md +57 -0
  34. package/docs/docs/configuration.md +123 -0
  35. package/docs/docs/deploy.md +31 -0
  36. package/docs/docs/log.md +1 -0
  37. package/docs/docs/more-pages.md +23 -0
  38. package/docs/docs/quickstart.md +119 -0
  39. package/docs/docs/rechart-attributes.md +74 -0
  40. package/docs/docs/rechart-basic-usage.md +162 -0
  41. package/docs/docs/static/_images/deploy-github-pages.png +0 -0
  42. package/docs/docs/static/logo/favicon.ico +0 -0
  43. package/docs/docs/static/logo/logo_128x128.png +0 -0
  44. package/docs/docs/static/logo/logo_192x192.png +0 -0
  45. package/docs/docs/static/logo/logo_256x256.png +0 -0
  46. package/docs/docs/static/logo/logo_512x512.png +0 -0
  47. package/docs/docs/static/logo/logo_64x64.png +0 -0
  48. package/docs/docs/theme.md +5 -0
  49. package/docs/index.html +71 -0
  50. package/docs/manifest.json +24 -0
  51. package/docs/static/css/fluff-stuff.css +170 -0
  52. package/docs/static/css/font-awesome.min.css +4 -0
  53. package/docs/static/css/visualify.css +25 -0
  54. package/docs/static/fonts/fontawesome-webfont.woff2 +0 -0
  55. package/docs/static/images/star.png +0 -0
  56. package/docs/static/js/configuration.js +448 -0
  57. package/docs/static/js/fluff.js +1 -0
  58. package/docs/static/js/visualify.js +188 -0
  59. package/docs/static/logo/favicon.ico +0 -0
  60. package/docs/static/logo/logo_128x128.png +0 -0
  61. package/docs/static/logo/logo_192x192.png +0 -0
  62. package/docs/static/logo/logo_256x256.png +0 -0
  63. package/docs/static/logo/logo_512x512.png +0 -0
  64. package/docs/static/logo/logo_64x64.png +0 -0
  65. package/package.json +84 -0
  66. package/rollup.config.mjs +76 -0
  67. package/src/_css/404.css +116 -0
  68. package/src/_css/App.css +38 -0
  69. package/src/_css/autoSuggestion.css +27 -0
  70. package/src/_css/circular-progress.css +33 -0
  71. package/src/_css/index.css +37 -0
  72. package/src/_css/modern.css +25 -0
  73. package/src/_media/404.png +0 -0
  74. package/src/_media/corner.svg +8 -0
  75. package/src/_media/download.svg +3 -0
  76. package/src/_media/icon.svg +1 -0
  77. package/src/_media/logo.svg +14 -0
  78. package/src/_test/App.test.js +15 -0
  79. package/src/_utils/reportWebVitals.js +13 -0
  80. package/src/core/appContext.js +27 -0
  81. package/src/core/components/Scatter.js +188 -0
  82. package/src/core/components/ScatterBio.js +572 -0
  83. package/src/core/components/VisiumPlot.js +165 -0
  84. package/src/core/components/browser.js +42 -0
  85. package/src/core/components/dotplot.js +413 -0
  86. package/src/core/components/html.js +29 -0
  87. package/src/core/components/list.js +178 -0
  88. package/src/core/components/macaron.js +201 -0
  89. package/src/core/components/markdown.js +56 -0
  90. package/src/core/components/parser.scatterBio.js +579 -0
  91. package/src/core/components/ratio.js +80 -0
  92. package/src/core/components/scatterL.js +173 -0
  93. package/src/core/components/searchbar.js +131 -0
  94. package/src/core/components/selection.js +193 -0
  95. package/src/core/components/timeline.js +281 -0
  96. package/src/core/components/visium.js +97 -0
  97. package/src/core/fetch/condfetch.js +82 -0
  98. package/src/core/fetch/fetch.js +92 -0
  99. package/src/core/fetch/json.js +29 -0
  100. package/src/core/fetch/vfetch.js +42 -0
  101. package/src/core/liveEditor.js +44 -0
  102. package/src/core/modules/codeEditorWithPreview.js +104 -0
  103. package/src/core/modules/echarts/common.js +20 -0
  104. package/src/core/modules/echarts/presetHandler.js +41 -0
  105. package/src/core/modules/echarts/presets/esodev.chromium.js +172 -0
  106. package/src/core/modules/echarts/presets/esodev.codex.js +130 -0
  107. package/src/core/modules/echarts/presets/esodev.visium.js +123 -0
  108. package/src/core/modules/echarts/presets/mmtrbc.js +186 -0
  109. package/src/core/modules/echarts.js +71 -0
  110. package/src/core/modules/echartsUtils.js +43 -0
  111. package/src/core/modules/echartswitcher.js +152 -0
  112. package/src/core/modules/replotly/presetHandler.js +24 -0
  113. package/src/core/modules/replotly/presets/minimum.js +18 -0
  114. package/src/core/modules/replotly/presets/mmtrbc.dot.js +114 -0
  115. package/src/core/modules/replotly/presets/mmtrbc.violin.js +100 -0
  116. package/src/core/modules/replotly.js +71 -0
  117. package/src/core/pages/404.js +50 -0
  118. package/src/core/pages/error.js +27 -0
  119. package/src/core/pages/jsonPage.js +62 -0
  120. package/src/core/pages/loading.js +44 -0
  121. package/src/core/parser/echart.data.js +183 -0
  122. package/src/core/parser/echart.features.js +125 -0
  123. package/src/core/parser/echart.general.js +143 -0
  124. package/src/core/parser/echart.hilbert.js +57 -0
  125. package/src/core/parser/echart.parser.js +210 -0
  126. package/src/core/parser/echart.series.js +67 -0
  127. package/src/core/parser/echart.types.js +76 -0
  128. package/src/core/parser/plotly.config.js +10 -0
  129. package/src/core/parser/plotly.data.js +132 -0
  130. package/src/core/parser/plotly.layout.js +10 -0
  131. package/src/core/parser/plotly.violin.js +18 -0
  132. package/src/core/recharts.js +62 -0
  133. package/src/core/router/alias.js +49 -0
  134. package/src/core/router/jsonRouter.js +31 -0
  135. package/src/core/themes/modern.js +32 -0
  136. package/src/core/themes/themeSelector.js +33 -0
  137. package/src/core/visualify.js +47 -0
  138. package/src/core/widgets/circularProgress.js +24 -0
  139. package/src/core/widgets/controller.js +83 -0
  140. package/src/core/widgets/errorBoundary.js +36 -0
  141. package/src/core/widgets/footer.js +177 -0
  142. package/src/core/widgets/header.js +234 -0
  143. package/src/core/widgets/layout/Grid.js +31 -0
  144. package/src/core/widgets/layout.js +36 -0
  145. package/src/core/widgets/mapping.js +42 -0
  146. package/src/index.js +62 -0
  147. package/src/setupTests.js +5 -0
@@ -0,0 +1,173 @@
1
+ /*
2
+ * @Author : Lihao leolihao@arizona.edu
3
+ * @Date : 2023-11-06 17:23:59
4
+ * @FilePath : /visualifyjs/src/core/components/scatterL.js
5
+ * @Description :
6
+ * Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
+ */
8
+ import React, { useEffect, useRef, useState } from 'react';
9
+ import { useAppContext } from '../appContext';
10
+ import Loading from '../pages/loading';
11
+ import {
12
+ initChart,
13
+ handleChartForSharedDataChange,
14
+ } from '../modules/echartsUtils';
15
+ import {
16
+ parseConfig,
17
+ validateConfig,
18
+ handleAPI,
19
+ handleSimplyLoad,
20
+ onDataZoom,
21
+ parseData,
22
+ outputAxisValues,
23
+ } from './parser.scatterBio';
24
+
25
+ function ScatterBio({ props, style }) {
26
+ const chartRef = useRef(null);
27
+ const { sharedData } = useAppContext();
28
+ const [loading, setLoading] = useState({ active: true, message: null });
29
+
30
+ // Store the previous sharedData value using a ref
31
+ const previousSharedDataRef = useRef(null);
32
+
33
+ useEffect(() => {
34
+ let option = parseConfig(props);
35
+ console.log('option: ', option);
36
+ let fetched_dat = null;
37
+
38
+ // Check if the sharedData has changed
39
+ handleChartForSharedDataChange(
40
+ chartRef,
41
+ sharedData,
42
+ previousSharedDataRef,
43
+ () => {
44
+ option.xAxis.min = props?.echart?.xAxis?.min;
45
+ option.xAxis.max = props?.echart?.xAxis?.max;
46
+ option.yAxis.min = props?.echart?.yAxis?.min;
47
+ option.yAxis.max = props?.echart?.yAxis?.max;
48
+ },
49
+ );
50
+
51
+ // Simulate fetching data asynchronously (replace with your data fetching logic)
52
+ const updatePlot = async () => {
53
+ try {
54
+ setLoading({ active: true, message: null });
55
+ validateConfig(props.config);
56
+ const myChart = initChart(chartRef, option);
57
+ if (props.config.simpleload)
58
+ handleSimplyLoad(props.config.simpleload);
59
+ else {
60
+ const ibox = props.config?.ibox ?? {
61
+ xMin: -9999,
62
+ yMin: -9999,
63
+ xMax: 9999,
64
+ yMax: 9999,
65
+ };
66
+ fetched_dat = await handleAPI(
67
+ props.config,
68
+ sharedData,
69
+ ibox,
70
+ );
71
+ console.log(fetched_dat, 'fetched_dat');
72
+ }
73
+ var { series, legend, visualMap, title } = parseData(
74
+ fetched_dat,
75
+ props.config,
76
+ sharedData,
77
+ );
78
+ // Chart options
79
+ option.series = props?.echart?.series ?? series;
80
+ option.legend = {
81
+ ...option.legend,
82
+ ...legend,
83
+ };
84
+
85
+ option.visualMap = visualMap;
86
+ option.title = {
87
+ ...option.title,
88
+ text: title,
89
+ };
90
+
91
+ // Set the initial option
92
+ myChart.setOption(option);
93
+
94
+ let zoomTimeout;
95
+ const zoom_action = () => {
96
+ clearTimeout(zoomTimeout);
97
+ zoomTimeout = setTimeout(async () => {
98
+ await onDataZoom(
99
+ props,
100
+ sharedData,
101
+ fetched_dat,
102
+ myChart,
103
+ option,
104
+ );
105
+ }, 500);
106
+ };
107
+
108
+ myChart.on('dataZoom', zoom_action);
109
+
110
+ setLoading({ active: false, message: null });
111
+
112
+ let bbox = outputAxisValues(myChart);
113
+ option.xAxis.min = option.xAxis.min ?? bbox.xMin;
114
+ option.xAxis.max = option.xAxis.max ?? bbox.xMax;
115
+ option.yAxis.min = option.yAxis.min ?? bbox.yMin;
116
+ option.yAxis.max = option.yAxis.max ?? bbox.yMax;
117
+
118
+ // Cleanup event listeners on component unmount
119
+ return () => {
120
+ myChart.off('dataZoom', zoom_action);
121
+ myChart.dispose();
122
+ };
123
+ } catch (error) {
124
+ setLoading({ active: true, message: error.message });
125
+ }
126
+ };
127
+
128
+ // Execute the updatePlot function
129
+ updatePlot();
130
+
131
+ // Observe changes to the size of the chart container
132
+ const resizeObserver = new ResizeObserver((entries) => {
133
+ for (let entry of entries) {
134
+ if (entry.contentRect.width && entry.contentRect.height) {
135
+ updatePlot();
136
+ resizeObserver.disconnect();
137
+ }
138
+ }
139
+ });
140
+
141
+ if (chartRef.current) {
142
+ resizeObserver.observe(chartRef.current);
143
+ }
144
+
145
+ // Cleanup function
146
+ return () => {
147
+ resizeObserver.disconnect();
148
+ };
149
+ }, [props, sharedData]);
150
+
151
+ return (
152
+ <div
153
+ id={props.id}
154
+ style={{ ...style, position: 'relative' }}>
155
+ {loading.active && (
156
+ <Loading
157
+ message={loading.message}
158
+ style={{ marginTop: '10px' }}
159
+ />
160
+ )}
161
+ <div
162
+ ref={chartRef}
163
+ style={{
164
+ opacity: loading.active ? 0 : 1,
165
+ width: props.config?.size?.width || '100%',
166
+ height: props.config?.size?.height || '100%',
167
+ }}
168
+ />
169
+ </div>
170
+ );
171
+ }
172
+
173
+ export default ScatterBio;
@@ -0,0 +1,131 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import '../../_css/autoSuggestion.css';
3
+ import { useAppContext } from '../appContext';
4
+ import conditionalFetch from '../fetch/condfetch';
5
+
6
+ function SearchBar({ props, style }) {
7
+ const [suggestions, setSuggestions] = useState([]);
8
+ const [wordlist, setWordlist] = useState([]);
9
+ const [inputValue, setInputValue] = useState('');
10
+
11
+ const { sharedData, setSharedData } = useAppContext();
12
+
13
+ const {
14
+ id,
15
+ title = 'Search',
16
+ className,
17
+ style: _style = { height: '130px', width: '200px' },
18
+ placeholder = 'Search...',
19
+ wordlimit = 15,
20
+ suggestLen = 3,
21
+ searchStyle = {
22
+ borderRadius: '15px',
23
+ width: '100%',
24
+ },
25
+ config = {},
26
+ debug,
27
+ } = props;
28
+
29
+ if (config.save && typeof config.save !== 'string') config.save = id;
30
+
31
+ useEffect(() => {
32
+ if (config.source) {
33
+ const fetchWordlist = async () => {
34
+ const response = await conditionalFetch(
35
+ config.source,
36
+ sharedData,
37
+ null,
38
+ null,
39
+ );
40
+ if (response) {
41
+ const newWordlist =
42
+ response[config.source.responseKey] || response;
43
+ setWordlist(newWordlist);
44
+ } else if (config.source.trigger) {
45
+ console.log('wait for trigger');
46
+ } else {
47
+ console.error('Error fetching wordlist.');
48
+ }
49
+ };
50
+
51
+ if (Array.isArray(config.source)) {
52
+ setWordlist(config.source);
53
+ } else if (typeof config.source === 'object') {
54
+ fetchWordlist();
55
+ }
56
+ }
57
+ }, [config.source, debug, sharedData]);
58
+
59
+ useEffect(() => {
60
+ // 更新inputValue,但不要影响其他组件的共享数据
61
+ setInputValue(sharedData[id] || '');
62
+ }, [sharedData, id]);
63
+
64
+ const handleInputChange = (e) => {
65
+ const inputValue = e.target.value;
66
+ const inputValueLowerCase = inputValue.trim().toLowerCase();
67
+ setInputValue(inputValue);
68
+
69
+ if (inputValue.length >= suggestLen) {
70
+ setSuggestions(
71
+ wordlist
72
+ .filter((word) =>
73
+ word.toLowerCase().includes(inputValueLowerCase),
74
+ )
75
+ .slice(0, wordlimit),
76
+ );
77
+ }
78
+
79
+ if (
80
+ config.save &&
81
+ (wordlist.includes(inputValue) || inputValue === '')
82
+ ) {
83
+ setSharedData((prevSharedData) => ({
84
+ ...prevSharedData,
85
+ [config.save]: inputValue,
86
+ }));
87
+ }
88
+ };
89
+
90
+ const handleSuggestionClick = (suggestion) => {
91
+ setInputValue(suggestion);
92
+ setSuggestions([]);
93
+
94
+ if (config.save) {
95
+ setSharedData((prevSharedData) => ({
96
+ ...prevSharedData,
97
+ [config.save]: suggestion,
98
+ }));
99
+ }
100
+ };
101
+
102
+ return (
103
+ <div
104
+ id={id}
105
+ style={{ ...style, ..._style }}
106
+ className={className}>
107
+ {title && <h3>{title}</h3>}
108
+ <div className='autosuggestion'>
109
+ <input
110
+ type='text'
111
+ placeholder={placeholder}
112
+ style={searchStyle}
113
+ value={inputValue}
114
+ onChange={handleInputChange}
115
+ />
116
+ <ul className='suggestion-list'>
117
+ {suggestions.map((suggestion, index) => (
118
+ <li
119
+ key={index}
120
+ className='suggestion-item'
121
+ onClick={() => handleSuggestionClick(suggestion)}>
122
+ {suggestion}
123
+ </li>
124
+ ))}
125
+ </ul>
126
+ </div>
127
+ </div>
128
+ );
129
+ }
130
+
131
+ export default SearchBar;
@@ -0,0 +1,193 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { useAppContext } from '../appContext';
3
+ import simplefetch from '../fetch/fetch';
4
+ import Select from 'react-select';
5
+
6
+ function Selection({ props, style }) {
7
+ const { debug } = props;
8
+ const { style: _style } = props;
9
+
10
+ // Render title if it exists
11
+ const { title } = props;
12
+ const renderTitle = () => {
13
+ return title && <h3>{title}</h3>;
14
+ };
15
+
16
+ // If val is exist, store it to SharedData
17
+ const { sharedData, setSharedData } = useAppContext();
18
+
19
+ // store attr in state so that we can update it when it changes
20
+ const [selected, setSelected] = useState([]);
21
+
22
+ // store options in state so that we can update it when it changes
23
+ const [selectionOptions, setSelectionOptions] = useState([]);
24
+
25
+ const [menuIsOpen, setMenuIsOpen] = useState();
26
+
27
+ useEffect(() => {
28
+ const { selection, urlval, rm_suffix, nested = false, entry } = props;
29
+
30
+ const fetchData = async () => {
31
+ if (nested) {
32
+ if (entry) {
33
+ const entryValue = sharedData[entry];
34
+ if (entryValue && entryValue.length > 0) {
35
+ if (debug)
36
+ console.log('Selection: entryValue:', entryValue);
37
+ if (debug)
38
+ console.log(
39
+ 'Selection: nested url:',
40
+ selection + entryValue[0],
41
+ urlval,
42
+ );
43
+ try {
44
+ const response = await simplefetch(
45
+ selection + entryValue[0],
46
+ {
47
+ key: urlval,
48
+ debug: debug,
49
+ },
50
+ );
51
+ // remove the suffix "_metadata" from the options
52
+ try {
53
+ const removed_suffix = response.map((item) =>
54
+ item.replace(rm_suffix, ''),
55
+ );
56
+ // insert the "None" into removed_Suffix
57
+ removed_suffix.unshift('None');
58
+ if (debug)
59
+ console.log(
60
+ 'Removed suffix:',
61
+ removed_suffix,
62
+ );
63
+ setSelectionOptions(removed_suffix);
64
+ } catch (error) {
65
+ setSelectionOptions([]);
66
+ }
67
+ } catch (error) {
68
+ console.error('Error fetching options:', error);
69
+ }
70
+ }
71
+ } else
72
+ console.error(
73
+ 'Error: nested is true but entry is not defined.',
74
+ );
75
+ } else {
76
+ try {
77
+ const response = await simplefetch(selection, {
78
+ key: urlval,
79
+ debug: debug,
80
+ });
81
+ // remove the suffix "_metadata" from the options
82
+ try {
83
+ const removed_suffix = response.map((item) =>
84
+ item.replace(rm_suffix, ''),
85
+ );
86
+ //console.log("Removed suffix:", removed_suffix);
87
+ setSelectionOptions(removed_suffix);
88
+ } catch (error) {
89
+ setSelectionOptions(response);
90
+ }
91
+ } catch (error) {
92
+ console.error('Error fetching options:', error);
93
+ }
94
+ }
95
+ };
96
+
97
+ fetchData();
98
+ }, [props, setSelectionOptions, sharedData, debug]);
99
+
100
+ const handleChange = (selectedOptions) => {
101
+ if (single) {
102
+ // If single selection, selectedOptions will be an object
103
+ setSelected(selectedOptions ? [selectedOptions] : []);
104
+ } else {
105
+ // If multi-selection, selectedOptions will be an array
106
+ setSelected(selectedOptions || []);
107
+ }
108
+ };
109
+
110
+ const onInputChange = (inputValue, { action, prevInputValue }) => {
111
+ if (action === 'input-change') return inputValue;
112
+ if (action === 'menu-close') {
113
+ if (prevInputValue) setMenuIsOpen(true);
114
+ else setMenuIsOpen(undefined);
115
+ }
116
+ return prevInputValue;
117
+ };
118
+
119
+ // ----------------- Selection bar ------------------------------------------------
120
+ const { config = {} } = props;
121
+ const {
122
+ bar_width = '300px',
123
+ bar_margin = '0 auto',
124
+ bar_maxHeight = '300px',
125
+ menu_maxHeight = '300px',
126
+ single = false,
127
+ } = config;
128
+
129
+ const renderSelection = () => {
130
+ const options = selectionOptions.map((item) => ({
131
+ value: item,
132
+ label: item,
133
+ }));
134
+
135
+ return (
136
+ <div className='select-wrapper'>
137
+ <Select
138
+ isMulti={!single}
139
+ options={options}
140
+ value={selected}
141
+ onChange={handleChange}
142
+ onInputChange={onInputChange}
143
+ menuIsOpen={menuIsOpen}
144
+ styles={{
145
+ container: (provided) => ({
146
+ ...provided,
147
+ width: bar_width,
148
+ margin: bar_margin,
149
+ maxHeight: bar_maxHeight,
150
+ }),
151
+ valueContainer: (provided) => ({
152
+ ...provided,
153
+ maxHeight: bar_maxHeight ?? 'auto',
154
+ overflowY: 'auto',
155
+ }),
156
+ menu: (provided) => ({
157
+ ...provided,
158
+ maxHeight: menu_maxHeight ?? 'auto', // Set the max height as required
159
+ overflowY: 'auto', // Enable scroll if exceeds max height
160
+ }),
161
+ }}
162
+ />
163
+ </div>
164
+ );
165
+ };
166
+
167
+ // Store value to SharedData
168
+ const { id, val } = props;
169
+
170
+ useEffect(() => {
171
+ if (val) {
172
+ setSharedData((prevSharedData) => {
173
+ const selectedValues = selected
174
+ ? selected.map((option) => option.value)
175
+ : [];
176
+ //console.log("Selection: selected:", selectedValues);
177
+ return { ...prevSharedData, [val]: selectedValues };
178
+ });
179
+ }
180
+ }, [selected, val, setSharedData]);
181
+
182
+ return (
183
+ <div
184
+ key={id}
185
+ style={{ ...style, ..._style }}
186
+ className='selection-box-container'>
187
+ {renderTitle()}
188
+ {renderSelection()}
189
+ </div>
190
+ );
191
+ }
192
+
193
+ export default Selection;