Added sceneries list
+Added built-in sceneries list (sceneries are not provided with the repo due to copyright reasons) *Renamed FileSelect to CustomFileSelect *Updated README.md
This commit is contained in:
parent
3137a46e32
commit
af631bc4e5
2
.gitignore
vendored
2
.gitignore
vendored
@ -21,3 +21,5 @@
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
public/sceneries/*
|
||||
@ -1,8 +1,11 @@
|
||||
# td2-visualizer
|
||||
|
||||
Narzędzie do przeglądania plików scenerii symulatora Train Driver 2 (.SC) w przeglądarce. Umożliwia szybkie podejrzenie układu torowego dowolnej scenerii, jej szlaków zewnętrzych, semaforów, wskaźników, spawnów, numerów rozjazdów i wiele więcej
|
||||
Narzędzie do przeglądania plików scenerii symulatora Train Driver 2 (.SC) w przeglądarce. Umożliwia szybkie podejrzenie układu torowego dowolnej scenerii, jej szlaków zewnętrzych, semaforów, wskaźników, spawnów, numerów rozjazdów i wiele więcej. Z powodów praw autorskich wersja github nie posiada dołączonych plików scenerii.
|
||||
|
||||
A tool for viewing Train Driver 2 simulator scenery files (.SC) in the browser. It allows for quick lookup of the track layout of any scenery, its external routes, signals, signs, spawns, switch numbers, and much more
|
||||
A tool for viewing Train Driver 2 simulator scenery files (.SC) in the browser. It allows for quick lookup of the track layout of any scenery, its external routes, signals, signs, spawns, switch numbers, and much more. Due to copyright reasons, the github version does not include scenery files.
|
||||
|
||||
Wątek na forum / Forum thread:
|
||||
https://td2.info.pl/narzedzie-tools/nowy-td2-visualizer!/
|
||||
|
||||
#
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import MainContext from "../../contexts/MainContext";
|
||||
import { useZoomPanEmitter } from "../../hooks/useZoomPubSub";
|
||||
import SceneryFilesHelper from "../../helpers/sceneryFilesHelper";
|
||||
|
||||
export default function FileSelect() {
|
||||
export default function CustomFileSelect() {
|
||||
const {setScenery, setIsLoading} = useContext(MainContext);
|
||||
const { center } = useZoomPanEmitter();
|
||||
|
||||
@ -18,8 +18,8 @@ export default function FileSelect() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='file-select'>
|
||||
<input type='file' id='file-input' onChange={handleFileChange} />
|
||||
<div className='custom-file-select'>
|
||||
<input type='file' id='custom-file-input' onChange={handleFileChange} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
49
src/components/toolbar/SceneriesList.js
Normal file
49
src/components/toolbar/SceneriesList.js
Normal file
@ -0,0 +1,49 @@
|
||||
import { useContext, useState, useEffect } from 'react';
|
||||
import MainContext from '../../contexts/MainContext';
|
||||
import { useZoomPanEmitter } from '../../hooks/useZoomPubSub';
|
||||
import SceneryFilesHelper from '../../helpers/sceneryFilesHelper';
|
||||
|
||||
export default function SceneriesList(props) {
|
||||
const {setScenery, setIsLoading} = useContext(MainContext);
|
||||
const [ sceneryNames, setSceneryNames ] = useState(null);
|
||||
const { center } = useZoomPanEmitter();
|
||||
|
||||
const handleSelectChange = async (event) => {
|
||||
const name = event.target.value;
|
||||
|
||||
setIsLoading(true);
|
||||
const scenery = await SceneryFilesHelper.load(name, center);
|
||||
setScenery(scenery);
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
const updateSceneryList = async () => {
|
||||
const sceneries = await SceneryFilesHelper.getList();
|
||||
setSceneryNames(sceneries);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
updateSceneryList();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className='sceneries-list'>
|
||||
<select onChange={handleSelectChange} defaultValue="">
|
||||
<option value="" disabled>Select a scenery</option>
|
||||
{Array.isArray(sceneryNames) && sceneryNames.map((name) => (
|
||||
<SceneriesListOption key={name} name={name} />
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SceneriesListOption({ name }) {
|
||||
// remove .lite.sc or .sc
|
||||
const regex = /\.(lite\.)?sc$/i;
|
||||
const displayName = name.replace(regex, '');
|
||||
|
||||
return (
|
||||
<option value={name}>{displayName}</option>
|
||||
);
|
||||
}
|
||||
@ -1,14 +1,17 @@
|
||||
import React from 'react';
|
||||
import './Toolbar.css';
|
||||
import LoadingIndicator from './LoadingIndicator';
|
||||
import FileSelect from './FileSelect';
|
||||
import CustomFileSelect from './CustomFileSelect';
|
||||
import SideMenuToggle from './SideMenuToggle';
|
||||
import SceneriesList from './SceneriesList';
|
||||
|
||||
export default function Toolbar() {
|
||||
return (
|
||||
<div className='toolbar-cont'>
|
||||
<div className='toolbar'>
|
||||
<FileSelect />
|
||||
<SceneriesList />
|
||||
or
|
||||
<CustomFileSelect />
|
||||
<div className='toolbar-spacer'></div>
|
||||
<SideMenuToggle />
|
||||
</div>
|
||||
|
||||
@ -41,6 +41,11 @@ const Constants = {
|
||||
errors: {
|
||||
invalidSceneryInfo: true
|
||||
},
|
||||
sceneryFiles: {
|
||||
fetchDisable: false,
|
||||
fetchBaseUrl: `${process.env.PUBLIC_URL}/sceneries/`,
|
||||
fetchListUrl: `${process.env.PUBLIC_URL}/sceneries/sceneries.json`,
|
||||
},
|
||||
layers: [
|
||||
{
|
||||
id: 'tracks',
|
||||
|
||||
@ -1,9 +1,44 @@
|
||||
import Constants from "./constants";
|
||||
import SceneryParser from "../model/scenery-parser";
|
||||
import SceneryParserLog from "../model/scenery-parser-log";
|
||||
import { showCustomDialog } from "../services/dialogService";
|
||||
import SceneryLoadedDialog from "../components/scenery-loaded-dialog/SceneryLoadedDialog";
|
||||
|
||||
export default class SceneryFilesHelper {
|
||||
static async fetch(url, toJson) {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return toJson ? await response.json() : await response.blob();
|
||||
} catch (error) {
|
||||
console.error(`Failed to fetch from ${url}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
static async getList() {
|
||||
try {
|
||||
const url = Constants.sceneryFiles.fetchListUrl;
|
||||
return await this.fetch(url, true);
|
||||
} catch(error) {
|
||||
console.error(`Failed to fetch sceneries list`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static async getScenery(name) {
|
||||
const url = `${Constants.sceneryFiles.fetchBaseUrl}/${name}`;
|
||||
return await this.fetch(url, false);
|
||||
}
|
||||
|
||||
static async load(name, centerFn = null) {
|
||||
const file = await this.getScenery(name);
|
||||
return await this.loadCustom(file, centerFn);
|
||||
}
|
||||
|
||||
static async loadCustom(file, centerFn = null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
SceneryParserLog.clear();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user