Skip to content

Commit a3c6821

Browse files
authored
Merge pull request #631 from OpenKnowledgeMaps/old-code-removal
Old code removal
2 parents 48cd567 + cced4c6 commit a3c6821

33 files changed

Lines changed: 1009 additions & 1109 deletions

.babelrc

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
{
2-
"presets": [
3-
"@babel/preset-react",
4-
"@babel/preset-env"
2+
"presets": ["@babel/preset-react", "@babel/preset-env"],
3+
"plugins": [
4+
[
5+
"@babel/plugin-transform-runtime",
6+
{
7+
"regenerator": true
8+
}
59
]
6-
}
10+
]
11+
}

package-lock.json

Lines changed: 225 additions & 143 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
},
2525
"homepage": "https://github.com/OpenKnowledgeMaps/Headstart#readme",
2626
"dependencies": {
27+
"@babel/runtime": "^7.17.2",
2728
"@citation-js/core": "^0.5.4",
2829
"@citation-js/plugin-csl": "^0.5.4",
2930
"bootstrap": "3.4.1",
31+
"bowser": "^2.11.0",
3032
"d3": "^3.5.17",
3133
"d3-ease": "^2.0.0",
3234
"d3-selection": "^2.0.0",
@@ -35,10 +37,8 @@
3537
"hyphenation.en-us": "*",
3638
"hypher": "^0.2.4",
3739
"iso-639-1": "^2.1.9",
38-
"javascript-state-machine": "^2.3.5",
3940
"jquery": "^3.5.1",
4041
"mark.js": "^8.11.1",
41-
"mediator-js": "^0.9.9",
4242
"react": "^16.13.1",
4343
"react-bootstrap": "^0.33.1",
4444
"react-dom": "^16.13.1",
@@ -51,6 +51,7 @@
5151
"devDependencies": {
5252
"@babel/core": "^7.15.5",
5353
"@babel/eslint-parser": "^7.15.8",
54+
"@babel/plugin-transform-runtime": "^7.17.0",
5455
"@babel/preset-env": "^7.15.6",
5556
"@babel/preset-react": "^7.14.5",
5657
"babel-core": "^6.11.4",
@@ -66,7 +67,6 @@
6667
"eslint-plugin-flowtype": "^4.7.0",
6768
"eslint-plugin-react": "^7.20.3",
6869
"eslint-plugin-react-hooks": "^4.2.1-alpha-02f411578-20211019",
69-
"exports-loader": "^3.0.0",
7070
"file-loader": "^6.2.0",
7171
"imports-loader": "^3.0.0",
7272
"jest": "^27.3.1",

vis/app.js

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
1-
/* Load stylesheets and bootstrap */
2-
import 'styles/main.scss';
1+
import "styles/main.scss";
32

4-
/* Import headstart module to initiliase HeadstartFSM */
5-
/* Notice 'import * as hs' -> hs.headstart is not read-only */
6-
import config from 'config';
7-
import * as hs from 'headstart';
8-
import 'bootstrap';
9-
import 'bootstrap/dist/css/bootstrap.min.css';
3+
import config from "config";
4+
import "bootstrap";
5+
import "bootstrap/dist/css/bootstrap.min.css";
106

11-
var start = function(json_data) {
12-
if(data_config) Object.assign(config, data_config);
13-
window.namespace = "headstart";
14-
window.headstartInstance = new hs.HeadstartFSM(json_data);
15-
window.headstartInstance.start();
16-
}
7+
// needed for draggable modals (it can be refactored with react-bootstrap though)
8+
import "./lib/jquery-ui.min.js";
179

18-
export {start};
10+
import HeadstartRunner from "./js/HeadstartRunner";
11+
12+
const start = (additional_config) => {
13+
if (data_config) {
14+
Object.assign(config, data_config);
15+
}
16+
if (additional_config) {
17+
Object.assign(config, additional_config);
18+
}
19+
20+
const headstartRunner = new HeadstartRunner(config);
21+
headstartRunner.run();
22+
};
23+
24+
export { start };

vis/js/HeadstartRunner.js

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import ReactDOM from "react-dom";
2+
import React from "react";
3+
import { createStore } from "redux";
4+
import { Provider } from "react-redux";
5+
6+
import rootReducer, { getInitialState } from "./reducers";
7+
import {
8+
initializeStore,
9+
updateDimensions,
10+
applyForceAreas,
11+
applyForcePapers,
12+
} from "./actions";
13+
14+
import applyHeadstartMiddleware from "./middleware";
15+
16+
import { applyForce } from "./utils/force";
17+
18+
import { getChartSize, getListSize } from "./utils/dimensions";
19+
import Headstart from "./components/Headstart";
20+
import { removeQueryParams } from "./utils/url";
21+
import debounce from "./utils/debounce";
22+
import DataManager from "./dataprocessing/managers/DataManager";
23+
import FetcherFactory from "./dataprocessing/fetchers/FetcherFactory";
24+
import onBackButtonClick from "./utils/backButton";
25+
26+
import Bowser from "bowser";
27+
28+
class HeadstartRunner {
29+
constructor(config) {
30+
this.config = config;
31+
this.dataManager = new DataManager(config);
32+
33+
this.originalTitle = document.title;
34+
this.actionQueue = [];
35+
36+
const initialState = getInitialState(this.config);
37+
const middleware = applyHeadstartMiddleware(this);
38+
this.store = createStore(rootReducer, initialState, middleware);
39+
40+
this.hsContainer = document.getElementById(this.config.tag);
41+
this.hsContainer.classList.add("headstart");
42+
43+
this.backendData = [];
44+
}
45+
46+
async run() {
47+
this.checkBrowserVersion();
48+
this.renderReact();
49+
this.addBackButtonListener();
50+
this.backendData = await this.fetchData();
51+
this.dispatchDataEvent(this.backendData);
52+
this.initStore(this.backendData);
53+
this.applyQueryParams();
54+
this.addWindowResizeListener();
55+
}
56+
57+
checkBrowserVersion() {
58+
const browser = Bowser.getParser(window.navigator.userAgent);
59+
// TODO use proper browser filtering https://www.npmjs.com/package/bowser#filtering-browsers
60+
if (
61+
!["chrome", "firefox", "safari"].includes(browser.getBrowserName(true))
62+
) {
63+
alert(
64+
"You are using an unsupported browser. " +
65+
"This visualization was successfully tested " +
66+
"with the latest versions of Chrome, Firefox and Safari."
67+
);
68+
}
69+
}
70+
71+
renderReact() {
72+
ReactDOM.render(
73+
<Provider store={this.store}>
74+
<Headstart />
75+
</Provider>,
76+
this.hsContainer
77+
);
78+
}
79+
80+
addBackButtonListener() {
81+
const handleBackButtonClick = () => {
82+
onBackButtonClick(this.dataManager, this.store, this.config);
83+
};
84+
85+
window.addEventListener("popstate", debounce(handleBackButtonClick, 300));
86+
}
87+
88+
async fetchData() {
89+
const config = this.config;
90+
91+
const dataFetcher = FetcherFactory.getInstance(config.mode, {
92+
serverUrl: config.server_url,
93+
files: config.files,
94+
isStreamgraph: config.is_streamgraph,
95+
});
96+
97+
return await dataFetcher.getData();
98+
}
99+
100+
initStore(backendData) {
101+
const config = this.config;
102+
103+
const { size, width, height } = getChartSize(config);
104+
105+
this.dataManager.parseData(backendData, size);
106+
107+
const context = this.dataManager.context;
108+
109+
const list = getListSize(config, context, size);
110+
111+
this.store.dispatch(
112+
initializeStore(
113+
config,
114+
context,
115+
this.dataManager.papers,
116+
this.dataManager.areas,
117+
this.dataManager.streams,
118+
size,
119+
width,
120+
height,
121+
list.height,
122+
this.dataManager.scalingFactors
123+
)
124+
);
125+
126+
if (!this.config.is_streamgraph) {
127+
this.applyForceLayout();
128+
}
129+
}
130+
131+
applyQueryParams() {
132+
const queryParams = new URLSearchParams(window.location.search);
133+
// enable this for ability to share link to a zoomed bubble / paper
134+
// if (queryParams.has("paper")) {
135+
// selectUrlPaper(this.dataManager, this.store, this.config);
136+
// } else {
137+
// zoomUrlArea(this.dataManager, this.store, this.config);
138+
// }
139+
// remove the following lines if the previous line is uncommented
140+
const paramsToRemove = [];
141+
if (queryParams.has("area")) {
142+
paramsToRemove.push("area");
143+
}
144+
if (queryParams.has("paper")) {
145+
paramsToRemove.push("paper");
146+
}
147+
if (paramsToRemove.length > 0) {
148+
removeQueryParams(...paramsToRemove);
149+
}
150+
}
151+
152+
addWindowResizeListener() {
153+
window.addEventListener("resize", () => {
154+
const chart = getChartSize(this.config, this.dataManager.context);
155+
const list = getListSize(
156+
this.config,
157+
this.dataManager.context,
158+
chart.size
159+
);
160+
this.store.dispatch(updateDimensions(chart, list));
161+
});
162+
}
163+
164+
// used after each INITIALIZE
165+
applyForceLayout() {
166+
const state = this.store.getState();
167+
applyForce(
168+
state.areas.list,
169+
state.data.list,
170+
state.chart.width,
171+
(newAreas) =>
172+
this.store.dispatch(applyForceAreas(newAreas, state.chart.height)),
173+
(newPapers) =>
174+
this.store.dispatch(applyForcePapers(newPapers, state.chart.height)),
175+
this.config
176+
);
177+
}
178+
179+
/**
180+
* Dispatches a custom event that the data has been loaded for reuse outside of Headstart.
181+
* @param {Object} data the raw data
182+
*/
183+
dispatchDataEvent(data) {
184+
const elem = document.getElementById(this.config.tag);
185+
const event = new CustomEvent("headstart.data.loaded", {
186+
detail: { data },
187+
});
188+
elem.dispatchEvent(event);
189+
}
190+
191+
rescaleMap(scaleBy, baseUnit, isContentBased, initialSort) {
192+
this.config.scale_by = scaleBy;
193+
this.config.base_unit = baseUnit;
194+
this.config.content_based = isContentBased;
195+
this.config.initial_sort = initialSort;
196+
// TODO this might cause a bug (or there might be more params that require setting to false)
197+
// bug description: map different after rescaling to the same metric
198+
this.config.dynamic_sizing = false;
199+
200+
this.initStore(this.backendData);
201+
}
202+
}
203+
204+
export default HeadstartRunner;

vis/js/actions/index.js

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,6 @@ export const zoomOut = (callback, isFromBackButton = false) => ({
4242
isFromBackButton,
4343
});
4444

45-
/**
46-
* Action for initializing the data that are known from the very beginning.
47-
* @param {Object} configObject the default_config.json + data_config.json
48-
*/
49-
export const preinitializeStore = (configObject) => ({
50-
type: "PREINITIALIZE",
51-
configObject,
52-
});
53-
5445
/**
5546
* Action for initializing the data that aren't known in advance.
5647
* @param {Object} configObject the default_config.json + data_config.json
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Fetcher {
2+
config = {
3+
serverUrl: "",
4+
files: [],
5+
isStreamgraph: false,
6+
};
7+
8+
constructor(config) {
9+
this.config = config;
10+
}
11+
12+
async getData() {
13+
throw new Error("Function not implemented.");
14+
}
15+
}
16+
17+
export default Fetcher;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import Fetcher from "./Fetcher";
2+
import GsheetsFetcher from "./GsheetsFetcher";
3+
import LocalFetcher from "./LocalFetcher";
4+
import ServerFetcher from "./ServerFetcher";
5+
6+
class FetcherFactory {
7+
static getInstance(type, config) {
8+
switch (type) {
9+
case "local_files":
10+
return new LocalFetcher(config);
11+
case "gsheets":
12+
return new GsheetsFetcher(config);
13+
case "search_repos":
14+
return new ServerFetcher(config);
15+
default:
16+
return new Fetcher(config);
17+
}
18+
}
19+
}
20+
21+
export default FetcherFactory;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import Fetcher from "./Fetcher";
2+
3+
class GsheetsFetcher extends Fetcher {
4+
async getData() {
5+
const url =
6+
this.config.serverUrl +
7+
"services/getGSheetsMap.php?vis_id=" +
8+
this.config.files[0].file +
9+
"&q=" +
10+
this.config.files[0].title +
11+
"&context=true&streamgraph=" +
12+
this.config.isStreamgraph;
13+
14+
const response = await fetch(url);
15+
const data = await response.json();
16+
17+
return data;
18+
}
19+
}
20+
21+
export default GsheetsFetcher;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import Fetcher from "./Fetcher";
2+
3+
class LocalFetcher extends Fetcher {
4+
async getData() {
5+
return await this.getDataFromFile(0);
6+
}
7+
8+
async getDataFromFile(fileIndex) {
9+
const url = this.config.files[fileIndex].file;
10+
11+
const response = await fetch(url);
12+
// TODO csv (based on config.input_format)
13+
const data = await response.json();
14+
15+
return data;
16+
}
17+
}
18+
19+
export default LocalFetcher;

0 commit comments

Comments
 (0)