mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-23 12:31:24 +01:00
Merge remote-tracking branch 'upstream/master' into dev-submap
This commit is contained in:
commit
1d1cd0bb71
15 changed files with 594 additions and 607 deletions
29
dropbox.html
29
dropbox.html
|
|
@ -1,7 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" dir="ltr">
|
<html lang="en" dir="ltr">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<script type="text/javascript" src="https://unpkg.com/dropbox@10.8.0/dist/Dropbox-sdk.min.js"></script>
|
<script type="text/javascript" src="https://unpkg.com/dropbox@10.8.0/dist/Dropbox-sdk.min.js"></script>
|
||||||
<title>FMG Dropbox Auth</title>
|
<title>FMG Dropbox Auth</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
@ -13,32 +13,35 @@
|
||||||
window.
|
window.
|
||||||
*/
|
*/
|
||||||
const REDIRECT_URI = window.location.origin + window.location.pathname;
|
const REDIRECT_URI = window.location.origin + window.location.pathname;
|
||||||
const dbxAuth = new Dropbox.DropboxAuth({ clientId: 'sp7tzwm27u2w5ns', });
|
const dbxAuth = new Dropbox.DropboxAuth({clientId: "pdr9ae64ip0qno4"});
|
||||||
|
|
||||||
const spObj = new URLSearchParams(window.location.search);
|
const spObj = new URLSearchParams(window.location.search);
|
||||||
const searchParams = Object.fromEntries(spObj.entries())
|
const searchParams = Object.fromEntries(spObj.entries());
|
||||||
|
|
||||||
if (searchParams.code) getToken()
|
if (searchParams.code) getToken();
|
||||||
else doAuth(); // start authentication
|
else doAuth(); // start authentication
|
||||||
|
|
||||||
function doAuth() {
|
function doAuth() {
|
||||||
dbxAuth.getAuthenticationUrl(REDIRECT_URI, undefined, 'code', 'offline', undefined, undefined, true)
|
dbxAuth
|
||||||
|
.getAuthenticationUrl(REDIRECT_URI, undefined, "code", "offline", undefined, undefined, true)
|
||||||
.then(authUrl => {
|
.then(authUrl => {
|
||||||
window.sessionStorage.clear();
|
window.sessionStorage.clear();
|
||||||
window.sessionStorage.setItem("codeVerifier", dbxAuth.codeVerifier);
|
window.sessionStorage.setItem("codeVerifier", dbxAuth.codeVerifier);
|
||||||
window.location.href = authUrl;
|
window.location.href = authUrl;
|
||||||
})
|
})
|
||||||
.catch((error) => console.error(error));
|
.catch(error => console.error(error));
|
||||||
};
|
}
|
||||||
|
|
||||||
function getToken() {
|
function getToken() {
|
||||||
dbxAuth.setCodeVerifier(window.sessionStorage.getItem('codeVerifier'));
|
dbxAuth.setCodeVerifier(window.sessionStorage.getItem("codeVerifier"));
|
||||||
dbxAuth.getAccessTokenFromCode(REDIRECT_URI, searchParams.code)
|
dbxAuth
|
||||||
.then((resp) => {
|
.getAccessTokenFromCode(REDIRECT_URI, searchParams.code)
|
||||||
|
.then(resp => {
|
||||||
const token = resp.result.access_token;
|
const token = resp.result.access_token;
|
||||||
window.opener.Cloud.providers.dropbox.setDropBoxToken(token)
|
window.opener.Cloud.providers.dropbox.setDropBoxToken(token);
|
||||||
}).catch((error) => {
|
})
|
||||||
console.error(error)
|
.catch(error => {
|
||||||
|
console.error(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
175
fonts.css
175
fonts.css
|
|
@ -1,175 +0,0 @@
|
||||||
@font-face {
|
|
||||||
font-family: 'Amatic SC';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: local('Amatic SC Bold'), local('AmaticSC-Bold'), url(https://fonts.gstatic.com/s/amaticsc/v11/TUZ3zwprpvBS1izr_vOMscGKfrUC.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Architects Daughter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Architects Daughter Regular'), local('ArchitectsDaughter-Regular'), url(https://fonts.gstatic.com/s/architectsdaughter/v8/RXTgOOQ9AAtaVOHxx0IUBM3t7GjCYufj5TXV5VnA2p8.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Bitter';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Bitter Regular'), local('Bitter-Regular'), url(https://fonts.gstatic.com/s/bitter/v12/zfs6I-5mjWQ3nxqccMoL2A.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Caesar Dressing';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Caesar Dressing'), local('CaesarDressing-Regular'), url(https://fonts.gstatic.com/s/caesardressing/v6/yYLx0hLa3vawqtwdswbotmK4vrRHdrz7.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Cinzel';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Cinzel Regular'), local('Cinzel-Regular'), url(https://fonts.gstatic.com/s/cinzel/v7/zOdksD_UUTk1LJF9z4tURA.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Comfortaa';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: local('Comfortaa Bold'), local('Comfortaa-Bold'), url(https://fonts.gstatic.com/s/comfortaa/v12/fND5XPYKrF2tQDwwfWZJI-gdm0LZdjqr5-oayXSOefg.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Dancing Script';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
src: local('Dancing Script Bold'), local('DancingScript-Bold'), url(https://fonts.gstatic.com/s/dancingscript/v9/KGBfwabt0ZRLA5W1ywjowUHdOuSHeh0r6jGTOGdAKHA.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Fredericka the Great';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Fredericka the Great'), local('FrederickatheGreat'), url(https://fonts.gstatic.com/s/frederickathegreat/v6/9Bt33CxNwt7aOctW2xjbCstzwVKsIBVV--Sjxbc.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Gloria Hallelujah';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Gloria Hallelujah'), local('GloriaHallelujah'), url(https://fonts.gstatic.com/s/gloriahallelujah/v9/CA1k7SlXcY5kvI81M_R28cNDay8z-hHR7F16xrcXsJw.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Great Vibes';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Great Vibes'), local('GreatVibes-Regular'), url(https://fonts.gstatic.com/s/greatvibes/v5/6q1c0ofG6NKsEhAc2eh-3Y4P5ICox8Kq3LLUNMylGO4.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'IM Fell English';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('IM FELL English Roman'), local('IM_FELL_English_Roman'), url(https://fonts.gstatic.com/s/imfellenglish/v7/xwIisCqGFi8pff-oa9uSVAkYLEKE0CJQa8tfZYc_plY.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Kaushan Script';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Kaushan Script'), local('KaushanScript-Regular'), url(https://fonts.gstatic.com/s/kaushanscript/v6/qx1LSqts-NtiKcLw4N03IEd0sm1ffa_JvZxsF_BEwQk.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'MedievalSharp';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('MedievalSharp'), url(https://fonts.gstatic.com/s/medievalsharp/v9/EvOJzAlL3oU5AQl2mP5KdgptMqhwMg.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Metamorphous';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Metamorphous'), url(https://fonts.gstatic.com/s/metamorphous/v7/Wnz8HA03aAXcC39ZEX5y133EOyqs.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montez';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Montez Regular'), local('Montez-Regular'), url(https://fonts.gstatic.com/s/montez/v8/aq8el3-0osHIcFK6bXAPkw.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Nova Script';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Nova Script Regular'), local('NovaScript-Regular'), url(https://fonts.gstatic.com/s/novascript/v10/7Au7p_IpkSWSTWaFWkumvlQKGFw.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Orbitron';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Orbitron Regular'), local('Orbitron-Regular'), url(https://fonts.gstatic.com/s/orbitron/v9/HmnHiRzvcnQr8CjBje6GQvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Satisfy';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Satisfy Regular'), local('Satisfy-Regular'), url(https://fonts.gstatic.com/s/satisfy/v8/2OzALGYfHwQjkPYWELy-cw.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Shadows Into Light';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Shadows Into Light'), local('ShadowsIntoLight'), url(https://fonts.gstatic.com/s/shadowsintolight/v7/clhLqOv7MXn459PTh0gXYFK2TSYBz0eNcHnp4YqE4Ts.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Uncial Antiqua';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Uncial Antiqua'), local('UncialAntiqua-Regular'), url(https://fonts.gstatic.com/s/uncialantiqua/v5/N0bM2S5WOex4OUbESzoESK-i-MfWQZQ.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Underdog';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Underdog'), local('Underdog-Regular'), url(https://fonts.gstatic.com/s/underdog/v6/CHygV-jCElj7diMroWSlWV8.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Yellowtail';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
src: local('Yellowtail Regular'), local('Yellowtail-Regular'), url(https://fonts.gstatic.com/s/yellowtail/v8/GcIHC9QEwVkrA19LJU1qlPk_vArhqVIZ0nv9q090hN8.woff2) format('woff2');
|
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
|
||||||
}
|
|
||||||
147
index.css
147
index.css
File diff suppressed because one or more lines are too long
78
index.html
78
index.html
|
|
@ -242,7 +242,7 @@
|
||||||
|
|
||||||
<div id="collapsible">
|
<div id="collapsible">
|
||||||
<button id="optionsTrigger" data-t="tipOptionsTrigger" data-tip="Click to show options pane. Shortcut: Tab" class="options glow" onclick="showOptions(event)" style="padding:.6em .45em">►</button>
|
<button id="optionsTrigger" data-t="tipOptionsTrigger" data-tip="Click to show options pane. Shortcut: Tab" class="options glow" onclick="showOptions(event)" style="padding:.6em .45em">►</button>
|
||||||
<button id="regenerate" data-t="tipRegenerate" data-tip="Click to generate a new map. Shortcut: F2" onclick="regeneratePrompt()" class="options" style="display:none; padding:.6em 1em"><t data-t="newMap">New Map!</t></button>
|
<button id="regenerate" data-t="tipRegenerate" data-tip="Click to generate a new map. Shortcut: F2" onclick="regeneratePrompt()" class="options" style="display: none"><t data-t="newMap">New Map!</t></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="options" style="display:none">
|
<div id="options" style="display:none">
|
||||||
|
|
@ -273,8 +273,8 @@
|
||||||
<option value="landmass">Pure landmass</option>
|
<option value="landmass">Pure landmass</option>
|
||||||
<option hidden value="custom">Custom (not saved)</option>
|
<option hidden value="custom">Custom (not saved)</option>
|
||||||
</select>
|
</select>
|
||||||
<button id="savePresetButton" data-tip="Click to save displayed layers as a new preset" class="icon-plus presetButton" style="display:none" onclick="savePreset()"></button>
|
<button id="savePresetButton" data-tip="Click to save displayed layers as a new preset" class="icon-plus sideButton" style="display:none" onclick="savePreset()"></button>
|
||||||
<button id="removePresetButton" data-tip="Click to remove current custom preset" class="icon-minus presetButton" style="display:none" onclick="removePreset()"></button>
|
<button id="removePresetButton" data-tip="Click to remove current custom preset" class="icon-minus sideButton" style="display:none" onclick="removePreset()"></button>
|
||||||
|
|
||||||
<p data-tip="Click to toggle a layer, drag to raise or lower a layer. Ctrl + click to edit layer style">Displayed layers and layers order:</p>
|
<p data-tip="Click to toggle a layer, drag to raise or lower a layer. Ctrl + click to edit layer style">Displayed layers and layers order:</p>
|
||||||
<ul data-tip="Click to toggle a layer, drag to raise or lower a layer. Ctrl + click to edit layer style" id="mapLayers">
|
<ul data-tip="Click to toggle a layer, drag to raise or lower a layer. Ctrl + click to edit layer style" id="mapLayers">
|
||||||
|
|
@ -326,8 +326,8 @@
|
||||||
<option value="styleWatercolor" data-system=1>Watercolor</option>
|
<option value="styleWatercolor" data-system=1>Watercolor</option>
|
||||||
<option value="styleMonochrome" data-system=1>Monochrome</option>
|
<option value="styleMonochrome" data-system=1>Monochrome</option>
|
||||||
</select>
|
</select>
|
||||||
<button id="addStyleButton" data-tip="Click to save current style as a new preset" class="icon-plus styleButton" style="display: inline-block" onclick="addStylePreset()"></button>
|
<button id="addStyleButton" data-tip="Click to save current style as a new preset" class="icon-plus sideButton" style="display: inline-block" onclick="addStylePreset()"></button>
|
||||||
<button id="removeStyleButton" data-tip="Click to remove current custom style preset" class="icon-minus styleButton" style="display: none" onclick="removeStylePreset()"></button>
|
<button id="removeStyleButton" data-tip="Click to remove current custom style preset" class="icon-minus sideButton" style="display: none" onclick="removeStylePreset()"></button>
|
||||||
|
|
||||||
<p data-tip="Select an element to edit its style" style="display: inline-block;">Select element:</p>
|
<p data-tip="Select an element to edit its style" style="display: inline-block;">Select element:</p>
|
||||||
<select data-tip="Select an element to edit its style (list is ordered alphabetically)" id="styleElementSelect" style="width:42%">
|
<select data-tip="Select an element to edit its style (list is ordered alphabetically)" id="styleElementSelect" style="width:42%">
|
||||||
|
|
@ -458,7 +458,7 @@
|
||||||
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/iran-small.jpg">Iran small</option>
|
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/iran-small.jpg">Iran small</option>
|
||||||
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/spain-small.jpg">Spain small</option>
|
<option value="https://i2.wp.com/azgaar.files.wordpress.com/2019/07/spain-small.jpg">Spain small</option>
|
||||||
</select>
|
</select>
|
||||||
<button data-tip="Click and provide a URL to image to be set as a texture" class="icon-plus styleButton" onclick="textureProvideURL()"></button>
|
<button data-tip="Click and provide a URL to image to be set as a texture" class="icon-plus sideButton" onclick="textureProvideURL()"></button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|
@ -666,8 +666,7 @@
|
||||||
<td>Font</td>
|
<td>Font</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="styleSelectFont"></select>
|
<select id="styleSelectFont"></select>
|
||||||
<input id="styleInputFont" data-tip="Provide a link to @font-face declaration or type Google font name" type="text" placeholder="link to @font-face">
|
<button id="styleFontAdd" data-tip="Add a font" class="icon-plus sideButton"></button>
|
||||||
<button id="styleFontAdd" data-tip="Add custom font from the web" class="icon-plus styleButton"></button>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
@ -1311,14 +1310,15 @@
|
||||||
</tr> -->
|
</tr> -->
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<div>
|
||||||
<button id="configureWorld" data-tip="Click to open world configurator to setup map position on Globe and World climate" onclick="editWorld()">Configure World</button>
|
<button id="configureWorld" data-tip="Click to open world configurator to setup map position on Globe and World climate" onclick="editWorld()">Configure World</button>
|
||||||
<button id="optionsReset" data-tip="Click to restore default options (page will be reloaded)" onclick="restoreDefaultOptions()">Reset to defaults</button>
|
<button id="optionsReset" data-tip="Click to restore default options (page will be reloaded)" onclick="restoreDefaultOptions()">Reset to defaults</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="toolsContent" class="tabcontent">
|
<div id="toolsContent" class="tabcontent">
|
||||||
<div>
|
|
||||||
<p>Click to configure:</p>
|
<p>Click to configure:</p>
|
||||||
|
<div>
|
||||||
<button id="editHeightmapButton" data-tip="Click to open Heightmap customization menu. Shortcut: Shift + H">Heightmap</button>
|
<button id="editHeightmapButton" data-tip="Click to open Heightmap customization menu. Shortcut: Shift + H">Heightmap</button>
|
||||||
<button id="editBiomesButton" data-tip="Click to open Biomes Editor. Shortcut: Shift + B">Biomes</button>
|
<button id="editBiomesButton" data-tip="Click to open Biomes Editor. Shortcut: Shift + B">Biomes</button>
|
||||||
<button id="editStatesButton" data-tip="Click to open States Editor. Shortcut: Shift + S">States</button>
|
<button id="editStatesButton" data-tip="Click to open States Editor. Shortcut: Shift + S">States</button>
|
||||||
|
|
@ -1333,18 +1333,18 @@
|
||||||
<button id="editNotesButton" data-tip="Click to open Notes Editor. Shortcut: Shift + O">Notes</button>
|
<button id="editNotesButton" data-tip="Click to open Notes Editor. Shortcut: Shift + O">Notes</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<p>Click to overview:</p>
|
<p>Click to overview:</p>
|
||||||
|
<div>
|
||||||
<button id="overviewBurgsButton" data-tip="Click to open Burgs Overview. Shortcut: Shift + T">Burgs</button>
|
<button id="overviewBurgsButton" data-tip="Click to open Burgs Overview. Shortcut: Shift + T">Burgs</button>
|
||||||
<button id="overviewRiversButton" data-tip="Click to open Rivers Overview. Shortcut: Shift + V">Rivers</button>
|
<button id="overviewRiversButton" data-tip="Click to open Rivers Overview. Shortcut: Shift + V">Rivers</button>
|
||||||
<button id="overviewMilitaryButton" data-tip="Click to open Military Forces Overview. Shortcut: Shift + M">Military</button>
|
<button id="overviewMilitaryButton" data-tip="Click to open Military Forces Overview. Shortcut: Shift + M">Military</button>
|
||||||
<button id="overviewCellsButton" data-tip="Click to open Cell details view. Shortcut: Shift + E">Cells</button>
|
<button id="overviewCellsButton" data-tip="Click to open Cell details view. Shortcut: Shift + E">Cells</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="regenerateFeature">
|
|
||||||
<p>Click to regenerate:</p>
|
<p>Click to regenerate:</p>
|
||||||
<button id="regenerateStateLabels" data-tip="Click to update state labels placement based on current borders">State labels</button>
|
<div id="regenerateFeature">
|
||||||
<button id="regenerateReliefIcons" data-tip="Click to regenerate all relief icons based on current cell biome and elevation">Relief icons</button>
|
<button id="regenerateStateLabels" data-tip="Click to update state labels placement based on current borders">Labels</button>
|
||||||
|
<button id="regenerateReliefIcons" data-tip="Click to regenerate all relief icons based on current cell biome and elevation">Relief</button>
|
||||||
<button id="regenerateRoutes" data-tip="Click to regenerate all routes">Routes</button>
|
<button id="regenerateRoutes" data-tip="Click to regenerate all routes">Routes</button>
|
||||||
<button id="regenerateRivers" data-tip="Click to regenerate all rivers (restore default state)">Rivers</button>
|
<button id="regenerateRivers" data-tip="Click to regenerate all rivers (restore default state)">Rivers</button>
|
||||||
<button id="regeneratePopulation" data-tip="Click to recalculate rural and urban population">Population</button>
|
<button id="regeneratePopulation" data-tip="Click to recalculate rural and urban population">Population</button>
|
||||||
|
|
@ -1360,8 +1360,8 @@
|
||||||
<button id="regenerateZones" data-tip="Click to regenerate zones. Hold Ctrl and click to set zones number multiplier">Zones</button>
|
<button id="regenerateZones" data-tip="Click to regenerate zones. Hold Ctrl and click to set zones number multiplier">Zones</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="addFeature">
|
|
||||||
<p>Click to add:</p>
|
<p>Click to add:</p>
|
||||||
|
<div id="addFeature">
|
||||||
<button id="addBurgTool" data-tip="Click on map to place a burg. Hold <kbd>Shift</kbd> to add multiple. Shortcut: Shift + 1">Burg</button>
|
<button id="addBurgTool" data-tip="Click on map to place a burg. Hold <kbd>Shift</kbd> to add multiple. Shortcut: Shift + 1">Burg</button>
|
||||||
<button id="addLabel" data-tip="Click on map to place label. Hold Shift to add multiple. Shortcut: Shift + 2">Label</button>
|
<button id="addLabel" data-tip="Click on map to place label. Hold Shift to add multiple. Shortcut: Shift + 2">Label</button>
|
||||||
<button id="addRiver" data-tip="Click on map to place a river. Hold Shift to add multiple. Shortcut: Shift + 3">River</button>
|
<button id="addRiver" data-tip="Click on map to place a river. Hold Shift to add multiple. Shortcut: Shift + 3">River</button>
|
||||||
|
|
@ -1385,8 +1385,8 @@
|
||||||
<button data-tip="Preview heightmap in 3D scene" id="heightmap3DView">3D scene</button>
|
<button data-tip="Preview heightmap in 3D scene" id="heightmap3DView">3D scene</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="customizeOptions">
|
|
||||||
<p>Options:</p>
|
<p>Options:</p>
|
||||||
|
<div id="customizeOptions">
|
||||||
<div data-tip="Heightmap edit mode">Edit mode: <span id="heightmapEditMode"></span></div>
|
<div data-tip="Heightmap edit mode">Edit mode: <span id="heightmapEditMode"></span></div>
|
||||||
<div data-tip="Render cells below the sea level (with height less than 20)">
|
<div data-tip="Render cells below the sea level (with height less than 20)">
|
||||||
<input id="renderOcean" class="checkbox" type="checkbox">
|
<input id="renderOcean" class="checkbox" type="checkbox">
|
||||||
|
|
@ -1409,14 +1409,14 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<p>Statistics:</p>
|
<p>Statistics:</p>
|
||||||
|
<div>
|
||||||
<span>Land cells: </span><span id="landmassCounter">0</span>
|
<span>Land cells: </span><span id="landmassCounter">0</span>
|
||||||
<span style="margin-left:.9em">Mean height: </span><span id="landmassAverage">0</span>
|
<span style="margin-left:.9em">Mean height: </span><span id="landmassAverage">0</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<p>Cell info:</p>
|
<p>Cell info:</p>
|
||||||
|
<div>
|
||||||
<span>Coord: </span><span id="heightmapInfoX"></span>/<span id="heightmapInfoY"></span><br>
|
<span>Coord: </span><span id="heightmapInfoX"></span>/<span id="heightmapInfoY"></span><br>
|
||||||
<span>Cell: </span><span id="heightmapInfoCell"></span><br>
|
<span>Cell: </span><span id="heightmapInfoCell"></span><br>
|
||||||
<span>Height: </span><span id="heightmapInfoHeight"></span>
|
<span>Height: </span><span id="heightmapInfoHeight"></span>
|
||||||
|
|
@ -3351,6 +3351,22 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="addFontDialog" style="display: none" class="dialog">
|
||||||
|
<span>There are 3 ways to add a custom font:</span>
|
||||||
|
<p><strong>Google font</strong>. Open <a href="https://fonts.google.com/" target="_blank">Google Fonts</a>, find a font you like and enter its name to the field below.</p>
|
||||||
|
<p><strong>Local font</strong>. If you have a font <a href="https://faqs.skillcrush.com/article/275-downloading-installing-a-font-on-your-computer" target="_blank">installed on your computer</a>, just provide the font name. Make sure the browser is reloaded after the installation. The font won't work on machines not having it installed. Good source of fonts are <a href="https://fontesk.com" target="_blank">Fontdesk</a> and <a href="https://www.dafont.com" target="_blank">DaFont</a>.</p>
|
||||||
|
<p><strong>Font URL</strong>. Provide font name and link to the font file hosted online. The best free font hostings are <a href="https://fonts.google.com/" target="_blank">Google Fonts</a> and <a target="_blank" href="https://www.cdnfonts.com">CDN Fonts</a>. To get font file open the link to css provided by these services and manually copy the link to <code>woff2</code>.</p>
|
||||||
|
<div style="margin-top: .3em" data-tip="Select font adding method">
|
||||||
|
<select id="addFontMethod">
|
||||||
|
<option value="googleFont" selected>Google font</option>
|
||||||
|
<option value="localFont">Local font</option>
|
||||||
|
<option value="fontURL" selected>Font URL</option>
|
||||||
|
</select>
|
||||||
|
<input id="addFontNameInput" placeholder="font family" style="width:15em">
|
||||||
|
<input id="addFontURLInput" placeholder="font file URL" style="width:22.6em; margin-top:.1em">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="cellInfo" style="display: none" class="dialog stable">
|
<div id="cellInfo" style="display: none" class="dialog stable">
|
||||||
<p><b>Cell:</b> <span id="infoCell"></span> <b>X:</b> <span id="infoX"></span> <b>Y:</b> <span id="infoY"></span></p>
|
<p><b>Cell:</b> <span id="infoCell"></span> <b>X:</b> <span id="infoX"></span> <b>Y:</b> <span id="infoY"></span></p>
|
||||||
<p><b>Latitude:</b> <span id="infoLat"></span></p>
|
<p><b>Latitude:</b> <span id="infoLat"></span></p>
|
||||||
|
|
@ -3480,11 +3496,9 @@
|
||||||
<button onclick="saveGeoJSON_Rivers()" data-tip="Download rivers data in GeoJSON format">rivers</button>
|
<button onclick="saveGeoJSON_Rivers()" data-tip="Download rivers data in GeoJSON format">rivers</button>
|
||||||
<button onclick="saveGeoJSON_Markers()" data-tip="Download markers data in GeoJSON format">markers</button>
|
<button onclick="saveGeoJSON_Markers()" data-tip="Download markers data in GeoJSON format">markers</button>
|
||||||
</div>
|
</div>
|
||||||
<p style="font-style: italic">GeoJSON format is used in GIS tools such as QGIS. Check out <a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/GIS-data-export" target="_blank">wiki-page</a> for guidance</p>
|
<p>GeoJSON format is used in GIS tools such as QGIS. Check out <a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/GIS-data-export" target="_blank">wiki-page</a> for guidance.</p>
|
||||||
|
<p>Generator uses pop-up window to download files. Please ensure your browser does not block popups.</p>
|
||||||
<p style="font-style: italic">Generator uses pop-up window to download files. Please ensure your browser does not block popups.</p>
|
<p>It's also possible to export map to <i>Foundry VTT</i>, see <a href="https://github.com/Ethck/azgaar-foundry" target="_blank">the module.</a></p>
|
||||||
|
|
||||||
<p style="font-style: italic">It's also possible to export map to Foundry VTT, see <a href="https://github.com/Ethck/azgaar-foundry" target="_blank">the module.</a></p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="saveMapData" style="display: none" class="dialog">
|
<div id="saveMapData" style="display: none" class="dialog">
|
||||||
|
|
@ -3492,24 +3506,26 @@
|
||||||
<strong>Save map to</strong>
|
<strong>Save map to</strong>
|
||||||
<button onclick="dowloadMap()" data-tip="Download .map file to your local disk. Shortcut: Ctrl + S">machine</button>
|
<button onclick="dowloadMap()" data-tip="Download .map file to your local disk. Shortcut: Ctrl + S">machine</button>
|
||||||
<button onclick="saveToDropbox()" data-tip="Save .map file to your Dropbox">dropbox</button>
|
<button onclick="saveToDropbox()" data-tip="Save .map file to your Dropbox">dropbox</button>
|
||||||
<button onclick="quickSave()" data-tip="Save the project to browser storage (quick save). It can be unreliable. Shortcut: F6">browser</button>
|
<button onclick="quickSave()" data-tip="Save the project to browser storage. It can be unreliable. Shortcut: F6">browser</button>
|
||||||
</div>
|
</div>
|
||||||
<p style="font-style: italic">Maps are saved in <i>.map</i> format, that can be loaded back via 'Load' in menu. Please keep noted that we do not keep any data on our side. There is no way to restore the progress if .map file is lost. Please keep old .map files on your machine or cloud storage as backups.</p>
|
<p>Maps are saved in <i>.map</i> format, that can be loaded back via the <i>Load</i> in menu. There is no way to restore the progress if file is lost. Please keep old <i>.map</i> files on your machine or cloud storage as backups.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="loadMapData" style="display: none" class="dialog">
|
<div id="loadMapData" style="display: none" class="dialog">
|
||||||
<div style="margin-bottom: .3em">Load map from</div>
|
|
||||||
<div>
|
<div>
|
||||||
|
<strong>Load map from</strong>
|
||||||
<button onclick="mapToLoad.click()" data-tip="Load .map file from local disk">local disk</button>
|
<button onclick="mapToLoad.click()" data-tip="Load .map file from local disk">local disk</button>
|
||||||
<button onclick="loadURL()" data-tip="Load .map file from URL (server should allow CORS)">URL</button>
|
<button onclick="loadURL()" data-tip="Load .map file from URL (server should allow CORS)">URL</button>
|
||||||
<button onclick="quickLoad()" data-tip="Load map from browser storage (if saved before)">storage</button>
|
<button onclick="quickLoad()" data-tip="Load map from browser storage (if saved before)">storage</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="loadFromDropbox">
|
<div id="loadFromDropbox">
|
||||||
<p>From your Dropbox account:</p>
|
<p style="margin-bottom: .3em">From your Dropbox account</p>
|
||||||
<select style="margin-bottom:.3em">
|
<select id="loadFromDropboxSelect" style="width: 22em"></select>
|
||||||
</select>
|
|
||||||
|
<div id="loadFromDropboxButtons" style="margin-bottom: .3em">
|
||||||
<button onclick="loadFromDropbox()" data-tip="Load .map file from your Dropbox">Open</button>
|
<button onclick="loadFromDropbox()" data-tip="Load .map file from your Dropbox">Open</button>
|
||||||
<button onclick="createSharableDropboxLink()" data-tip="Select .map file on dropbox and share a sharable link">Create link</button>
|
<button onclick="createSharableDropboxLink()" data-tip="Select file and create a link to share with your friends">Create link</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style="margin-top: .3em">
|
<div style="margin-top: .3em">
|
||||||
<div id="sharableLinkContainer" style="display: none">
|
<div id="sharableLinkContainer" style="display: none">
|
||||||
|
|
@ -3521,7 +3537,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="saveTilesScreen" style="display: none" class="dialog">
|
<div id="saveTilesScreen" style="display: none" class="dialog">
|
||||||
<p style="font-style: italic">Map will be split into tiles and downloaded as a single zip file. Avoid saving to big images</p>
|
<p>Map will be split into tiles and downloaded as a single zip file. Avoid saving to big images</p>
|
||||||
<div data-tip="Number of columns" style="margin-bottom: .3em">
|
<div data-tip="Number of columns" style="margin-bottom: .3em">
|
||||||
<div class="label">Columns:</div>
|
<div class="label">Columns:</div>
|
||||||
<input id="tileColsInput" data-stored="tileCols" type="range" min=2 max=20 value=8 style="width: 11em">
|
<input id="tileColsInput" data-stored="tileCols" type="range" min=2 max=20 value=8 style="width: 11em">
|
||||||
|
|
|
||||||
2
libs/dropins.min.js
vendored
Normal file
2
libs/dropins.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
main.js
6
main.js
|
|
@ -2,7 +2,7 @@
|
||||||
// https://github.com/Azgaar/Fantasy-Map-Generator
|
// https://github.com/Azgaar/Fantasy-Map-Generator
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
const version = "1.66"; // generator version1
|
const version = "1.661"; // generator version
|
||||||
document.title += " v" + version;
|
document.title += " v" + version;
|
||||||
|
|
||||||
// Switches to disable/enable logging features
|
// Switches to disable/enable logging features
|
||||||
|
|
@ -122,7 +122,6 @@ let customization = 0; // 0 - no; 1 = heightmap draw; 2 - states draw; 3 - add s
|
||||||
|
|
||||||
let biomesData = applyDefaultBiomesSystem();
|
let biomesData = applyDefaultBiomesSystem();
|
||||||
let nameBases = Names.getNameBases(); // cultures-related data
|
let nameBases = Names.getNameBases(); // cultures-related data
|
||||||
const fonts = ["Almendra+SC", "Georgia", "Arial", "Times+New+Roman", "Comic+Sans+MS", "Lucida+Sans+Unicode", "Courier+New", "Verdana", "Arial", "Impact"]; // default fonts
|
|
||||||
|
|
||||||
let color = d3.scaleSequential(d3.interpolateSpectral); // default color scheme
|
let color = d3.scaleSequential(d3.interpolateSpectral); // default color scheme
|
||||||
const lineGen = d3.line().curve(d3.curveBasis); // d3 line generator with default curve interpolation
|
const lineGen = d3.line().curve(d3.curveBasis); // d3 line generator with default curve interpolation
|
||||||
|
|
@ -221,7 +220,7 @@ void (function checkLoadParameters() {
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function generateMapOnLoad() {
|
function generateMapOnLoad() {
|
||||||
applyStyleOnLoad(); // apply default of previously selected style
|
applyStyleOnLoad(); // apply default or previously selected style
|
||||||
generate(); // generate map
|
generate(); // generate map
|
||||||
focusOn(); // based on searchParams focus on point, cell or burg from MFCG
|
focusOn(); // based on searchParams focus on point, cell or burg from MFCG
|
||||||
applyPreset(); // apply saved layers preset
|
applyPreset(); // apply saved layers preset
|
||||||
|
|
@ -379,6 +378,7 @@ function showWelcomeMessage() {
|
||||||
alertMessage.innerHTML = `The Fantasy Map Generator is updated up to version <b>${version}</b>.
|
alertMessage.innerHTML = `The Fantasy Map Generator is updated up to version <b>${version}</b>.
|
||||||
This version is compatible with ${changelog}, loaded <i>.map</i> files will be auto-updated.
|
This version is compatible with ${changelog}, loaded <i>.map</i> files will be auto-updated.
|
||||||
<ul>Main changes:
|
<ul>Main changes:
|
||||||
|
<li>Add custom fonts dialog</li>
|
||||||
<li>Save and load <i>.map</i> files to Dropbox</li>
|
<li>Save and load <i>.map</i> files to Dropbox</li>
|
||||||
<li>Ability to add control points on river edit</li>
|
<li>Ability to add control points on river edit</li>
|
||||||
<li>New heightmap template: Taklamakan</li>
|
<li>New heightmap template: Taklamakan</li>
|
||||||
|
|
|
||||||
124
modules/cloud.js
124
modules/cloud.js
|
|
@ -16,126 +16,124 @@ restore(): restore access tokens from storage if possible
|
||||||
*/
|
*/
|
||||||
|
|
||||||
window.Cloud = (function () {
|
window.Cloud = (function () {
|
||||||
|
|
||||||
// helpers to use in providers for token handling
|
// helpers to use in providers for token handling
|
||||||
const lSKey = x => `auth-${x}`
|
const lSKey = x => `auth-${x}`;
|
||||||
const setToken = (prov, key) => localStorage.setItem(lSKey(prov), key)
|
const setToken = (prov, key) => localStorage.setItem(lSKey(prov), key);
|
||||||
const getToken = prov => localStorage.getItem(lSKey(prov))
|
const getToken = prov => localStorage.getItem(lSKey(prov));
|
||||||
|
|
||||||
/**********************************************************/
|
/**********************************************************/
|
||||||
/* Dropbox provider */
|
/* Dropbox provider */
|
||||||
/**********************************************************/
|
/**********************************************************/
|
||||||
|
|
||||||
const DBP = {
|
const DBP = {
|
||||||
name: 'dropbox',
|
name: "dropbox",
|
||||||
clientId: 'sp7tzwm27u2w5ns',
|
clientId: "pdr9ae64ip0qno4",
|
||||||
authWindow: undefined,
|
authWindow: undefined,
|
||||||
token: null, // Access token
|
token: null, // Access token
|
||||||
api: null,
|
api: null,
|
||||||
|
|
||||||
restore() {
|
restore() {
|
||||||
this.token = getToken(this.name)
|
this.token = getToken(this.name);
|
||||||
if (this.token) this.connect(this.token)
|
if (this.token) this.connect(this.token);
|
||||||
},
|
},
|
||||||
|
|
||||||
async call(name, param) {
|
async call(name, param) {
|
||||||
try {
|
try {
|
||||||
return await this.api[name](param)
|
return await this.api[name](param);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.name !== "DropboxResponseError") throw(e)
|
if (e.name !== "DropboxResponseError") throw e;
|
||||||
// retry with auth
|
// retry with auth
|
||||||
await this.auth()
|
await this.auth();
|
||||||
return await this.api[name](param)
|
return await this.api[name](param);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
connect(token) {
|
connect(token) {
|
||||||
const clientId = this.clientId
|
const clientId = this.clientId;
|
||||||
const auth = new Dropbox.DropboxAuth({ clientId })
|
const auth = new Dropbox.DropboxAuth({clientId});
|
||||||
auth.setAccessToken(token)
|
auth.setAccessToken(token);
|
||||||
this.api = new Dropbox.Dropbox({ auth })
|
this.api = new Dropbox.Dropbox({auth});
|
||||||
},
|
},
|
||||||
|
|
||||||
async save(fileName, contents) {
|
async save(fileName, contents) {
|
||||||
if (!this.api) await this.auth()
|
if (!this.api) await this.auth();
|
||||||
const resp = this.call('filesUpload', { path: '/' + fileName, contents })
|
const resp = this.call("filesUpload", {path: "/" + fileName, contents});
|
||||||
console.log("Dropbox response:", resp)
|
DEBUG && console.log("Dropbox response:", resp);
|
||||||
return true
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
async load(path) {
|
async load(path) {
|
||||||
if (!this.api) await this.auth()
|
if (!this.api) await this.auth();
|
||||||
const resp = await this.call('filesDownload', { path })
|
const resp = await this.call("filesDownload", {path});
|
||||||
const blob = resp.result.fileBlob
|
const blob = resp.result.fileBlob;
|
||||||
if (!blob) throw(new Error('Invalid response from dropbox.'))
|
if (!blob) throw new Error("Invalid response from dropbox.");
|
||||||
return blob
|
return blob;
|
||||||
},
|
},
|
||||||
|
|
||||||
async list() {
|
async list() {
|
||||||
if (!this.api) return null
|
if (!this.api) return null;
|
||||||
const resp = await this.call('filesListFolder', { path: '' })
|
const resp = await this.call("filesListFolder", {path: ""});
|
||||||
return resp.result.entries.map(e => ({ name: e.name, path: e.path_lower }))
|
return resp.result.entries.map(e => ({name: e.name, path: e.path_lower}));
|
||||||
},
|
},
|
||||||
|
|
||||||
auth() {
|
auth() {
|
||||||
const url = window.location.origin + window.location.pathname + 'dropbox.html'
|
const url = window.location.origin + window.location.pathname + "dropbox.html";
|
||||||
this.authWindow = window.open(url, 'auth', 'width=640,height=480')
|
this.authWindow = window.open(url, "auth", "width=640,height=480");
|
||||||
// child window expected to call
|
// child window expected to call
|
||||||
// window.opener.Cloud.providers.dropbox.setDropBoxToken (see below)
|
// window.opener.Cloud.providers.dropbox.setDropBoxToken (see below)
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const watchDog = () => {
|
const watchDog = () => {
|
||||||
this.authWindow.close()
|
this.authWindow.close();
|
||||||
reject(new Error("Timeout. No auth for dropbox."))
|
reject(new Error("Timeout. No auth for dropbox."));
|
||||||
}
|
};
|
||||||
setTimeout(watchDog, 120*1000)
|
setTimeout(watchDog, 120 * 1000);
|
||||||
window.addEventListener('dropboxauth', e => {
|
window.addEventListener("dropboxauth", e => {
|
||||||
clearTimeout(watchDog)
|
clearTimeout(watchDog);
|
||||||
resolve()
|
resolve();
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// Callback function for auth window.
|
// Callback function for auth window.
|
||||||
setDropBoxToken(token) {
|
setDropBoxToken(token) {
|
||||||
console.log('Access token got:', token)
|
DEBUG && console.log("Access token:", token);
|
||||||
setToken(this.name, token)
|
setToken(this.name, token);
|
||||||
this.connect(token)
|
this.connect(token);
|
||||||
this.authWindow.close()
|
this.authWindow.close();
|
||||||
window.dispatchEvent(new Event('dropboxauth'))
|
window.dispatchEvent(new Event("dropboxauth"));
|
||||||
},
|
},
|
||||||
|
|
||||||
async getLink(path) {
|
async getLink(path) {
|
||||||
if (!this.api) await this.auth()
|
if (!this.api) await this.auth();
|
||||||
let resp
|
let resp;
|
||||||
|
|
||||||
// already exists?
|
// already exists?
|
||||||
resp = await this.call('sharingListSharedLinks', { path })
|
resp = await this.call("sharingListSharedLinks", {path});
|
||||||
if (resp.result.links.length)
|
if (resp.result.links.length) return resp.result.links[0].url;
|
||||||
return resp.result.links[0].url
|
|
||||||
|
|
||||||
// create new
|
// create new
|
||||||
resp = await this.call('sharingCreateSharedLinkWithSettings', {
|
resp = await this.call("sharingCreateSharedLinkWithSettings", {
|
||||||
path,
|
path,
|
||||||
settings: {
|
settings: {
|
||||||
require_password: false,
|
require_password: false,
|
||||||
audience: 'public',
|
audience: "public",
|
||||||
access: 'viewer',
|
access: "viewer",
|
||||||
requested_visibility: 'public',
|
requested_visibility: "public",
|
||||||
allow_download: true,
|
allow_download: true
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
console.log("dropbox link object:", resp.result)
|
DEBUG && console.log("Dropbox link object:", resp.result);
|
||||||
return resp.result.url
|
return resp.result.url;
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// register providers here:
|
// register providers here:
|
||||||
const providers = {
|
const providers = {
|
||||||
dropbox: DBP,
|
dropbox: DBP
|
||||||
}
|
};
|
||||||
|
|
||||||
// restore all providers at startup
|
// restore all providers at startup
|
||||||
for (const p of Object.values(providers)) p.restore()
|
for (const p of Object.values(providers)) p.restore();
|
||||||
|
|
||||||
return { providers }
|
return {providers};
|
||||||
})()
|
})();
|
||||||
|
|
|
||||||
370
modules/fonts.js
370
modules/fonts.js
|
|
@ -1,141 +1,271 @@
|
||||||
// helper finctions to work with fonts
|
"use strict";
|
||||||
|
|
||||||
async function addFonts(url) {
|
const fonts = [
|
||||||
$("head").append('<link rel="stylesheet" type="text/css" href="' + url + '">');
|
{family: "Arial"},
|
||||||
|
{family: "Times New Roman"},
|
||||||
|
{family: "Georgia"},
|
||||||
|
{family: "Garamond"},
|
||||||
|
{family: "Lucida Sans Unicode"},
|
||||||
|
{family: "Courier New"},
|
||||||
|
{family: "Verdana"},
|
||||||
|
{family: "Impact"},
|
||||||
|
{family: "Comic Sans MS"},
|
||||||
|
{family: "Papyrus"},
|
||||||
|
{
|
||||||
|
family: "Almendra SC",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/almendrasc/v13/Iure6Yx284eebowr7hbyTaZOrLQ.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Amatic SC",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/amaticsc/v11/TUZ3zwprpvBS1izr_vOMscGKfrUC.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Architects Daughter",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/architectsdaughter/v8/RXTgOOQ9AAtaVOHxx0IUBM3t7GjCYufj5TXV5VnA2p8.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Bitter",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/bitter/v12/zfs6I-5mjWQ3nxqccMoL2A.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Caesar Dressing",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/caesardressing/v6/yYLx0hLa3vawqtwdswbotmK4vrRHdrz7.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Cinzel",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/cinzel/v7/zOdksD_UUTk1LJF9z4tURA.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Dancing Script",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/dancingscript/v9/KGBfwabt0ZRLA5W1ywjowUHdOuSHeh0r6jGTOGdAKHA.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Fredericka the Great",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/frederickathegreat/v6/9Bt33CxNwt7aOctW2xjbCstzwVKsIBVV--Sjxbc.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Gloria Hallelujah",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/gloriahallelujah/v9/CA1k7SlXcY5kvI81M_R28cNDay8z-hHR7F16xrcXsJw.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Great Vibes",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/greatvibes/v5/6q1c0ofG6NKsEhAc2eh-3Y4P5ICox8Kq3LLUNMylGO4.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "IM Fell English",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/imfellenglish/v7/xwIisCqGFi8pff-oa9uSVAkYLEKE0CJQa8tfZYc_plY.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Kaushan Script",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/kaushanscript/v6/qx1LSqts-NtiKcLw4N03IEd0sm1ffa_JvZxsF_BEwQk.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "MedievalSharp",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/medievalsharp/v9/EvOJzAlL3oU5AQl2mP5KdgptMqhwMg.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Metamorphous",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/metamorphous/v7/Wnz8HA03aAXcC39ZEX5y133EOyqs.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Montez",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/montez/v8/aq8el3-0osHIcFK6bXAPkw.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Nova Script",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/novascript/v10/7Au7p_IpkSWSTWaFWkumvlQKGFw.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Orbitron",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/orbitron/v9/HmnHiRzvcnQr8CjBje6GQvesZW2xOQ-xsNqO47m55DA.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Satisfy",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/satisfy/v8/2OzALGYfHwQjkPYWELy-cw.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Shadows Into Light",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/shadowsintolight/v7/clhLqOv7MXn459PTh0gXYFK2TSYBz0eNcHnp4YqE4Ts.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Uncial Antiqua",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/uncialantiqua/v5/N0bM2S5WOex4OUbESzoESK-i-MfWQZQ.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Underdog",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/underdog/v6/CHygV-jCElj7diMroWSlWV8.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
family: "Yellowtail",
|
||||||
|
src: "url(https://fonts.gstatic.com/s/yellowtail/v8/GcIHC9QEwVkrA19LJU1qlPk_vArhqVIZ0nv9q090hN8.woff2)",
|
||||||
|
unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
declareDefaultFonts(); // execute once on load
|
||||||
|
|
||||||
|
function declareFont(font) {
|
||||||
|
const {family, src, ...rest} = font;
|
||||||
|
if (!src) return;
|
||||||
|
|
||||||
|
const fontFace = new FontFace(family, src, {...rest, display: "block"});
|
||||||
|
document.fonts.add(fontFace);
|
||||||
|
addFontOption(family);
|
||||||
|
}
|
||||||
|
|
||||||
|
function declareDefaultFonts() {
|
||||||
|
fonts.forEach(font => {
|
||||||
|
if (font.src) declareFont(font);
|
||||||
|
else addFontOption(font.family);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUsedFonts(svg) {
|
||||||
|
const usedFontFamilies = new Set();
|
||||||
|
|
||||||
|
const labelGroups = svg.querySelectorAll("#labels g");
|
||||||
|
for (const labelGroup of labelGroups) {
|
||||||
|
const font = labelGroup.getAttribute("font-family");
|
||||||
|
if (font) usedFontFamilies.add(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
const provinceFont = provs.attr("font-family");
|
||||||
|
if (provinceFont) usedFontFamilies.add(provinceFont);
|
||||||
|
|
||||||
|
const legend = svg.querySelector("#legend");
|
||||||
|
const legendFont = legend?.getAttribute("font-family");
|
||||||
|
if (legendFont) usedFontFamilies.add(legendFont);
|
||||||
|
|
||||||
|
const usedFonts = fonts.filter(font => usedFontFamilies.has(font.family));
|
||||||
|
return usedFonts;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addFontOption(family) {
|
||||||
|
const options = document.getElementById("styleSelectFont");
|
||||||
|
// const existingOption = options.querySelector(`[value="${family}"]`);
|
||||||
|
// if (existingOption) return;
|
||||||
|
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = family;
|
||||||
|
option.innerText = family;
|
||||||
|
option.style.fontFamily = family;
|
||||||
|
options.add(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchGoogleFont(family) {
|
||||||
|
const url = `https://fonts.googleapis.com/css2?family=${family.replace(/ /g, "+")}`;
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(url);
|
const resp = await fetch(url);
|
||||||
const text = await resp.text();
|
const text = await resp.text();
|
||||||
let s = document.createElement("style");
|
|
||||||
s.innerHTML = text;
|
const fontFaceRules = text.match(/font-face\s*{[^}]+}/g);
|
||||||
document.head.appendChild(s);
|
const fonts = fontFaceRules.map(fontFace => {
|
||||||
let styleSheet = Array.prototype.filter.call(document.styleSheets, sS => sS.ownerNode === s)[0];
|
const srcURL = fontFace.match(/url\(['"]?(.+?)['"]?\)/)[1];
|
||||||
let FontRule = rule_1 => {
|
const src = `url(${srcURL})`;
|
||||||
let family = rule_1.style.getPropertyValue("font-family");
|
const unicodeRange = fontFace.match(/unicode-range: (.*?);/)?.[1];
|
||||||
let font = family.replace(/['"]+/g, "").replace(/ /g, "+");
|
const variant = fontFace.match(/font-style: (.*?);/)?.[1];
|
||||||
let weight = rule_1.style.getPropertyValue("font-weight");
|
|
||||||
if (weight && weight !== "400") font += ":" + weight;
|
const font = {family, src};
|
||||||
if (fonts.indexOf(font) == -1) {
|
if (unicodeRange) font.unicodeRange = unicodeRange;
|
||||||
fonts.push(font);
|
if (variant && variant !== "normal") font.variant = variant;
|
||||||
fetched++;
|
return font;
|
||||||
}
|
});
|
||||||
};
|
|
||||||
let fetched = 0;
|
return fonts;
|
||||||
for (let r of styleSheet.cssRules) {
|
|
||||||
FontRule(r);
|
|
||||||
}
|
|
||||||
document.head.removeChild(s);
|
|
||||||
return fetched;
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return ERROR && console.error(err);
|
ERROR && console.error(err);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadUsedFonts() {
|
function readBlobAsDataURL(blob) {
|
||||||
const fontsInUse = getFontsList(svg);
|
return new Promise(function (resolve, reject) {
|
||||||
const fontsToLoad = fontsInUse.filter(font => !fonts.includes(font));
|
const reader = new FileReader();
|
||||||
if (fontsToLoad?.length) {
|
reader.onloadend = () => resolve(reader.result);
|
||||||
const url = "https://fonts.googleapis.com/css?family=" + fontsToLoad.join("|");
|
reader.onerror = reject;
|
||||||
addFonts(url);
|
reader.readAsDataURL(blob);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFontsList(svg) {
|
|
||||||
const fontsInUse = [];
|
|
||||||
|
|
||||||
svg.selectAll("#labels > g").each(function () {
|
|
||||||
if (!this.hasChildNodes()) return;
|
|
||||||
const font = this.dataset.font;
|
|
||||||
if (font) fontsInUse.push(font);
|
|
||||||
});
|
});
|
||||||
if (legend?.node()?.hasChildNodes()) fontsInUse.push(legend.attr("data-font"));
|
|
||||||
|
|
||||||
return [...new Set(fontsInUse)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// code from Kaiido's answer https://stackoverflow.com/questions/42402584/how-to-use-google-fonts-in-canvas-when-drawing-dom-objects-in-svg
|
async function loadFontsAsDataURI(fonts) {
|
||||||
function GFontToDataURI(url) {
|
const promises = fonts.map(async font => {
|
||||||
if (!url) return Promise.resolve();
|
const url = font.src.match(/url\(['"]?(.+?)['"]?\)/)[1];
|
||||||
return fetch(url) // first fecth the embed stylesheet page
|
const resp = await fetch(url);
|
||||||
.then(resp => resp.text()) // we only need the text of it
|
const blob = await resp.blob();
|
||||||
.then(text => {
|
const dataURL = await readBlobAsDataURL(blob);
|
||||||
let s = document.createElement("style");
|
|
||||||
s.innerHTML = text;
|
|
||||||
document.head.appendChild(s);
|
|
||||||
const styleSheet = Array.prototype.filter.call(document.styleSheets, sS => sS.ownerNode === s)[0];
|
|
||||||
|
|
||||||
const FontRule = rule => {
|
return {...font, src: `url('${dataURL}')`};
|
||||||
const src = rule.style.getPropertyValue("src");
|
|
||||||
const url = src ? src.split("url(")[1].split(")")[0] : "";
|
|
||||||
return {rule, src, url: url.substring(url.length - 1, 1)};
|
|
||||||
};
|
|
||||||
const fontProms = [];
|
|
||||||
|
|
||||||
for (const r of styleSheet.cssRules) {
|
|
||||||
let fR = FontRule(r);
|
|
||||||
if (!fR.url) continue;
|
|
||||||
|
|
||||||
fontProms.push(
|
|
||||||
fetch(fR.url) // fetch the actual font-file (.woff)
|
|
||||||
.then(resp => resp.blob())
|
|
||||||
.then(blob => {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
let f = new FileReader();
|
|
||||||
f.onload = e => resolve(f.result);
|
|
||||||
f.readAsDataURL(blob);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return await Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addGoogleFont(family) {
|
||||||
|
const fontRanges = await fetchGoogleFont(family);
|
||||||
|
if (!fontRanges) return tip("Cannot fetch Google font for this value", true, "error", 4000);
|
||||||
|
tip(`Google font ${family} is loading...`, true, "warn", 4000);
|
||||||
|
|
||||||
|
const promises = fontRanges.map(range => {
|
||||||
|
const {src, unicodeRange, variant} = range;
|
||||||
|
const fontFace = new FontFace(family, src, {unicodeRange, variant, display: "block"});
|
||||||
|
return fontFace.load();
|
||||||
|
});
|
||||||
|
|
||||||
|
Promise.all(promises)
|
||||||
|
.then(fontFaces => {
|
||||||
|
fontFaces.forEach(fontFace => document.fonts.add(fontFace));
|
||||||
|
fonts.push(...fontRanges);
|
||||||
|
tip(`Google font ${family} is added to the list`, true, "success", 4000);
|
||||||
|
addFontOption(family);
|
||||||
|
document.getElementById("styleSelectFont").value = family;
|
||||||
|
changeFont();
|
||||||
})
|
})
|
||||||
.then(dataURL => fR.rule.cssText.replace(fR.url, dataURL))
|
.catch(err => {
|
||||||
);
|
tip(`Failed to load Google font ${family}`, true, "error", 4000);
|
||||||
}
|
console.error(err);
|
||||||
document.head.removeChild(s); // clean up
|
|
||||||
return Promise.all(fontProms); // wait for all this has been done
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch default fonts if not done before
|
function addLocalFont(family) {
|
||||||
function loadDefaultFonts() {
|
fonts.push({family});
|
||||||
if (!$('link[href="fonts.css"]').length) {
|
|
||||||
$("head").append('<link rel="stylesheet" type="text/css" href="fonts.css">');
|
const fontFace = new FontFace(family, `local(${family})`, {display: "block"});
|
||||||
const fontsToAdd = ["Amatic+SC:700", "IM+Fell+English", "Great+Vibes", "MedievalSharp", "Metamorphous", "Nova+Script", "Uncial+Antiqua", "Underdog", "Caesar+Dressing", "Bitter", "Yellowtail", "Montez", "Shadows+Into+Light", "Fredericka+the+Great", "Orbitron", "Dancing+Script:700", "Architects+Daughter", "Kaushan+Script", "Gloria+Hallelujah", "Satisfy", "Comfortaa:700", "Cinzel"];
|
document.fonts.add(fontFace);
|
||||||
fontsToAdd.forEach(function (f) {
|
tip(`Local font ${family} is added to the fonts list`, true, "success", 4000);
|
||||||
if (fonts.indexOf(f) === -1) fonts.push(f);
|
addFontOption(family);
|
||||||
});
|
document.getElementById("styleSelectFont").value = family;
|
||||||
updateFontOptions();
|
changeFont();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchFonts(url) {
|
function addWebFont(family, url) {
|
||||||
return new Promise((resolve, reject) => {
|
const src = `url('${url}')`;
|
||||||
if (url === "") return tip("Use a direct link to any @font-face declaration or just font name to fetch from Google Fonts");
|
fonts.push({family, src});
|
||||||
|
|
||||||
if (url.indexOf("http") === -1) {
|
const fontFace = new FontFace(family, src, {display: "block"});
|
||||||
url = url.replace(url.charAt(0), url.charAt(0).toUpperCase()).split(" ").join("+");
|
document.fonts.add(fontFace);
|
||||||
url = "https://fonts.googleapis.com/css?family=" + url;
|
tip(`Font ${family} is added to the list`, true, "success", 4000);
|
||||||
}
|
addFontOption(family);
|
||||||
|
document.getElementById("styleSelectFont").value = family;
|
||||||
addFonts(url).then(fetched => {
|
changeFont();
|
||||||
if (fetched === undefined) return tip("Cannot fetch font for this value!", false, "error");
|
|
||||||
if (fetched === 0) return tip("Already in the fonts list!", false, "error");
|
|
||||||
|
|
||||||
updateFontOptions();
|
|
||||||
if (fetched === 1) {
|
|
||||||
tip("Font " + fonts[fonts.length - 1] + " is fetched");
|
|
||||||
} else if (fetched > 1) {
|
|
||||||
tip(fetched + " fonts are added to the list");
|
|
||||||
}
|
|
||||||
resolve(fetched);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update font list for Label and Burg Editors
|
|
||||||
function updateFontOptions() {
|
|
||||||
styleSelectFont.innerHTML = "";
|
|
||||||
for (let i = 0; i < fonts.length; i++) {
|
|
||||||
const opt = document.createElement("option");
|
|
||||||
opt.value = i;
|
|
||||||
const font = fonts[i].split(":")[0].replace(/\+/g, " ");
|
|
||||||
opt.style.fontFamily = opt.innerHTML = font;
|
|
||||||
styleSelectFont.add(opt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,11 @@ function quickLoad() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadFromDropbox(fileName) {
|
async function loadFromDropbox() {
|
||||||
const map = document.querySelector("#loadFromDropbox select").value;
|
const mapPath = document.getElementById("loadFromDropboxSelect")?.value;
|
||||||
console.log('loading dropbox map', map);
|
|
||||||
const blob = await Cloud.providers.dropbox.load(map);
|
DEBUG && console.log("Loading map from Dropbox:", mapPath);
|
||||||
|
const blob = await Cloud.providers.dropbox.load(mapPath);
|
||||||
uploadMap(blob);
|
uploadMap(blob);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,18 +24,18 @@ async function createSharableDropboxLink() {
|
||||||
const mapFile = document.querySelector("#loadFromDropbox select").value;
|
const mapFile = document.querySelector("#loadFromDropbox select").value;
|
||||||
const sharableLink = document.getElementById("sharableLink");
|
const sharableLink = document.getElementById("sharableLink");
|
||||||
const sharableLinkContainer = document.getElementById("sharableLinkContainer");
|
const sharableLinkContainer = document.getElementById("sharableLinkContainer");
|
||||||
let url
|
let url;
|
||||||
try {
|
try {
|
||||||
url = await Cloud.providers.dropbox.getLink(mapFile);
|
url = await Cloud.providers.dropbox.getLink(mapFile);
|
||||||
} catch {
|
} catch {
|
||||||
tip("Dropbox API error. Can not create link.", true, "error", 2000);
|
tip("Dropbox API error. Can not create link.", true, "error", 2000);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fmg = window.location.href.split("?")[0];
|
const fmg = window.location.href.split("?")[0];
|
||||||
const reallink = `${fmg}?maplink=${url}`;
|
const reallink = `${fmg}?maplink=${url}`;
|
||||||
// voodoo magic required by the yellow god of CORS
|
// voodoo magic required by the yellow god of CORS
|
||||||
const link = reallink.replace('www.dropbox.com/s/', 'dl.dropboxusercontent.com/1/view/')
|
const link = reallink.replace("www.dropbox.com/s/", "dl.dropboxusercontent.com/1/view/");
|
||||||
const shortLink = link.slice(0, 50) + "...";
|
const shortLink = link.slice(0, 50) + "...";
|
||||||
|
|
||||||
sharableLinkContainer.style.display = "block";
|
sharableLinkContainer.style.display = "block";
|
||||||
|
|
@ -236,6 +237,15 @@ function parseLoadedData(data) {
|
||||||
if (data[2]) mapCoordinates = JSON.parse(data[2]);
|
if (data[2]) mapCoordinates = JSON.parse(data[2]);
|
||||||
if (data[4]) notes = JSON.parse(data[4]);
|
if (data[4]) notes = JSON.parse(data[4]);
|
||||||
if (data[33]) rulers.fromString(data[33]);
|
if (data[33]) rulers.fromString(data[33]);
|
||||||
|
if (data[34]) {
|
||||||
|
const usedFonts = JSON.parse(data[34]);
|
||||||
|
usedFonts.forEach(usedFont => {
|
||||||
|
const {family: usedFamily, unicodeRange: usedRange, variant: usedVariant} = usedFont;
|
||||||
|
const defaultFont = fonts.find(({family, unicodeRange, variant}) => family === usedFamily && unicodeRange === usedRange && variant === usedVariant);
|
||||||
|
if (!defaultFont) fonts.push(usedFont);
|
||||||
|
declareFont(usedFont);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const biomes = data[3].split("|");
|
const biomes = data[3].split("|");
|
||||||
biomesData = applyDefaultBiomesSystem();
|
biomesData = applyDefaultBiomesSystem();
|
||||||
|
|
@ -309,8 +319,6 @@ function parseLoadedData(data) {
|
||||||
burgLabels = labels.select("#burgLabels");
|
burgLabels = labels.select("#burgLabels");
|
||||||
})();
|
})();
|
||||||
|
|
||||||
loadUsedFonts();
|
|
||||||
|
|
||||||
void (function parseGridData() {
|
void (function parseGridData() {
|
||||||
grid = JSON.parse(data[6]);
|
grid = JSON.parse(data[6]);
|
||||||
calculateVoronoi(grid, grid.points);
|
calculateVoronoi(grid, grid.points);
|
||||||
|
|
@ -423,7 +431,7 @@ function parseLoadedData(data) {
|
||||||
|
|
||||||
// 1.0 adds a legend box
|
// 1.0 adds a legend box
|
||||||
legend = svg.append("g").attr("id", "legend");
|
legend = svg.append("g").attr("id", "legend");
|
||||||
legend.attr("font-family", "Almendra SC").attr("data-font", "Almendra+SC").attr("font-size", 13).attr("data-size", 13).attr("data-x", 99).attr("data-y", 93).attr("stroke-width", 2.5).attr("stroke", "#812929").attr("stroke-dasharray", "0 4 10 4").attr("stroke-linecap", "round");
|
legend.attr("font-family", "Almendra SC").attr("font-size", 13).attr("data-size", 13).attr("data-x", 99).attr("data-y", 93).attr("stroke-width", 2.5).attr("stroke", "#812929").attr("stroke-dasharray", "0 4 10 4").attr("stroke-linecap", "round");
|
||||||
|
|
||||||
// 1.0 separated drawBorders fron drawStates()
|
// 1.0 separated drawBorders fron drawStates()
|
||||||
stateBorders = borders.append("g").attr("id", "stateBorders");
|
stateBorders = borders.append("g").attr("id", "stateBorders");
|
||||||
|
|
|
||||||
|
|
@ -275,14 +275,22 @@ async function getMapURL(type, options = {}) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// load non-standard fonts
|
// TODO: add dataURL for all used fonts
|
||||||
const usedFonts = getFontsList(clone);
|
const usedFonts = getUsedFonts(cloneEl);
|
||||||
const webSafe = ["Georgia", "Times+New+Roman", "Comic+Sans+MS", "Lucida+Sans+Unicode", "Courier+New", "Verdana", "Arial", "Impact"];
|
const fontsToLoad = usedFonts.filter(font => font.src);
|
||||||
const fontsToLoad = usedFonts.filter(font => !webSafe.includes(font));
|
|
||||||
if (fontsToLoad.length) {
|
if (fontsToLoad.length) {
|
||||||
const url = "https://fonts.googleapis.com/css?family=" + fontsToLoad.join("|");
|
const dataURLfonts = await loadFontsAsDataURI(fontsToLoad);
|
||||||
const fontStyle = await GFontToDataURI(url);
|
|
||||||
if (fontStyle) clone.select("defs").append("style").text(fontStyle.join("\n"));
|
const fontFaces = dataURLfonts
|
||||||
|
.map(({family, src, unicodeRange = "", variant = "normal"}) => {
|
||||||
|
return `@font-face {font-family: "${family}"; src: ${src}; unicode-range: ${unicodeRange}; font-variant: ${variant};}`;
|
||||||
|
})
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
const style = document.createElement("style");
|
||||||
|
style.setAttribute("type", "text/css");
|
||||||
|
style.innerHTML = fontFaces;
|
||||||
|
cloneEl.querySelector("defs").appendChild(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
clone.remove();
|
clone.remove();
|
||||||
|
|
@ -378,6 +386,7 @@ function getMapData() {
|
||||||
const biomes = [biomesData.color, biomesData.habitability, biomesData.name].join("|");
|
const biomes = [biomesData.color, biomesData.habitability, biomesData.name].join("|");
|
||||||
const notesData = JSON.stringify(notes);
|
const notesData = JSON.stringify(notes);
|
||||||
const rulersString = rulers.toString();
|
const rulersString = rulers.toString();
|
||||||
|
const fonts = JSON.stringify(getUsedFonts(svg.node()));
|
||||||
|
|
||||||
// save svg
|
// save svg
|
||||||
const cloneEl = document.getElementById("map").cloneNode(true);
|
const cloneEl = document.getElementById("map").cloneNode(true);
|
||||||
|
|
@ -414,7 +423,7 @@ function getMapData() {
|
||||||
const pop = Array.from(pack.cells.pop).map(p => rn(p, 4));
|
const pop = Array.from(pack.cells.pop).map(p => rn(p, 4));
|
||||||
|
|
||||||
// data format as below
|
// data format as below
|
||||||
const mapData = [params, settings, coords, biomes, notesData, serializedSVG, gridGeneral, grid.cells.h, grid.cells.prec, grid.cells.f, grid.cells.t, grid.cells.temp, packFeatures, cultures, states, burgs, pack.cells.biome, pack.cells.burg, pack.cells.conf, pack.cells.culture, pack.cells.fl, pop, pack.cells.r, pack.cells.road, pack.cells.s, pack.cells.state, pack.cells.religion, pack.cells.province, pack.cells.crossroad, religions, provinces, namesData, rivers, rulersString].join("\r\n");
|
const mapData = [params, settings, coords, biomes, notesData, serializedSVG, gridGeneral, grid.cells.h, grid.cells.prec, grid.cells.f, grid.cells.t, grid.cells.temp, packFeatures, cultures, states, burgs, pack.cells.biome, pack.cells.burg, pack.cells.conf, pack.cells.culture, pack.cells.fl, pop, pack.cells.r, pack.cells.road, pack.cells.s, pack.cells.state, pack.cells.religion, pack.cells.province, pack.cells.crossroad, religions, provinces, namesData, rivers, rulersString, fonts].join("\r\n");
|
||||||
TIME && console.timeEnd("createMapData");
|
TIME && console.timeEnd("createMapData");
|
||||||
return mapData;
|
return mapData;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,15 +32,20 @@ function tip(tip = "Tip is undefined", main, type, time) {
|
||||||
else if (type === "warn") tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #be5d08cc, #ffffff00)";
|
else if (type === "warn") tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #be5d08cc, #ffffff00)";
|
||||||
else if (type === "success") tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #127912cc, #ffffff00)";
|
else if (type === "success") tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #127912cc, #ffffff00)";
|
||||||
|
|
||||||
if (main) tooltip.dataset.main = tip; // set main tip
|
if (main) {
|
||||||
if (time) setTimeout(() => (tooltip.dataset.main = ""), time); // clear main in some time
|
tooltip.dataset.main = tip;
|
||||||
|
tooltip.dataset.color = tooltip.style.background;
|
||||||
|
}
|
||||||
|
if (time) setTimeout(() => clearMainTip(), time);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMainTip() {
|
function showMainTip() {
|
||||||
|
tooltip.style.background = tooltip.dataset.color;
|
||||||
tooltip.innerHTML = tooltip.dataset.main;
|
tooltip.innerHTML = tooltip.dataset.main;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearMainTip() {
|
function clearMainTip() {
|
||||||
|
tooltip.dataset.color = "";
|
||||||
tooltip.dataset.main = "";
|
tooltip.dataset.main = "";
|
||||||
tooltip.innerHTML = "";
|
tooltip.innerHTML = "";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ function editHeightmap() {
|
||||||
<p>You can <i>keep</i> the data, but you won't be able to change the coastline.</p>
|
<p>You can <i>keep</i> the data, but you won't be able to change the coastline.</p>
|
||||||
<p>Try <i>risk</i> mode to change the coastline and keep the data. The data will be restored as much as possible, but it can cause unpredictable errors.</p>
|
<p>Try <i>risk</i> mode to change the coastline and keep the data. The data will be restored as much as possible, but it can cause unpredictable errors.</p>
|
||||||
<p>Please <span class="pseudoLink" onclick=dowloadMap(); editHeightmap();>save the map</span> before editing the heightmap!</p>
|
<p>Please <span class="pseudoLink" onclick=dowloadMap(); editHeightmap();>save the map</span> before editing the heightmap!</p>
|
||||||
<p>Check out ${link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Heightmap-customization", "wiki")} for guidance.</p>`;
|
<p style="margin-bottom: 0">Check out ${link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Heightmap-customization", "wiki")} for guidance.</p>`;
|
||||||
|
|
||||||
$("#alert").dialog({
|
$("#alert").dialog({
|
||||||
resizable: false,
|
resizable: false,
|
||||||
|
|
|
||||||
|
|
@ -663,7 +663,7 @@ function showSavePane() {
|
||||||
$("#saveMapData").dialog({
|
$("#saveMapData").dialog({
|
||||||
title: "Save map",
|
title: "Save map",
|
||||||
resizable: false,
|
resizable: false,
|
||||||
width: "27em",
|
width: "25em",
|
||||||
position: {my: "center", at: "center", of: "svg"},
|
position: {my: "center", at: "center", of: "svg"},
|
||||||
buttons: {
|
buttons: {
|
||||||
Close: function () {
|
Close: function () {
|
||||||
|
|
@ -699,7 +699,7 @@ async function showLoadPane() {
|
||||||
$("#loadMapData").dialog({
|
$("#loadMapData").dialog({
|
||||||
title: "Load map",
|
title: "Load map",
|
||||||
resizable: false,
|
resizable: false,
|
||||||
width: "22em",
|
width: "24em",
|
||||||
position: {my: "center", at: "center", of: "svg"},
|
position: {my: "center", at: "center", of: "svg"},
|
||||||
buttons: {
|
buttons: {
|
||||||
Close: function () {
|
Close: function () {
|
||||||
|
|
@ -708,17 +708,23 @@ async function showLoadPane() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const dpx = document.getElementById("loadFromDropbox");
|
const loadFromDropboxButtons = document.getElementById("loadFromDropboxButtons");
|
||||||
const dpf = dpx.querySelector("select");
|
const fileSelect = document.getElementById("loadFromDropboxSelect");
|
||||||
const files = await Cloud.providers.dropbox.list();
|
const files = await Cloud.providers.dropbox.list();
|
||||||
dpx.style.display = files? "block" : "none";
|
|
||||||
if (!files) return;
|
if (!files) {
|
||||||
while(dpf.firstChild) dpf.removeChild(dpf.firstChild);
|
loadFromDropboxButtons.style.display = "none";
|
||||||
files.forEach(f => {
|
fileSelect.innerHTML = `<option value="" disabled selected>Save files to Dropbox first</option>`;
|
||||||
const opt = document.createElement('option');
|
return;
|
||||||
opt.innerText = f.name;
|
}
|
||||||
opt.value = f.path;
|
|
||||||
dpf.appendChild(opt);
|
loadFromDropboxButtons.style.display = "block";
|
||||||
|
fileSelect.innerHTML = "";
|
||||||
|
files.forEach(file => {
|
||||||
|
const opt = document.createElement("option");
|
||||||
|
opt.innerText = file.name;
|
||||||
|
opt.value = file.path;
|
||||||
|
fileSelect.appendChild(opt);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -475,7 +475,7 @@ function addLabelOnClick() {
|
||||||
const id = getNextId("label");
|
const id = getNextId("label");
|
||||||
|
|
||||||
let group = labels.select("#addedLabels");
|
let group = labels.select("#addedLabels");
|
||||||
if (!group.size()) group = labels.append("g").attr("id", "addedLabels").attr("fill", "#3e3e4b").attr("opacity", 1).attr("stroke", "#3a3a3a").attr("stroke-width", 0).attr("font-family", "Almendra SC").attr("data-font", "Almendra+SC").attr("font-size", 18).attr("data-size", 18).attr("filter", null);
|
if (!group.size()) group = labels.append("g").attr("id", "addedLabels").attr("fill", "#3e3e4b").attr("opacity", 1).attr("stroke", "#3a3a3a").attr("stroke-width", 0).attr("font-family", "Almendra SC").attr("font-size", 18).attr("data-size", 18).attr("filter", null);
|
||||||
|
|
||||||
const example = group.append("text").attr("x", 0).attr("x", 0).text(name);
|
const example = group.append("text").attr("x", 0).attr("x", 0).text(name);
|
||||||
const width = example.node().getBBox().width;
|
const width = example.node().getBBox().width;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue