diff --git a/index.html b/index.html
index 20afab01..90af6a46 100644
--- a/index.html
+++ b/index.html
@@ -970,8 +970,8 @@
Please select a saving variant:
-
-
-
-
-
+
+
+
+
+
Generator uses pop-up window to download files. Please ensure your browser does not block popups
@@ -3254,14 +3319,12 @@
Load map from:
-
-
-
+
+
+
-
-
diff --git a/main.js b/main.js
index af2bf3ff..8693ad9a 100644
--- a/main.js
+++ b/main.js
@@ -7,7 +7,7 @@
// See also https://github.com/Azgaar/Fantasy-Map-Generator/issues/153
"use strict";
-const version = "1.21"; // generator version
+const version = "1.22"; // generator version
document.title += " v" + version;
// if map version is not stored, clear localStorage and show a message
@@ -1233,8 +1233,9 @@ function addMarkers(number = 1) {
const burg = pack.burgs[cells.burg[cell]];
const river = pack.rivers.find(r => r.i === pack.cells.r[cell]);
- const name = Math.random() < .2 ? river.name : burg.name;
- notes.push({id, name:`${name} Bridge`, legend:`A stone bridge over the ${river.name} ${river.type} near ${burg.name}`});
+ const riverName = river ? `${river.name} ${river.type}` : "river";
+ const name = river && Math.random() < .2 ? river.name : burg.name;
+ notes.push({id, name:`${name} Bridge`, legend:`A stone bridge over the ${riverName} near ${burg.name}`});
count--;
}
}()
@@ -1393,10 +1394,10 @@ function addZones(number = 1) {
}
function addRebels() {
- const state = ra(states.filter(s => s.i && Array.from(s.neighbors).some(n => n)));
+ const state = ra(states.filter(s => s.i && s.neighbors.some(n => n)));
if (!state) return;
- const neib = ra(Array.from(state.neighbors).filter(n => n));
+ const neib = ra(state.neighbors.filter(n => n));
const cell = cells.i.find(i => cells.state[i] === state.i && cells.c[i].some(c => cells.state[c] === neib));
const cellsArray = [], queue = [cell], power = rand(10, 30);
@@ -1683,14 +1684,14 @@ function showStatistics() {
const regenerateMap = debounce(function() {
console.warn("Generate new random map");
- closeDialogs("#worldConfigurator");
+ closeDialogs("#worldConfigurator, #options3d");
customization = 0;
undraw();
resetZoom(1000);
generate();
restoreLayers();
const canvas3d = document.getElementById("canvas3d");
- if (canvas3d) update3dPreview(canvas3d);
+ if (canvas3d) ThreeD.redraw();
if ($("#worldConfigurator").is(":visible")) editWorld();
}, 500);
diff --git a/modules/burgs-and-states.js b/modules/burgs-and-states.js
index f6bbed0c..6a1d976e 100644
--- a/modules/burgs-and-states.js
+++ b/modules/burgs-and-states.js
@@ -558,6 +558,9 @@
}
}
+ // convert neighbors Set object into array
+ states.forEach(s => s.neighbors = Array.from(s.neighbors));
+
console.timeEnd("collectStatistics");
}
@@ -568,7 +571,7 @@
// assin basic color using greedy coloring algorithm
pack.states.forEach(s => {
if (!s.i || s.removed) return;
- const neibs = Array.from(s.neighbors);
+ const neibs = s.neighbors;
s.color = colors.find(c => neibs.every(n => pack.states[n].color !== c));
if (!s.color) s.color = getRandomColor();
colors.push(colors.shift());
@@ -633,8 +636,8 @@
};
const naval = states[f].type === "Naval" && states[t].type === "Naval" && cells.f[states[f].center] !== cells.f[states[t].center];
- const neib = naval ? false : states[f].neighbors.has(t);
- const neibOfNeib = naval || neib ? false : [...states[f].neighbors].map(n => [...states[n].neighbors]).join().includes(t);
+ const neib = naval ? false : states[f].neighbors.includes(t);
+ const neibOfNeib = naval || neib ? false : states[f].neighbors.map(n => states[n].neighbors).join().includes(t);
let status = naval ? rw(navals) : neib ? rw(neibs) : neibOfNeib ? rw(neibsOfNeibs) : rw(far);
@@ -770,7 +773,7 @@
const form = monarchy[expTiers[s.i]];
// Default name depends on exponent tier, some culture bases have special names for tiers
if (s.diplomacy) {
- if (form === "Duchy" && s.neighbors.size > 1 && rand(6) < s.neighbors.size && s.diplomacy.includes("Vassal")) return "Marches"; // some vassal dutchies on borderland
+ if (form === "Duchy" && s.neighbors.length > 1 && rand(6) < s.neighbors.length && s.diplomacy.includes("Vassal")) return "Marches"; // some vassal dutchies on borderland
if (Math.random() < .3 && s.diplomacy.includes("Vassal")) return "Protectorate"; // some vassals
}
diff --git a/modules/names-generator.js b/modules/names-generator.js
index ac53144d..0ace981e 100644
--- a/modules/names-generator.js
+++ b/modules/names-generator.js
@@ -227,7 +227,7 @@
{name: "Berber", i: 17, min: 4, max: 10, d: "s", m: .2, b: "Abkhouch,Adrar,Agadir,Agelmam,Aghmat,Agrakal,Agulmam,Ahaggar,Almou,Anfa,Annaba,Aousja,Arbat,Argoub,Arif,Asfi,Assamer,Assif,Azaghar,Azmour,Azrou,Beccar,Beja,Bennour,Benslimane,Berkane,Berrechid,Bizerte,Bouskoura,Boutferda,Dar Bouazza,Darallouch,Darchaabane,Dcheira,Denden,Djebel,Djedeida,Drargua,Essaouira,Ezzahra,Fas,Fnideq,Ghezeze,Goubellat,Grisaffen,Guelmim,Guercif,Hammamet,Harrouda,Hoceima,Idurar,Ifendassen,Ifoghas,Imilchil,Inezgane,Izoughar,Jendouba,Kacem,Kelibia,Kenitra,Kerrando,Khalidia,Khemisset,Khenifra,Khouribga,Kidal,Korba,Korbous,Lahraouyine,Larache,Leyun,Lqliaa,Manouba,Martil,Mazagan,Mcherga,Mdiq,Megrine,Mellal,Melloul,Midelt,Mohammedia,Mornag,Mrrakc,Nabeul,Nadhour,Nador,Nawaksut,Nefza,Ouarzazate,Ouazzane,Oued Zem,Oujda,Ouladteima,Qsentina,Rades,Rafraf,Safi,Sefrou,Sejnane,Settat,Sijilmassa,Skhirat,Slimane,Somaa,Sraghna,Susa,Tabarka,Taferka,Tafza,Tagbalut,Tagerdayt,Takelsa,Tanja,Tantan,Taourirt,Taroudant,Tasfelalayt,Tattiwin,Taza,Tazerka,Tazizawt,Tebourba,Teboursouk,Temara,Testour,Tetouan,Tibeskert,Tifelt,Tinariwen,Tinduf,Tinja,Tiznit,Toubkal,Trables,Tubqal,Tunes,Urup,Watlas,Wehran,Wejda,Youssoufia,Zaghouan,Zahret,Zemmour,Zriba"},
{name: "Arabic", i: 18, min: 4, max: 9, d: "ae", m: .2, b: "Abadilah,Abayt,Abha,Abud,Aden,Ahwar,Ajman,Alabadilah,Alabar,Alahjer,Alain,Alaraq,Alarish,Alarjam,Alashraf,Alaswaaq,Alawali,Albarar,Albawadi,Albirk,Aldhabiyah,Alduwaid,Alfareeq,Algayed,Alhada,Alhafirah,Alhamar,Alharam,Alharidhah,Alhawtah,Alhazim,Alhrateem,Alhudaydah,Alhujun,Alhuwaya,Aljahra,Aljohar,Aljubail,Alkawd,Alkhalas,Alkhawaneej,Alkhen,Alkhhafah,Alkhobar,Alkhuznah,Alkiranah,Allisafah,Allith,Almadeed,Almardamah,Almarwah,Almasnaah,Almejammah,Almojermah,Almshaykh,Almurjan,Almuwayh,Almuzaylif,Alnaheem,Alnashifah,Alqadeimah,Alqah,Alqahma,Alqalh,Alqouz,Alquaba,Alqunfudhah,Alqurayyat,Alradha,Alraqmiah,Alsadyah,Alsafa,Alshagab,Alshoqiq,Alshuqaiq,Alsilaa,Althafeer,Alwakrah,Alwasqah,Amaq,Amran,Annaseem,Aqbiyah,Arafat,Arar,Ardah,Arrawdah,Asfan,Ashayrah,Ashshahaniyah,Askar,Assaffaniyah,Ayaar,Aziziyah,Baesh,Bahrah,Baish,Balhaf,Banizayd,Baqaa,Baqal,Bidiyah,Bisha,Biyatah,Buqhayq,Burayda,Dafiyat,Damad,Dammam,Dariyah,Daynah,Dhafar,Dhahran,Dhalkut,Dhamar,Dhubab,Dhurma,Dibab,Dirab,Doha,Dukhan,Duwaibah,Enaker,Fadhla,Fahaheel,Fanateer,Farasan,Fardah,Fujairah,Ghalilah,Ghar,Ghizlan,Ghomgyah,Ghran,Hababah,Habil,Hadiyah,Haffah,Hajanbah,Hajrah,Halban,Haqqaq,Haradh,Hasar,Hathah,Hawarwar,Hawaya,Hawiyah,Hebaa,Hefar,Hijal,Husnah,Huwailat,Huwaitah,Irqah,Isharah,Ithrah,Jamalah,Jarab,Jareef,Jarwal,Jash,Jazan,Jeddah,Jiblah,Jihanah,Jilah,Jizan,Joha,Joraibah,Juban,Jubbah,Juddah,Jumeirah,Kamaran,Keyad,Khab,Khabtsaeed,Khaiybar,Khasab,Khathirah,Khawarah,Khulais,Khulays,Klayah,Kumzar,Limah,Linah,Mabar,Madrak,Mahab,Mahalah,Makhtar,Makshosh,Manfuhah,Manifah,Manshabah,Mareah,Masdar,Mashwar,Masirah,Maskar,Masliyah,Mastabah,Maysaan,Mazhar,Mdina,Meeqat,Mirbah,Mirbat,Mokhtara,Muharraq,Muladdah,Musandam,Musaykah,Muscat,Mushayrif,Musrah,Mussafah,Mutrah,Nafhan,Nahdah,Nahwa,Najran,Nakhab,Nizwa,Oman,Qadah,Qalhat,Qamrah,Qasam,Qatabah,Qawah,Qosmah,Qurain,Quraydah,Quriyat,Qurwa,Rabigh,Radaa,Rafha,Rahlah,Rakamah,Rasheedah,Rasmadrakah,Risabah,Rustaq,Ryadh,Saabah,Saabar,Sabtaljarah,Sabya,Sadad,Sadah,Safinah,Saham,Sahlat,Saihat,Salalah,Salmalzwaher,Salmiya,Sanaa,Sanaban,Sayaa,Sayyan,Shabayah,Shabwah,Shafa,Shalim,Shaqra,Sharjah,Sharkat,Sharurah,Shatifiyah,Shibam,Shidah,Shifiyah,Shihar,Shoqra,Shoqsan,Shuwaq,Sibah,Sihmah,Sinaw,Sirwah,Sohar,Suhailah,Sulaibiya,Sunbah,Tabuk,Taif,Taqah,Tarif,Tharban,Thumrait,Thuqbah,Thuwal,Tubarjal,Turaif,Turbah,Tuwaiq,Ubar,Umaljerem,Urayarah,Urwah,Wabrah,Warbah,Yabreen,Yadamah,Yafur,Yarim,Yemen,Yiyallah,Zabid,Zahwah,Zallaq,Zinjibar,Zulumah"},
{name: "Inuit", i: 19, min: 5, max: 15, d: "alutsn", m: 0, b: "Aaluik,Aappilattoq,Aasiaat,Agdleruussakasit,Aggas,Akia,Akilia,Akuliaruseq,Akuliarutsip,Akunnaaq,Agissat,Agssaussat,Alluitsup,Alluttoq,Aluit,Aluk,Ammassalik,Amarortalik,Amitsorsuaq,Anarusuk,Angisorsuaq,Anguniartarfik,Annertussoq,Annikitsoq,Anoraliuirsoq,Appat,Apparsuit,Apusiaajik,Arsivik,Arsuk,Ataa,Atammik,Ateqanngitsorsuaq,Atilissuaq,Attu,Aukarnersuaq,Augpalugtoq, Aumat,Auvilikavsak,Auvilkikavsaup,Avadtlek,Avallersuaq,Bjornesk,Blabaerdalen,Blomsterdalen,Brattalhid,Bredebrae,Brededal,Claushavn,Edderfulegoer,Egger,Eqalugalinnguit,Eqalugarssuit,Eqaluit,Eqqua,Etah,Graah,Hakluyt,Haredalen,Hareoen,Hundeo,Igdlorssuit,Igaliku,Igdlugdlip,Igdluluarssuk,Iginniafik,Ikamiuk,Ikamiut,Ikarissat,Ikateq,Ikeq,Ikerasak,Ikerasaarsuk,Ikermiut,Ikermoissuaq,Ikertivaq,Ikorfarssuit,Ikorfat,Ilimanaq,Illorsuit,Iluileq,Iluiteq,Ilulissat,Illunnguit,Imaarsivik,Imartunarssuk,Immikkoortukajik,Innaarsuit,Ingjald,Inneruulalik,Inussullissuaq,Iqek,Ikerasakassak,Iperaq,Ippik,Isortok,Isungartussoq,Itileq,Itivdleq,Itissaalik,Ittit,Ittoqqortoormiit,Ivingmiut,Ivittuut,Kanajoorartuut,Kangaamiut,Kangaarsuk,Kangaatsiaq,Kangeq,Kangerluk,Kangerlussuaq,Kanglinnguit,Kapisillit,Karrat,Kekertamiut,Kiatak,Kiatassuaq,Kiataussaq,Kigatak,Kigdlussat,Kinaussak,Kingittorsuaq,Kitak,Kitsissuarsuit,Kitsissut,Klenczner,Kook,Kraulshavn,Kujalleq,Kullorsuaq,Kulusuk,Kuurmiit,Kuusuaq,Laksedalen,Maniitsoq,Marrakajik,Mattaangassut,Mernoq,Mittivakkat,Moriusaq,Myggbukta,Naajaat,Nako,Nangissat,Nanortalik,Nanuuseq,Nappassoq,Narsarmijt,Narssaq,Narsarsuaq,Narssarssuk,Nasaussaq,Nasiffik,Natsiarsiorfik,Naujanguit,Niaqornaarsuk,Niaqornat,Nordfjordspasset,Nugatsiaq,Nuluuk,Nunaa,Nunarssit,Nunarsuaq,Nunataaq,Nunatakavsaup,Nutaarmiut,Nuugaatsiaq,Nuuk,Nuukullak,Nuuluk,Nuussuaq,Olonkinbyen,Oqaatsut,Oqaitsúnguit,Oqonermiut,Oodaaq,Paagussat,Palungataq,Pamialluk,Paamiut,Paatuut,Patuersoq,Perserajoq,Paornivik,Pituffik,Puugutaa,Puulkuip,Qaanaq,Qaarsorsuaq,Qaarsorsuatsiaq,Qaasuitsup,Qaersut,Qajartalik,Qallunaat,Qaneq,Qaqaarissorsuaq,Qaqit,Qaqortok,Qasigiannguit,Qasse,Qassimiut,Qeertartivaq,Qeertartivatsiaq,Qeqertaq,Qeqertarssdaq,Qeqertarsuaq,Qeqertasussuk,Qeqertarsuatsiaat,Qeqertat,Qeqqata,Qernertoq,Qernertunnguit,Qianarreq,Qilalugkiarfik,Qingagssat,Qingaq,Qoornuup,Qorlortorsuaq,Qullikorsuit,Qunnerit,Qutdleq,Ravnedalen,Ritenbenk,Rypedalen,Sarfannguit,Saarlia,Saarloq,Saatoq,Saatorsuaq,Saatup,Saattut,Sadeloe,Salleq,Salliaruseq,Sammeqqat,Sammisoq,Sanningassoq,Saqqaq,Saqqarlersuaq,Saqqarliit,Sarqaq,Sattiaatteq,Savissivik,Serfanguaq,Sermersooq,Sermersut,Sermilik,Sermiligaaq,Sermitsiaq,Simitakaja,Simiutaq,Singamaq,Siorapaluk,Sisimiut,Sisuarsuit,Skal,Skarvefjeld,Skjoldungen,Storoen,Sullorsuaq,Suunikajik,Sverdrup,Taartoq,Takiseeq,Talerua,Tarqo,Tasirliaq,Tasiusak,Tiilerilaaq,Timilersua,Timmiarmiut,Tingmjarmiut,Traill,Tukingassoq,Tuttorqortooq,Tuujuk,Tuttulissuup,Tussaaq,Uigordlit,Uigorlersuaq,Uilortussoq,Uiivaq,Ujuaakajiip,Ukkusissat,Umanat,Upernavik,Upernattivik,Upepnagssivik,Upernivik,Uttorsiutit,Uumannaq,Uummannaarsuk,Uunartoq,Uvkusigssat,Ymer"},
- {name: "Basque", i: 20, min: 4, max: 11, d: "r", m: .1, b: "Abadio,Abaltzisketa,Abanto Zierbena,Aduna,Agurain,Aia,Aiara,Aizarnazabal,Ajangiz,Albiztur,Alegia,Alkiza,Alonsotegi,Altzaga,Altzo,Amezketa,Amorebieta,Amoroto,Amurrio,Andoain,Anoeta,Antzuola,Arakaldo,Arama,Aramaio,Arantzazu,Arbatzegi ,Areatza,Aretxabaleta,Arraia,Arrankudiaga,Arrasate,Arratzu,Arratzua,Arrieta,Arrigorriaga,Artea,Artzentales,Artziniega,Asparrena,Asteasu,Astigarraga,Ataun,Atxondo,Aulesti,Azkoitia,Azpeitia,Bakio,Baliarrain,Balmaseda,Barakaldo,Barrika,Barrundia,Basauri,Bastida,Beasain,Bedia,Beizama,Belauntza,Berango,Berantevilla,Berastegi,Bergara,Bermeo,Bernedo,Berriatua,Berriz,Berrobi,Bidania,Bilar,Bilbao,Burgelu,Busturia,Deba,Derio,Dima,Donemiliaga,Donostia,Dulantzi,Durango,Ea,Eibar,Elantxobe,Elduain,Elgeta,Elgoibar,Elorrio,Erandio,Ere–o,Ermua,Errenteria,Errezil,Erribera Beitia,Erriberagoitia,Errigoiti,Eskoriatza,Eskuernaga,Etxebarri,Etxebarria,Ezkio,Fika,Forua,Fruiz,Gabiria,Gaintza,Galdakao,Galdames,Gamiz,Garai,Gasteiz,Gatika,Gatzaga,Gaubea,Gauna,Gautegiz Arteaga,Gaztelu,Gernika,Gerrikaitz,Getaria,Getxo,Gizaburuaga,Goiatz,Gordexola,Gorliz,Harana,Hernani,Hernialde,Hondarribia,Ibarra,Ibarrangelu,Idiazabal,Iekora,Igorre,Ikaztegieta,Iru–a Oka,Irun,Irura,Iruraiz,Ispaster,Itsaso,Itsasondo,Iurreta,Izurtza,Jatabe,Kanpezu,Karrantza Harana,Kortezubi,Kripan,Kuartango,Lanestosa,Lantziego,Larrabetzu,Larraul,Lasarte,Laudio,Laukiz,Lazkao,Leaburu,Legazpi,Legorreta,Legutio,Leintz,Leioa,Lekeitio,Lemoa,Lemoiz,Leza,Lezama,Lezo,Lizartza,Loiu,Lumo,Ma–aria,Maeztu,Mallabia,Markina,Maruri,Ma–ueta,Me–aka,Mendaro,Mendata,Mendexa,Moreda Araba,Morga,Mundaka,Mungia,Munitibar,Murueta,Muskiz,Mutiloa,Mutriku,Muxika,Nabarniz,O–ati,Oiartzun,Oion,Okondo,Olaberria,Ondarroa,Ordizia,Orendain,Orexa,Oria,Orio,Ormaiztegi,Orozko,Ortuella,Otxandio,Pasaia,Plentzia,Portugalete,Samaniego,Santurtzi,Segura,Sestao,Sondika,Sopela,Sopuerta,Soraluze,Sukarrieta,Tolosa,Trapagaran,Turtzioz,Ubarrundia,Ubide,Ugao,Urdua,Urduliz,Urizaharra,Urkabustaiz,Urnieta,Urretxu,Usurbil,Xemein,Zaia,Zaldibar,Zaldibia,Zalduondo,Zambrana,Zamudio,Zaratamo,Zarautz,Zeanuri,Zeberio,Zegama,Zerain,Zestoa,Zierbena,Zigoitia,Ziortza,Zizurkil,Zuia,Zumaia,Zumarraga"},
+ {name: "Basque", i: 20, min: 4, max: 11, d: "r", m: .1, b: "Abadio,Abaltzisketa,Abanto Zierbena,Aduna,Agurain,Aia,Aiara,Aizarnazabal,Ajangiz,Albiztur,Alegia,Alkiza,Alonsotegi,Altzaga,Altzo,Amezketa,Amorebieta,Amoroto,Amurrio,Andoain,Anoeta,Antzuola,Arakaldo,Arama,Aramaio,Arantzazu,Arbatzegi ,Areatza,Aretxabaleta,Arraia,Arrankudiaga,Arrasate,Arratzu,Arratzua,Arrieta,Arrigorriaga,Artea,Artzentales,Artziniega,Asparrena,Asteasu,Astigarraga,Ataun,Atxondo,Aulesti,Azkoitia,Azpeitia,Bakio,Baliarrain,Balmaseda,Barakaldo,Barrika,Barrundia,Basauri,Bastida,Beasain,Bedia,Beizama,Belauntza,Berango,Berantevilla,Berastegi,Bergara,Bermeo,Bernedo,Berriatua,Berriz,Berrobi,Bidania,Bilar,Bilbao,Burgelu,Busturia,Deba,Derio,Dima,Donemiliaga,Donostia,Dulantzi,Durango,Ea,Eibar,Elantxobe,Elduain,Elgeta,Elgoibar,Elorrio,Erandio,Ere-o,Ermua,Errenteria,Errezil,Erribera Beitia,Erriberagoitia,Errigoiti,Eskoriatza,Eskuernaga,Etxebarri,Etxebarria,Ezkio,Fika,Forua,Fruiz,Gabiria,Gaintza,Galdakao,Galdames,Gamiz,Garai,Gasteiz,Gatika,Gatzaga,Gaubea,Gauna,Gautegiz Arteaga,Gaztelu,Gernika,Gerrikaitz,Getaria,Getxo,Gizaburuaga,Goiatz,Gordexola,Gorliz,Harana,Hernani,Hernialde,Hondarribia,Ibarra,Ibarrangelu,Idiazabal,Iekora,Igorre,Ikaztegieta,Iru-a Oka,Irun,Irura,Iruraiz,Ispaster,Itsaso,Itsasondo,Iurreta,Izurtza,Jatabe,Kanpezu,Karrantza Harana,Kortezubi,Kripan,Kuartango,Lanestosa,Lantziego,Larrabetzu,Larraul,Lasarte,Laudio,Laukiz,Lazkao,Leaburu,Legazpi,Legorreta,Legutio,Leintz,Leioa,Lekeitio,Lemoa,Lemoiz,Leza,Lezama,Lezo,Lizartza,Loiu,Lumo,Ma-aria,Maeztu,Mallabia,Markina,Maruri,Ma-ueta,Me-aka,Mendaro,Mendata,Mendexa,Moreda Araba,Morga,Mundaka,Mungia,Munitibar,Murueta,Muskiz,Mutiloa,Mutriku,Muxika,Nabarniz,O-ati,Oiartzun,Oion,Okondo,Olaberria,Ondarroa,Ordizia,Orendain,Orexa,Oria,Orio,Ormaiztegi,Orozko,Ortuella,Otxandio,Pasaia,Plentzia,Portugalete,Samaniego,Santurtzi,Segura,Sestao,Sondika,Sopela,Sopuerta,Soraluze,Sukarrieta,Tolosa,Trapagaran,Turtzioz,Ubarrundia,Ubide,Ugao,Urdua,Urduliz,Urizaharra,Urkabustaiz,Urnieta,Urretxu,Usurbil,Xemein,Zaia,Zaldibar,Zaldibia,Zalduondo,Zambrana,Zamudio,Zaratamo,Zarautz,Zeanuri,Zeberio,Zegama,Zerain,Zestoa,Zierbena,Zigoitia,Ziortza,Zizurkil,Zuia,Zumaia,Zumarraga"},
{name: "Nigerian", i: 21, min: 4, max: 10, d: "", m: .3, b: "Abadogo,Abafon,Abdu,Acharu,Adaba,Adealesu,Adeto,Adyongo,Afaga,Afamju,Afuje,Agbelagba,Agigbigi,Agogoke,Ahute,Aiyelaboro,Ajebe,Ajola,Akarekwu,Akessan,Akunuba,Alawode,Alkaijji,Amangam,Amaoji,Amgbaye,Amtasa,Amunigun,Anase,Aniho,Animahun,Antul,Anyoko,Apekaa,Arapagi,Asamagidi,Asande,Ataibang,Awgbagba,Awhum,Awodu,Babanana,Babateduwa,Bagu,Bakura,Bandakwai,Bangdi,Barbo,Barkeje,Basa,Basabra,Basansagawa,Bieleshin,Bilikani,Birnindodo,Braidu,Bulakawa,Buriburi,Burisidna,Busum,Bwoi,Cainnan,Chakum,Charati,Chondugh,Dabibikiri,Dagwarga,Dallok,Danalili,Dandala,Darpi,Dhayaki,Dokatofa,Doma,Dozere,Duci,Dugan,Ebelibri,Efem,Efoi,Egudu,Egundugbo,Ekoku,Ekpe,Ekwere,Erhua,Eteu,Etikagbene,Ewhoeviri,Ewhotie,Ezemaowa,Fatima,Gadege,Galakura,Galea,Gamai,Gamen,Ganjin,Gantetudu,Garangamawa,Garema,Gargar,Gari,Garinbode,Garkuwa,Garu Kime,Gazabu,Gbure,Gerti,Gidan,Giringwe,Gitabaremu,Giyagiri,Giyawa,Gmawa,Golakochi,Golumba,Guchi,Gudugu,Gunji,Gusa,Gwambula,Gwamgwam,Gwodoti,Hayinlere,Hayinmaialewa,Hirishi,Hombo,Ibefum,Iberekodo,Ibodeipa,Icharge,Ideoro,Idofin,Idofinoka,Idya,Iganmeji,Igbetar,Igbogo,Ijoko,Ijuwa,Ikawga,Ikekogbe,Ikhin,Ikoro,Ikotefe,Ikotokpora,Ikpakidout,Ikpeoniong,Ilofa,Imuogo,Inyeneke,Iorsugh,Ipawo,Ipinlerere,Isicha,Itakpa,Itoki,Iyedeame,Jameri,Jangi,Jara,Jare,Jataudakum,Jaurogomki,Jepel,Jibam,Jirgu,Jirkange,Kafinmalama,Kamkem,Katab,Katanga,Katinda,Katirije,Kaurakimba,Keffinshanu,Kellumiri,Kiagbodor,Kibiare,Kingking,Kirbutu,Kita,Kogbo,Kogogo,Kopje,Koriga,Koroko,Korokorosei,Kotoku,Kuata,Kujum,Kukau,Kunboon,Kuonubogbene,Kurawe,Kushinahu,Kwaramakeri,Ladimeji,Lafiaro,Lahaga,Laindebajanle,Laindegoro,Lajere,Lakati,Ligeri,Litenswa,Lokobimagaji,Lusabe,Maba,Madarzai,Magoi,Maialewa,Maianita,Maijuja,Mairakuni,Maleh,Malikansaa,Mallamkola,Mallammaduri,Marmara,Masagu,Masoma,Mata,Matankali,Mbalare,Megoyo,Meku,Miama,Mige,Mkporagwu,Modi,Molafa,Mshi,Msugh,Muduvu,Murnachehu,Namnai,Nanumawa,Nasudu,Ndagawo,Ndamanma,Ndiebeleagu,Ndiwulunbe,Ndonutim,Ngaruwa,Ngbande,Nguengu,Nto Ekpe,Nubudi,Nyajo,Nyido,Nyior,Obafor,Obazuwa,Odajie,Odiama,Ofunatam,Ogali,Ogan,Ogbaga,Ogbahu,Ogultu,Ogunbunmi,Ogunmakin,Ojaota,Ojirami,Ojopode,Okehin,Olugunna,Omotunde,Onipede,Onisopi,Onma,Orhere,Orya,Oshotan,Otukwang,Otunade,Pepegbene,Poros,Rafin,Rampa,Rimi,Rinjim,Robertkiri,Rugan,Rumbukawa,Sabiu,Sabon,Sabongari,Sai,Salmatappare,Sangabama,Sarabe,Seboregetore,Seibiri,Sendowa,Shafar,Shagwa,Shata,Shefunda,Shengu,Sokoron,Sunnayu,Taberlma,Tafoki,Takula,Talontan,Taraku,Tarhemba,Tayu,Ter,Timtim,Timyam,Tindirke,Tirkalou,Tokunbo,Tonga,Torlwam,Tseakaadza,Tseanongo,Tseavungu,Tsebeeve,Tsekov,Tsepaegh,Tuba,Tumbo,Tungalombo,Tungamasu,Tunganrati,Tunganyakwe,Tungenzuri,Ubimimi,Uhkirhi,Umoru,Umuabai,Umuaja,Umuajuju,Umuimo,Umuojala,Unchida,Ungua,Unguwar,Unongo,Usha,Ute,Utongbo,Vembera,Vorokotok,Wachin,Walebaga,Wurawura,Wuro,Yanbashi,Yanmedi,Yenaka,Yoku,Zamangera,Zarunkwari,Zilumo,Zulika"},
{name: "Celtic", i: 22, min: 4, max: 12, d: "nld", m: 0, b: "Aberaman,Aberangell,Aberarth,Aberavon,Aberbanc,Aberbargoed,Aberbeeg,Abercanaid,Abercarn,Abercastle,Abercegir,Abercraf,Abercregan,Abercych,Abercynon,Aberdare,Aberdaron,Aberdaugleddau,Aberdeen,Aberdulais,Aberdyfi,Aberedw,Abereiddy,Abererch,Abereron,Aberfan,Aberffraw,Aberffrwd,Abergavenny,Abergele,Aberglasslyn,Abergorlech,Abergwaun,Abergwesyn,Abergwili,Abergwynfi,Abergwyngregyn,Abergynolwyn,Aberhafesp,Aberhonddu,Aberkenfig,Aberllefenni,Abermain,Abermaw,Abermorddu,Abermule,Abernant,Aberpennar,Aberporth,Aberriw,Abersoch,Abersychan,Abertawe,Aberteifi,Aberthin,Abertillery,Abertridwr,Aberystwyth,Achininver,Afonhafren,Alisaha,Antinbhearmor,Ardenna,Attacon,Beira,Bhrura,Boioduro,Bona,Boudobriga,Bravon,Brigant,Briganta,Briva,Cambodunum,Cambra,Caracta,Catumagos,Centobriga,Ceredigion,Chalain,Dinn,Diwa,Dubingen,Duro,Ebora,Ebruac,Eburodunum,Eccles,Eighe,Eireann,Ferkunos,Genua,Ghrainnse,Inbhear,Inbhir,Inbhirair,Innerleithen,Innerleven,Innerwick,Inver,Inveraldie,Inverallan,Inveralmond,Inveramsay,Inveran,Inveraray,Inverarnan,Inverbervie,Inverclyde,Inverell,Inveresk,Inverfarigaig,Invergarry,Invergordon,Invergowrie,Inverhaddon,Inverkeilor,Inverkeithing,Inverkeithney,Inverkip,Inverleigh,Inverleith,Inverloch,Inverlochlarig,Inverlochy,Invermay,Invermoriston,Inverness,Inveroran,Invershin,Inversnaid,Invertrossachs,Inverugie,Inveruglas,Inverurie,Kilninver,Kirkcaldy,Kirkintilloch,Krake,Latense,Leming,Lindomagos,Llanaber,Lochinver,Lugduno,Magoduro,Monmouthshire,Narann,Novioduno,Nowijonago,Octoduron,Penning,Pheofharain,Ricomago,Rossinver,Salodurum,Seguia,Sentica,Theorsa,Uige,Vitodurum,Windobona"},
{name: "Mesopotamian", i: 23, min: 4, max: 9, d: "srpl", m: .1, b: "Adab,Akkad,Akshak,Amnanum,Arbid,Arpachiyah,Arrapha,Assur,Babilim,Badtibira,Balawat,Barsip,Borsippa,Carchemish,Chagar Bazar,Chuera,Ctesiphon ,Der,Dilbat,Diniktum,Doura,Durkurigalzu,Ekallatum,Emar,Erbil,Eridu,Eshnunn,Fakhariya ,Gawra,Girsu,Hadatu,Hamoukar,Haradum,Harran,Hatra,Idu,Irisagrig,Isin,Jemdet,Kahat,Kartukulti,Khaiber,Kish ,Kisurra,Kuara,Kutha,Lagash,Larsa ,Leilan,Marad,Mardaman,Mari,Mashkan,Mumbaqat ,Nabada,Nagar,Nerebtum,Nimrud,Nineveh,Nippur,Nuzi,Qalatjarmo,Qatara,Rawda,Seleucia,Shaduppum,Shanidar,Sharrukin,Shemshara,Shibaniba,Shuruppak,Sippar,Tarbisu,Tellagrab,Tellessawwan,Tellessweyhat,Tellhassuna,Telltaya,Telul,Terqa,Thalathat,Tutub,Ubaid ,Umma,Ur,Urfa,Urkesh,Uruk,Urum,Zabalam,Zenobia"},
diff --git a/modules/river-generator.js b/modules/river-generator.js
index cd8f09f4..eac7dfab 100644
--- a/modules/river-generator.js
+++ b/modules/river-generator.js
@@ -4,7 +4,7 @@
(global.Rivers = factory());
}(this, (function () {'use strict';
- const generate = function Rivers() {
+ const generate = function() {
console.time('generateRivers');
Math.seedrandom(seed);
const cells = pack.cells, p = cells.p, features = pack.features;
@@ -285,11 +285,11 @@
}
const getBasin = function(r, p, e) {
- while (p) {
+ while (p && r !== p && r !== e) {
const parent = pack.rivers.find(r => r.i === p);
- if (parent) r = parent.i;
- p = parent ? parent.parent : 0;
- if (r === e) return r;
+ if (!parent) return r;
+ r = parent.i;
+ p = parent.parent;
}
return r;
}
diff --git a/modules/save-and-load.js b/modules/save-and-load.js
index 2fb726ed..d8760d90 100644
--- a/modules/save-and-load.js
+++ b/modules/save-and-load.js
@@ -84,6 +84,7 @@ async function getMapURL(type, subtype) {
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
if (isFirefox && type === "mesh") clone.select("#oceanPattern").remove();
if (subtype === "globe") clone.select("#scaleBar").remove();
+ if (subtype === "noWater") {clone.select("#oceanBase").attr("opacity", 0); clone.select("#oceanPattern").attr("opacity", 0);}
if (type === "mesh") clone.attr("width", graphWidth).attr("height", graphHeight);
if (type !== "png") clone.select("#viewbox").attr("transform", null); // reset transform to show whole map
if (type === "svg") removeUnusedElements(clone);
@@ -670,7 +671,7 @@ function parseLoadedData(data) {
pack.burgs = JSON.parse(data[15]);
pack.religions = data[29] ? JSON.parse(data[29]) : [{i: 0, name: "No religion"}];
pack.provinces = data[30] ? JSON.parse(data[30]) : [0];
- pack.rivers = data[32] ? JSON.stringify(data[32]) : [];
+ pack.rivers = data[32] ? JSON.parse(data[32]) : [];
const cells = pack.cells;
cells.biome = Uint8Array.from(data[16].split(","));
@@ -746,7 +747,7 @@ function parseLoadedData(data) {
void function resolveVersionConflicts() {
const version = parseFloat(data[0].split("|")[0]);
- if (version == 0.8) {
+ if (version < 0.9) {
// 0.9 has additional relief icons to be included into older maps
document.getElementById("defs-relief").innerHTML = reliefIcons;
}
@@ -917,6 +918,18 @@ function parseLoadedData(data) {
}
+ if (version < 1.22) {
+ // v 1.21 had incorrect style formatting
+ localStorage.removeItem("styleClean");
+ localStorage.removeItem("styleGloom");
+ localStorage.removeItem("styleAncient");
+ localStorage.removeItem("styleMonochrome");
+ addDefaulsStyles();
+
+ // v 1.22 changed state neighbors from Set object to array
+ BurgsAndStates.collectStatistics();
+ }
+
}()
changeMapSize();
diff --git a/modules/ui/3d.js b/modules/ui/3d.js
index a35a1bfb..8211da09 100644
--- a/modules/ui/3d.js
+++ b/modules/ui/3d.js
@@ -1,116 +1,308 @@
-"use strict";
-let threeD = {}; // master object for 3d scane and parameters
-let threeDscale = 50; // 3d scene scale
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+ typeof define === 'function' && define.amd ? define(factory) :
+ (global.ThreeD = factory());
+}(this, (function () {'use strict';
+
+// set default options
+const options = {scale: 50, lightness: .7, shadow: .5, sun: {x: 100, y: 600, z: 1000}, rotateMesh: 0, rotateGlobe: .5,
+ skyColor: "#9ecef5", waterColor: "#53679f", extendedWater: 0, resolution: 2};
+
+// set variables
+let Renderer, scene, camera, controls, animationFrame, material, texture,
+ geometry, mesh, ambientLight, spotLight, waterPlane, waterMaterial, waterMesh;
+
+// initiate 3d scene
+const create = async function(canvas, type = "viewMesh") {
+ options.isGlobe = type === "viewGlobe";
+ return options.isGlobe ? newGlobe(canvas) : newMesh(canvas);
+}
+
+// redraw 3d scene
+const redraw = function() {
+ scene.remove(mesh);
+ Renderer.setSize(Renderer.domElement.width, Renderer.domElement.height);
+ if (options.isGlobe) updateGlobeTexure();
+ else createMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
+ render();
+}
+
+// update 3d texture
+const update = function() {
+ if (options.isGlobe) updateGlobeTexure(); else update3dTexture();
+}
+
+// try to clean the memory as much as possible
+const stop = function() {
+ cancelAnimationFrame(animationFrame);
+ texture.dispose();
+ geometry.dispose();
+ material.dispose();
+ if (waterPlane) waterPlane.dispose();
+ if (waterMaterial) waterMaterial.dispose();
+
+ Renderer.renderLists.dispose(); // is it required?
+ Renderer.dispose();
+ scene.remove(mesh);
+ scene.remove(spotLight);
+ scene.remove(ambientLight);
+ scene.remove(waterMesh);
+
+ // not sure it's required
+ Renderer = undefined;
+ scene = undefined;
+ controls = undefined;
+ camera = undefined;
+ material = undefined;
+ texture = undefined;
+ geometry = undefined;
+ mesh = undefined;
+}
+
+const setScale = function(scale) {
+ options.scale = scale;
+ geometry.vertices.forEach((v, i) => v.z = getMeshHeight(i));
+ geometry.verticesNeedUpdate = true;
+ geometry.computeVertexNormals();
+ render();
+ geometry.verticesNeedUpdate = false;
+}
+
+const setLightness = function(intensity) {
+ options.lightness = intensity;
+ ambientLight.intensity = intensity;
+ render();
+}
+
+const setSun = function(x, y, z) {
+ options.sun = {x, y, z};
+ spotLight.position.set(x, y, z);
+ render();
+}
+
+const setRotation = function(speed) {
+ if (options.isGlobe) options.rotateGlobe = speed; else options.rotateMesh = speed;
+ controls.autoRotateSpeed = speed;
+ controls.autoRotate = Boolean(controls.autoRotateSpeed);
+ controls.autoRotate ? animate() : cancelAnimationFrame(animationFrame);
+}
+
+const toggleSky = function() {
+ if (options.extendedWater) {
+ scene.background = null;
+ scene.fog = null;
+ scene.remove(waterMesh);
+ } else extendWater(graphWidth, graphHeight);
+
+ options.extendedWater = !options.extendedWater;
+ redraw();
+}
+
+const setColors = function(sky, water) {
+ options.skyColor = sky;
+ scene.background = scene.fog.color = new THREE.Color(sky);
+ options.waterColor = water;
+ waterMaterial.color = new THREE.Color(water);
+ render();
+}
+
+const setResolution = function(resolution) {
+ options.resolution = resolution;
+ update();
+}
+
+// download screenshot
+const saveScreenshot = async function() {
+ const URL = Renderer.domElement.toDataURL("image/jpeg");
+ const link = document.createElement("a");
+ link.download = getFileName() + ".jpeg";
+ link.href = URL;
+ document.body.appendChild(link);
+ link.click();
+ tip(`Screenshot is saved. Open "Downloads" screen (CTRL + J) to check`, true, "success", 7000);
+ window.setTimeout(() => window.URL.revokeObjectURL(URL), 5000);
+}
// start 3d view and heightmap edit preview
-async function start3d(canvas) {
+async function newMesh(canvas) {
const loaded = await loadTHREE();
if (!loaded) {tip("Cannot load 3d library", false, "error", 4000); return false};
- threeD.scene = new THREE.Scene();
- //threeD.scene.background = new THREE.Color(0x53679f);
- threeD.camera = new THREE.PerspectiveCamera(70, canvas.width / canvas.height, 0.1, 2000);
- threeD.camera.position.x = 0;
- threeD.camera.position.z = 350;
- threeD.camera.position.y = 285;
- threeD.Renderer = new THREE.WebGLRenderer({canvas, antialias: true, preserveDrawingBuffer: true});
- threeD.controls = await OrbitControls(threeD.camera, threeD.Renderer.domElement);
- threeD.controls.minDistance = 10; threeD.controls.maxDistance = 1000;
- threeD.controls.maxPolarAngle = Math.PI/2;
- threeD.controls.keys = {};
+ scene = new THREE.Scene();
- threeD.Renderer.setSize(canvas.width, canvas.height);
- add3dMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
-
- const ambientLight = new THREE.AmbientLight(0xcccccc, .7);
- threeD.scene.add(ambientLight);
- const spotLight = new THREE.SpotLight(0xcccccc, .8, 2000, .7, 0, 0);
- spotLight.position.set(100, 600, 1000);
+ // light
+ ambientLight = new THREE.AmbientLight(0xcccccc, options.lightness);
+ scene.add(ambientLight);
+ spotLight = new THREE.SpotLight(0xcccccc, .8, 2000, .8, 0, 0);
+ spotLight.position.set(options.sun.x, options.sun.y, options.sun.z);
spotLight.castShadow = true;
- threeD.scene.add(spotLight);
- //threeD.scene.add(new THREE.SpotLightHelper(spotLight));
+ scene.add(spotLight);
+ //scene.add(new THREE.SpotLightHelper(spotLight));
+
+ // Rendered
+ Renderer = new THREE.WebGLRenderer({canvas, antialias: true, preserveDrawingBuffer: true});
+ Renderer.setSize(canvas.width, canvas.height);
+ Renderer.shadowMap.enabled = true;
+ if (options.extendedWater) extendWater(graphWidth, graphHeight);
+ createMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
+
+ // camera
+ camera = new THREE.PerspectiveCamera(70, canvas.width / canvas.height, .1, 2000);
+ camera.position.set(0, rn(svgWidth/3.5), 500);
+
+ // controls
+ controls = await OrbitControls(camera, canvas);
+ controls.enableKeys = false;
+ controls.minDistance = 10;
+ controls.maxDistance = 1000;
+ controls.maxPolarAngle = Math.PI/2;
+ controls.autoRotate = Boolean(options.rotateMesh);
+ controls.autoRotateSpeed = options.rotateMesh;
+ if (controls.autoRotate) animate();
+ controls.addEventListener("change", render);
- threeD.controls.addEventListener("change", render);
return true;
}
// create a mesh from pixel data
-async function add3dMesh(width, height, segmentsX, segmentsY) {
- const geometry = new THREE.PlaneGeometry(width, height, segmentsX-1, segmentsY-1);
-
- // generateTexture
- //threeD.material = new THREE.MeshBasicMaterial();
- //const texture = new THREE.CanvasTexture(generateTexture(grid.cells.h, grid.cellsX, grid.cellsY));
- //threeD.material.map = texture;
-
- const url = await getMapURL("mesh");
- threeD.material = new THREE.MeshLambertMaterial();
- const texture = new THREE.TextureLoader().load(url, render);
+async function createMesh(width, height, segmentsX, segmentsY) {
+ const url = await getMapURL("mesh", options.extendedWater ? "noWater" : null);
+ window.setTimeout(() => window.URL.revokeObjectURL(url), 3000);
+ if (texture) texture.dispose();
+ texture = new THREE.TextureLoader().load(url, render);
texture.needsUpdate = true;
- threeD.material.map = texture;
+ if (material) material.dispose();
+ material = new THREE.MeshLambertMaterial();
+ material.map = texture;
+ material.transparent = true;
+
+ if (geometry) geometry.dispose();
+ geometry = new THREE.PlaneGeometry(width, height, segmentsX-1, segmentsY-1);
geometry.vertices.forEach((v, i) => v.z = getMeshHeight(i));
- geometry.computeVertexNormals(); // added
- threeD.Renderer.shadowMap.enabled = true; // added
- threeD.mesh = new THREE.Mesh(geometry, threeD.material);
- threeD.mesh.rotation.x = -Math.PI / 2;
- threeD.mesh.castShadow = true;
- threeD.mesh.receiveShadow = true;
- threeD.scene.add(threeD.mesh);
+ geometry.computeVertexNormals();
+
+ if (mesh) scene.remove(mesh);
+ mesh = new THREE.Mesh(geometry, material);
+ mesh.rotation.x = -Math.PI/2;
+ mesh.castShadow = true;
+ mesh.receiveShadow = true;
+ scene.add(mesh);
}
function getMeshHeight(i) {
const h = grid.cells.h[i];
- return h < 20 ? 0 : (h - 18) / 82 * threeDscale;
+ return h < 20 ? 0 : (h - 18) / 82 * options.scale;
}
-function generateTexture(data, width, height) {
- let context, image, imageData;
- const vector3 = new THREE.Vector3(0, 0, 0);
- const sun = new THREE.Vector3(1, 1, 1);
- sun.normalize();
+function extendWater(width, height) {
+ scene.background = new THREE.Color(options.skyColor);
- const canvas = document.createElement('canvas');
- canvas.width = width;
- canvas.height = height;
- context = canvas.getContext('2d');
- context.fillStyle = '#000';
- context.fillRect(0, 0, width, height);
+ waterPlane = new THREE.PlaneGeometry(width * 10, height * 10, 1);
+ waterMaterial = new THREE.MeshBasicMaterial({color: options.waterColor});
+ scene.fog = new THREE.Fog(scene.background, 500, 3000);
- image = context.getImageData(0, 0, canvas.width, canvas.height);
- imageData = image.data;
+ waterMesh = new THREE.Mesh(waterPlane, waterMaterial);
+ waterMesh.rotation.x = -Math.PI / 2;
+ waterMesh.position.y -= 3;
+ scene.add(waterMesh);
+}
- for (let i = 0, j = 0; i < imageData.length; i += 4, j ++) {
- vector3.x = data[j - 2] - data[j + 2];
- vector3.y = 2;
- vector3.z = data[j - width * 2] - data[j + width * 2];
- vector3.normalize();
+async function update3dTexture() {
+ if (texture) texture.dispose();
+ const url = await getMapURL("mesh");
+ window.setTimeout(() => window.URL.revokeObjectURL(url), 3000);
+ texture = new THREE.TextureLoader().load(url, render);
+ material.map = texture;
+}
- const shade = vector3.dot(sun);
- // initial: r 96 + shade * 128, g 32 + shade * 96, b shade * 96;
- const clr = (shade * 255) * (.5 + data[j] * .007); // new: black and white
- imageData[i] = imageData[i + 1] = imageData[i + 2] = clr;
+async function newGlobe(canvas) {
+ const loaded = await loadTHREE();
+ if (!loaded) {tip("Cannot load 3d library", false, "error", 4000); return false};
+
+ // scene
+ scene = new THREE.Scene();
+ scene.background = new THREE.TextureLoader().load("https://i0.wp.com/azgaar.files.wordpress.com/2019/10/stars-1.png", render);
+
+ // Renderer
+ Renderer = new THREE.WebGLRenderer({canvas, antialias: true, preserveDrawingBuffer: true});
+ Renderer.setSize(canvas.width, canvas.height);
+
+ // material
+ if (material) material.dispose();
+ material = new THREE.MeshBasicMaterial();
+ updateGlobeTexure(true);
+
+ // camera
+ camera = new THREE.PerspectiveCamera(45, canvas.width / canvas.height, 0.1, 1000).translateZ(5);
+
+ // controls
+ controls = await OrbitControls(camera, Renderer.domElement);
+ controls.enableKeys = false;
+ controls.minDistance = 1.8;
+ controls.maxDistance = 10;
+ controls.autoRotate = Boolean(options.rotateGlobe);
+ controls.autoRotateSpeed = options.rotateGlobe;
+ controls.addEventListener("change", render);
+
+ return true;
+}
+
+async function updateGlobeTexure(addMesh) {
+ const world = mapCoordinates.latT > 179; // define if map covers whole world
+
+ // texture size
+ const scale = options.resolution;
+ const height = 512 * scale;
+ const width = 1024 * scale;
+
+ // calculate map size and offset position
+ const mapHeight = rn(mapCoordinates.latT / 180 * height);
+ const mapWidth = world ? mapHeight * 2 : rn(graphWidth / graphHeight * mapHeight);
+ const dy = world ? 0 : (90 - mapCoordinates.latN) / 180 * height;
+ const dx = mapWidth / 4;
+
+ // draw map on canvas
+ const ctx = document.createElement("canvas").getContext("2d");
+ ctx.canvas.width = width;
+ ctx.canvas.height = height;
+
+ // add cloud texture if map does not cover all the globe
+ if (!world) {
+ const img = new Image;
+ img.onload = function() {ctx.drawImage(img, 0, 0, width, height)};
+ img.src = "data:image/png;base64,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";
}
- context.putImageData(image, 0, 0);
- const canvasScaled = document.createElement('canvas');
- canvasScaled.width = width * 4;
- canvasScaled.height = height * 4;
- context = canvasScaled.getContext('2d');
- context.scale(4, 4);
- context.drawImage(canvas, 0, 0);
+ // fill canvas segment with map texture
+ const img2 = new Image;
+ img2.onload = function() {
+ ctx.drawImage(img2, dx, dy, mapWidth, mapHeight);
+ if (texture) texture.dispose();
+ texture = new THREE.CanvasTexture(ctx.canvas, render);
+ material.map = texture;
+ if (addMesh) addGlobe3dMesh();
+ };
+ img2.src = await getMapURL("mesh", "globe");;
+}
- image = context.getImageData(0, 0, canvasScaled.width, canvasScaled.height);
- imageData = image.data;
+function addGlobe3dMesh() {
+ geometry = new THREE.SphereBufferGeometry(1, 64, 64);
+ mesh = new THREE.Mesh(geometry, material);
+ scene.add(mesh);
+ if (controls.autoRotate) animate(); else render();
+}
- for (let i = 0; i < imageData.length; i += 4) {
- const v = ~~(Math.random() * 5);
- imageData[i] += v;
- imageData[i + 1] += v;
- imageData[i + 2] += v;
- }
- context.putImageData(image, 0, 0);
- return canvasScaled;
+// render 3d scene and camera, do only on controls change
+function render() {
+ Renderer.render(scene,camera);
+}
+
+// animate 3d scene and camera
+function animate() {
+ animationFrame = requestAnimationFrame(animate);
+ controls.update();
+ Renderer.render(scene, camera);
}
function loadTHREE() {
@@ -137,90 +329,6 @@ function OrbitControls(camera, domElement) {
});
}
-function update3dPreview(canvas) {
- threeD.scene.remove(threeD.mesh);
- threeD.Renderer.setSize(canvas.width, canvas.height);
- if (canvas.dataset.type === "viewGlobe") addGlobe3dMesh();
- else add3dMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
- render();
-}
+return {create, redraw, update, stop, options, setScale, setLightness, setSun, setRotation, toggleSky, setResolution, setColors, saveScreenshot};
-async function update3d() {
- const url = await getMapURL("mesh");
- threeD.material.map = new THREE.TextureLoader().load(url, render);
-}
-
-function stop3d() {
- if (!threeD.controls || !threeD.Renderer) return;
- threeD.controls.dispose();
- threeD.Renderer.dispose()
- cancelAnimationFrame(threeD.animationFrame);
- threeD = {};
-}
-
-async function startGlobe(canvas) {
- const loaded = await loadTHREE();
- if (!loaded) {tip("Cannot load 3d library", false, "error", 4000); return false};
-
- threeD.scene = new THREE.Scene();
- threeD.scene.background = new THREE.TextureLoader().load("https://i0.wp.com/azgaar.files.wordpress.com/2019/10/stars.png", render);
- threeD.Renderer = new THREE.WebGLRenderer({canvas, antialias: true, preserveDrawingBuffer: true});
- threeD.Renderer.setSize(canvas.width, canvas.height);
-
- threeD.camera = new THREE.PerspectiveCamera(45, canvas.width / canvas.height, 0.1, 1000).translateZ(5);
- threeD.controls = await OrbitControls(threeD.camera, threeD.Renderer.domElement);
- threeD.controls.minDistance = 1.8; threeD.controls.maxDistance = 10;
- threeD.controls.autoRotate = true;
- threeD.controls.keys = {};
-
- const ambientLight = new THREE.AmbientLight(0xcccccc, .9);
- threeD.scene.add(ambientLight);
- const spotLight = new THREE.SpotLight(0xcccccc, .6, 200, .7, .1, 0);
- spotLight.position.set(700, 300, 200);
- spotLight.castShadow = false;
- threeD.scene.add(spotLight);
- //threeD.scene.add(new THREE.SpotLightHelper(spotLight));
-
- addGlobe3dMesh();
- threeD.controls.addEventListener("change", render);
- threeD.animationFrame = requestAnimationFrame(animate);
- return true;
-}
-
-// create globe mesh just from svg
-async function addGlobe3dMesh() {
- threeD.material = new THREE.MeshLambertMaterial();
- const url = await getMapURL("mesh", "globe");
- threeD.material.map = new THREE.TextureLoader().load(url, render);
- threeD.mesh = new THREE.Mesh(new THREE.SphereBufferGeometry(1, 64, 64), threeD.material);
- threeD.scene.add(threeD.mesh);
-}
-
-// render 3d scene and camera, do only on controls change
-function render() {
- threeD.Renderer.render(threeD.scene, threeD.camera);
-}
-
-// animate 3d scene and camera
-function animate() {
- threeD.animationFrame = requestAnimationFrame(animate);
- threeD.controls.update();
- threeD.Renderer.render(threeD.scene, threeD.camera);
-}
-
-function toggleRotation() {
- const rotate = threeD.controls.autoRotate = !threeD.controls.autoRotate;
- rotate ? requestAnimationFrame(animate) : cancelAnimationFrame(threeD.animationFrame);
-}
-
-// download screenshot
-async function saveScreenshot() {
- const URL = threeD.Renderer.domElement.toDataURL("image/jpeg");
- const link = document.createElement("a");
- link.download = getFileName() + ".jpeg";
- link.href = URL;
- document.body.appendChild(link);
- link.click();
- tip(`Screenshot is saved. Open "Downloads" screen (CTRL + J) to check`, true, "success", 7000);
- window.setTimeout(() => window.URL.revokeObjectURL(URL), 5000);
-}
\ No newline at end of file
+})));
\ No newline at end of file
diff --git a/modules/ui/general.js b/modules/ui/general.js
index d4baf309..b5c34aba 100644
--- a/modules/ui/general.js
+++ b/modules/ui/general.js
@@ -284,7 +284,7 @@ function showInfo() {
// prevent default browser behavior for FMG-used hotkeys
document.addEventListener("keydown", event => {
- if (event.altKey && event.keyCode !== 18) event.preventDefault(); // disallowalt key combinations
+ if (event.altKey && event.keyCode !== 18) event.preventDefault(); // disallow alt key combinations
if ([112, 113, 117, 120, 9].includes(event.keyCode)) event.preventDefault(); // F1, F2, F6, F9, Tab
});
@@ -307,18 +307,8 @@ document.addEventListener("keyup", event => {
else if (key === 9) toggleOptions(event); // Tab to toggle options
else if (key === 27) {closeDialogs(); hideOptions();} // Escape to close all dialogs
else if (key === 46) removeElementOnKey(); // "Delete" to remove the selected element
+ else if (key === 79 && canvas3d) toggle3dOptions(); // "O" to toggle 3d options
- else if (key === 83 && canvas3d) saveScreenshot(); // "S" to save a screenshot
- else if (key === 82 && canvas3d) toggleRotation(); // "R" to toggle 3d rotation
- else if (key === 85 && canvas3d && customization !== 1) update3d(); // "U" to update 3d view
-
- else if (ctrl && key === 80) savePNG(); // Ctrl + "P" to save as PNG
- else if (ctrl && key === 71) saveJPEG(); // Ctrl + "J" to save as JPEG
- else if (ctrl && key === 83) saveSVG(); // Ctrl + "S" to save as SVG
- else if (ctrl && key === 77) saveMap(); // Ctrl + "M" to save MAP file
- else if (ctrl && key === 71) saveGeoJSON(); // Ctrl + "G" to save as GeoJSON
- else if (ctrl && key === 85) mapToLoad.click(); // Ctrl + "U" to load MAP from URL
- else if (ctrl && key === 76) mapToLoad.click(); // Ctrl + "L" to load MAP from local file
else if (ctrl && key === 81) toggleSaveReminder(); // Ctrl + "Q" to toggle save reminder
else if (undo.offsetParent && ctrl && key === 90) undo.click(); // Ctrl + "Z" to undo
else if (redo.offsetParent && ctrl && key === 89) redo.click(); // Ctrl + "Y" to redo
diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js
index 8e2f1c5c..73d163a6 100644
--- a/modules/ui/heightmap-editor.js
+++ b/modules/ui/heightmap-editor.js
@@ -413,7 +413,7 @@ function editHeightmap() {
if (!noStat) {
updateStatistics();
if (document.getElementById("preview")) drawHeightmapPreview(); // update heightmap preview if opened
- if (document.getElementById("canvas3d")) update3dPreview(canvas3d); // update 3d heightmap preview if opened
+ if (document.getElementById("canvas3d")) ThreeD.redraw(); // update 3d heightmap preview if opened
}
}
@@ -428,7 +428,7 @@ function editHeightmap() {
updateStatistics();
if (document.getElementById("preview")) drawHeightmapPreview(); // update heightmap preview if opened
- if (document.getElementById("canvas3d")) update3dPreview(canvas3d); // update 3d heightmap preview if opened
+ if (document.getElementById("canvas3d")) ThreeD.redraw(); // update 3d heightmap preview if opened
}
// restart edits from 1st step
@@ -869,7 +869,7 @@ function editHeightmap() {
updateStatistics();
mockHeightmap();
if (document.getElementById("preview")) drawHeightmapPreview(); // update heightmap preview if opened
- if (document.getElementById("canvas3d")) update3dPreview(canvas3d); // update 3d heightmap preview if opened
+ if (document.getElementById("canvas3d")) ThreeD.redraw(); // update 3d heightmap preview if opened
}
function downloadTemplate() {
@@ -1203,13 +1203,15 @@ function editHeightmap() {
canvas.style.display = "block";
canvas.width = parseFloat(preview3d.style.width) || graphWidth / 3;
canvas.height = canvas.width / (graphWidth / graphHeight);
- const started = await start3d(canvas);
+ const started = ThreeD.create(canvas);
if (!started) return;
+
document.getElementById("preview3d").appendChild(canvas);
canvas.onmouseenter = () => {
+canvas.dataset.hovered > 2 ? tip("") : tip("Left mouse to change angle, middle mouse or mousewheel to zoom, right mouse to pan. R to toggle rotation");
canvas.dataset.hovered = (+canvas.dataset.hovered|0) + 1;
};
+ show3dOptions();
$("#preview3d").dialog({
title: "3D Preview", resizable: true,
@@ -1220,11 +1222,11 @@ function editHeightmap() {
function resize3d() {
canvas.width = parseFloat(preview3d.style.width);
canvas.height = parseFloat(preview3d.style.height) - 2;
- update3dPreview(canvas);
+ ThreeD.redraw();
}
function close3dPreview() {
- stop3d();
+ ThreeD.stop();
canvas.remove();
}
}
diff --git a/modules/ui/layers.js b/modules/ui/layers.js
index 0b44f14c..27201082 100644
--- a/modules/ui/layers.js
+++ b/modules/ui/layers.js
@@ -71,7 +71,7 @@ function changePreset(preset) {
const isDefault = getDefaultPresets()[preset];
removePresetButton.style.display = isDefault ? "none" : "inline-block";
savePresetButton.style.display = "none";
- if (document.getElementById("canvas3d")) setTimeout(update3d, 300);
+ if (document.getElementById("canvas3d")) setTimeout(ThreeD.update(), 400);
}
function savePreset() {
@@ -115,11 +115,6 @@ function getCurrentPreset() {
savePresetButton.style.display = "inline-block";
}
-// update 3d view is layer is toggled
-document.getElementById("mapLayers").addEventListener("click", () => {
- if (document.getElementById("canvas3d")) setTimeout(update3d, 300);
-});
-
function toggleHeight(event) {
if (!terrs.selectAll("*").size()) {
turnButtonOn("toggleHeight");
diff --git a/modules/ui/options.js b/modules/ui/options.js
index aeb8f40e..04364680 100644
--- a/modules/ui/options.js
+++ b/modules/ui/options.js
@@ -298,7 +298,7 @@ function applyStoredOptions() {
if (localStorage.getItem("winds")) winds = localStorage.getItem("winds").split(",").map(w => +w);
- changeDialogsTransparency(localStorage.getItem("transparency") || 15);
+ changeDialogsTransparency(localStorage.getItem("transparency") || 5);
if (localStorage.getItem("tooltipSize")) changeTooltipSize(localStorage.getItem("tooltipSize"));
if (localStorage.getItem("regions")) changeStatesNumber(localStorage.getItem("regions"));
@@ -444,8 +444,9 @@ function changeViewMode(event) {
function enterStandardView() {
if (!document.getElementById("canvas3d")) return;
+ ThreeD.stop();
document.getElementById("canvas3d").remove();
- stop3d();
+ if (options3dUpdate.offsetParent) $("#options3d").dialog("close");
}
async function enter3dView(type) {
@@ -457,13 +458,101 @@ async function enter3dView(type) {
canvas.style.position = "absolute";
canvas.style.display = "none";
canvas.dataset.type = type;
- const started = type === "viewGlobe" ? await startGlobe(canvas) : await start3d(canvas);
+ const started = await ThreeD.create(canvas, type);
if (!started) return;
canvas.style.display = "block";
document.body.insertBefore(canvas, optionsContainer);
canvas.onmouseenter = () => {
- const help = "Left mouse to change angle, middle mouse / mousewheel to zoom, right mouse to pan.\r\n
R to toggle rotation.
U to update.
S to get a screenshot";
+ const help = "Left mouse to change angle, middle mouse / mousewheel to zoom, right mouse to pan.
O to toggle options";
+canvas.dataset.hovered > 2 ? tip("") : tip(help);
canvas.dataset.hovered = (+canvas.dataset.hovered|0) + 1;
};
+ toggle3dOptions();
+}
+
+function toggle3dOptions() {
+ if (options3dUpdate.offsetParent) {$("#options3d").dialog("close"); return;}
+ $("#options3d").dialog({
+ title: "3D mode settings", resizable: false, width: fitContent(),
+ position: {my: "right top", at: "right-40 top+10", of: "svg", collision: "fit"}
+ });
+
+ updateValues();
+
+ if (modules.options3d) return;
+ modules.options3d = true;
+
+ document.getElementById("options3dUpdate").addEventListener("click", ThreeD.update);
+ document.getElementById("options3dSave").addEventListener("click", ThreeD.saveScreenshot);
+
+ document.getElementById("options3dScaleRange").addEventListener("input", changeHeightScale);
+ document.getElementById("options3dScaleNumber").addEventListener("change", changeHeightScale);
+ document.getElementById("options3dLightnessRange").addEventListener("input", changeLightness);
+ document.getElementById("options3dLightnessNumber").addEventListener("change", changeLightness);
+ document.getElementById("options3dSunX").addEventListener("change", changeSunPosition);
+ document.getElementById("options3dSunY").addEventListener("change", changeSunPosition);
+ document.getElementById("options3dSunZ").addEventListener("change", changeSunPosition);
+ document.getElementById("options3dMeshRotationRange").addEventListener("input", changeRotation);
+ document.getElementById("options3dMeshRotationNumber").addEventListener("change", changeRotation);
+ document.getElementById("options3dGlobeRotationRange").addEventListener("input", changeRotation);
+ document.getElementById("options3dGlobeRotationNumber").addEventListener("change", changeRotation);
+ document.getElementById("options3dMeshSkyMode").addEventListener("change", toggleSkyMode);
+ document.getElementById("options3dMeshSky").addEventListener("input", changeColors);
+ document.getElementById("options3dMeshWater").addEventListener("input", changeColors);
+ document.getElementById("options3dGlobeResolution").addEventListener("change", changeResolution);
+
+ function updateValues() {
+ const globe = document.getElementById("canvas3d").dataset.type === "viewGlobe";
+ options3dMesh.style.display = globe ? "none" : "block";
+ options3dGlobe.style.display = globe ? "block" : "none";
+ options3dScaleRange.value = options3dScaleNumber.value = ThreeD.options.scale;
+ options3dLightnessRange.value = options3dLightnessNumber.value = ThreeD.options.lightness * 100;
+ options3dSunX.value = ThreeD.options.sun.x;
+ options3dSunY.value = ThreeD.options.sun.y;
+ options3dSunZ.value = ThreeD.options.sun.z;
+ options3dMeshRotationRange.value = options3dMeshRotationNumber.value = ThreeD.options.rotateMesh;
+ options3dGlobeRotationRange.value = options3dGlobeRotationNumber.value = ThreeD.options.rotateGlobe;
+ options3dMeshSkyMode.value = ThreeD.options.extendedWater;
+ options3dColorSection.style.display = ThreeD.options.extendedWater ? "block" : "none";
+ options3dMeshSky.value = ThreeD.options.skyColor;
+ options3dMeshWater.value = ThreeD.options.waterColor;
+ options3dGlobeResolution.value = ThreeD.options.resolution;
+ }
+
+ function changeHeightScale() {
+ options3dScaleRange.value = options3dScaleNumber.value = this.value;
+ ThreeD.setScale(+this.value);
+ }
+
+ function changeLightness() {
+ options3dLightnessRange.value = options3dLightnessNumber.value = this.value;
+ ThreeD.setLightness(this.value / 100);
+ }
+
+ function changeSunPosition() {
+ const x = +options3dSunX.value;
+ const y = +options3dSunY.value;
+ const z = +options3dSunZ.value;
+ ThreeD.setSun(x, y, z);
+ }
+
+ function changeRotation() {
+ (this.nextElementSibling || this.previousElementSibling).value = this.value;
+ const speed = +this.value;
+ ThreeD.setRotation(speed);
+ }
+
+ function toggleSkyMode() {
+ const hide = ThreeD.options.extendedWater;
+ options3dColorSection.style.display = hide ? "none" : "block";
+ ThreeD.toggleSky();
+ }
+
+ function changeColors() {
+ ThreeD.setColors(options3dMeshSky.value, options3dMeshWater.value);
+ }
+
+ function changeResolution() {
+ ThreeD.setResolution(this.value);
+ }
}
\ No newline at end of file
diff --git a/modules/ui/style.js b/modules/ui/style.js
index 9d61c64d..a924fb1c 100644
--- a/modules/ui/style.js
+++ b/modules/ui/style.js
@@ -671,22 +671,22 @@ function applyStyleOnLoad() {
function addDefaulsStyles() {
if (!localStorage.getItem("styleClean")) {
- const clean = `{"#map":{"background-color":"#000000","filter":null,"data-filter":null},"#biomes":{"opacity":0.5,"filter":"url(#blur7)","mask":"url(#land)"},"#stateBorders":{"opacity":0.8,"stroke":"#414141","stroke-width":0.7,"stroke-dasharray":0,"stroke-linecap":"butt","filter":""},"#provinceBorders":{"opacity":0.8,"stroke":"#414141","stroke-width":0.45,"stroke-dasharray":1,"stroke-linecap":"butt","filter":null},"#cells":{"opacity":null,"stroke":"#808080","stroke-width":0.09,"filter":null,"mask":"url(#land)"},"#gridOverlay":{"opacity":0.8,"size":10,"type":"pointyHex","stroke":"#808080","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"transform":null,"filter":null,"mask":null},"#coordinates":{"opacity":1,"data-size":12,"font-size":12,"stroke":"#414141","stroke-width":0.45,"stroke-dasharray":3,"stroke-linecap":null,"filter":null,"mask":null},"#compass":{"opacity":0.8,"transform":null,"filter":null,"mask":"url(#water)","shape-rendering":"optimizespeed"},"#rose":{"transform":null},"#relig":{"opacity":0.7,"stroke":"#404040","stroke-width":0.7,"filter":null},"#cults":{"opacity":0.6,"stroke":"#777777","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#landmass":{"opacity":1,"fill":"#eeedeb","filter":null},"#markers":{"opacity":null,"rescale":null,"filter":"url(#dropShadow01)"},"#prec":{"opacity":null,"stroke":"#000000","stroke-width":0,"fill":"#0080ff","filter":null},"#population":{"opacity":null,"stroke-width":2.58,"stroke-dasharray":0,"stroke-linecap":"butt","filter":"url(#blur3)"},"#rural":{"stroke":"#ff0000"},"#urban":{"stroke":"#800000"},"#freshwater":{"opacity":0.5,"fill":"#aadaff","stroke":"#5f799d","stroke-width":0,"filter":null},"#salt":{"opacity":0.5,"fill":"#409b8a","stroke":"#388985","stroke-width":0.7,"filter":null},"#sinkhole":{"opacity":1,"fill":"#5bc9fd","stroke":"#53a3b0","stroke-width":0.7,"filter":null},"#frozen":{"opacity":0.95,"fill":"#cdd4e7","stroke":"#cfe0eb","stroke-width":0,"filter":null},"#lava":{"opacity":0.7,"fill":"#90270d","stroke":"#f93e0c","stroke-width":2,"filter":"url(#crumpled)"},"#sea_island":{"opacity":0.6,"stroke":"#595959","stroke-width":0.4,"filter":"","auto-filter":0},"#lake_island":{"opacity":0,"stroke":"#7c8eaf","stroke-width":0,"filter":null},"#terrain":{"opacity":null,"set":"simple","size":1,"density":.4,filter":null,"mask":null},"#rivers":{"opacity":null,"filter":null,"fill":"#aadaff"},"#ruler":{"opacity":null,"filter":null},"#roads":{"opacity":0.9,"stroke":"#f6d068","stroke-width":0.7,"stroke-dasharray":0,"stroke-linecap":"inherit","filter":null,"mask":null},"#trails":{"opacity":1,"stroke":"#ffffff","stroke-width":0.25,"stroke-dasharray":"","stroke-linecap":"round","filter":null,"mask":null},"#searoutes":{"opacity":0.8,"stroke":"#4f82c6","stroke-width":0.45,"stroke-dasharray":2,"stroke-linecap":"butt","filter":null,"mask":"url(#water)"},"#regions":{"opacity":0.4,"filter":null},"#statesHalo":{"opacity":0,"data-width":null,"stroke-width":0},"#provs":{"opacity":0.6,"filter":null},"#temperature":{"opacity":null,"font-size":"8px","fill":"#000000","fill-opacity":0.3,"stroke":null,"stroke-width":1.8,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#texture":{"opacity":null,"filter":null,"mask":"url(#land)"},"#textureImage":{},"#zones":{"opacity":0.7,"stroke":"#ff6262","stroke-width":0,"stroke-dasharray":"","stroke-linecap":"butt","filter":null,"mask":null},"#ocean":{"opacity":null},"#oceanLayers":{"filter":"","layers":"none"},"#oceanBase":{"fill":"#aadaff"},"#oceanPattern":{"opacity":null},"#oceanicPattern":{"filter":"url(#emptyImage)"},"#terrs":{"opacity":0.5,"scheme":"bright","terracing":0,"skip":5,"relax":0,"curve":0,"filter":"","mask":"url(#land)"},"#legend":{"data-size":12.74,"font-size":12.74,"data-font":"Arial","font-family":"Arial","stroke":"#909090","stroke-width":1.13,"stroke-dasharray":0,"stroke-linecap":"round","data-x":98.39,"data-y":12.67,"data-columns":null},"#legendBox":{},"#burgLabels > #cities":{"opacity":1,"fill":"#414141","data-size":7,"font-size":7,"data-font":"Arial","font-family":"Arial"},"#burgIcons > #cities":{"opacity":1,"fill":"#ffffff","fill-opacity":0.7,"size":1,"stroke":"#3e3e4b","stroke-width":0.24,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #cities":{"opacity":1,"fill":"#ffffff","size":2,"stroke":"#303030","stroke-width":1.7},"#burgLabels > #towns":{"opacity":1,"fill":"#414141","data-size":3,"font-size":3,"data-font":"Arial","font-family":"Arial"},"#burgIcons > #towns":{"opacity":1,"fill":"#ffffff","fill-opacity":0.7,"size":0.5,"stroke":"#3e3e4b","stroke-width":0.12,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #towns":{"opacity":1,"fill":"#ffffff","size":1,"stroke":"#3e3e4b","stroke-width":1.06},"#labels > #states":{"opacity":1,"fill":"#292929","stroke":"#303030","stroke-width":0,"data-size":10,"font-size":10,"data-font":"Arial","font-family":"Arial","filter":null},"#labels > #addedLabels":{"opacity":1,"fill":"#414141","stroke":"#3a3a3a","stroke-width":0,"data-size":18,"font-size":18,"data-font":"Arial","font-family":"Arial","filter":null},"#fogging-cont":{"opacity":null,"fill":null,"stroke-width":null}}`;
+ const clean = `{"#map":{"background-color":"#000000","filter":null,"data-filter":null},"#biomes":{"opacity":0.5,"filter":"url(#blur7)","mask":"url(#land)"},"#stateBorders":{"opacity":0.8,"stroke":"#414141","stroke-width":0.7,"stroke-dasharray":0,"stroke-linecap":"butt","filter":""},"#provinceBorders":{"opacity":0.8,"stroke":"#414141","stroke-width":0.45,"stroke-dasharray":1,"stroke-linecap":"butt","filter":null},"#cells":{"opacity":null,"stroke":"#808080","stroke-width":0.09,"filter":null,"mask":"url(#land)"},"#gridOverlay":{"opacity":0.8,"size":10,"type":"pointyHex","stroke":"#808080","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"transform":null,"filter":null,"mask":null},"#coordinates":{"opacity":1,"data-size":12,"font-size":12,"stroke":"#414141","stroke-width":0.45,"stroke-dasharray":3,"stroke-linecap":null,"filter":null,"mask":null},"#compass":{"opacity":0.8,"transform":null,"filter":null,"mask":"url(#water)","shape-rendering":"optimizespeed"},"#rose":{"transform":null},"#relig":{"opacity":0.7,"stroke":"#404040","stroke-width":0.7,"filter":null},"#cults":{"opacity":0.6,"stroke":"#777777","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#landmass":{"opacity":1,"fill":"#eeedeb","filter":null},"#markers":{"opacity":null,"rescale":null,"filter":"url(#dropShadow01)"},"#prec":{"opacity":null,"stroke":"#000000","stroke-width":0,"fill":"#0080ff","filter":null},"#population":{"opacity":null,"stroke-width":2.58,"stroke-dasharray":0,"stroke-linecap":"butt","filter":"url(#blur3)"},"#rural":{"stroke":"#ff0000"},"#urban":{"stroke":"#800000"},"#freshwater":{"opacity":0.5,"fill":"#aadaff","stroke":"#5f799d","stroke-width":0,"filter":null},"#salt":{"opacity":0.5,"fill":"#409b8a","stroke":"#388985","stroke-width":0.7,"filter":null},"#sinkhole":{"opacity":1,"fill":"#5bc9fd","stroke":"#53a3b0","stroke-width":0.7,"filter":null},"#frozen":{"opacity":0.95,"fill":"#cdd4e7","stroke":"#cfe0eb","stroke-width":0,"filter":null},"#lava":{"opacity":0.7,"fill":"#90270d","stroke":"#f93e0c","stroke-width":2,"filter":"url(#crumpled)"},"#sea_island":{"opacity":0.6,"stroke":"#595959","stroke-width":0.4,"filter":"","auto-filter":0},"#lake_island":{"opacity":0,"stroke":"#7c8eaf","stroke-width":0,"filter":null},"#terrain":{"opacity":null,"set":"simple","size":1,"density":0.4,"filter":null,"mask":null},"#rivers":{"opacity":null,"filter":null,"fill":"#aadaff"},"#ruler":{"opacity":null,"filter":null},"#roads":{"opacity":0.9,"stroke":"#f6d068","stroke-width":0.7,"stroke-dasharray":0,"stroke-linecap":"inherit","filter":null,"mask":null},"#trails":{"opacity":1,"stroke":"#ffffff","stroke-width":0.25,"stroke-dasharray":"","stroke-linecap":"round","filter":null,"mask":null},"#searoutes":{"opacity":0.8,"stroke":"#4f82c6","stroke-width":0.45,"stroke-dasharray":2,"stroke-linecap":"butt","filter":null,"mask":"url(#water)"},"#regions":{"opacity":0.4,"filter":null},"#statesHalo":{"opacity":0,"data-width":null,"stroke-width":0},"#provs":{"opacity":0.6,"filter":null},"#temperature":{"opacity":null,"font-size":"8px","fill":"#000000","fill-opacity":0.3,"stroke":null,"stroke-width":1.8,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#texture":{"opacity":null,"filter":null,"mask":"url(#land)"},"#textureImage":{},"#zones":{"opacity":0.7,"stroke":"#ff6262","stroke-width":0,"stroke-dasharray":"","stroke-linecap":"butt","filter":null,"mask":null},"#ocean":{"opacity":null},"#oceanLayers":{"filter":"","layers":"none"},"#oceanBase":{"fill":"#aadaff"},"#oceanPattern":{"opacity":null},"#oceanicPattern":{"filter":"url(#emptyImage)"},"#terrs":{"opacity":0.5,"scheme":"bright","terracing":0,"skip":5,"relax":0,"curve":0,"filter":"","mask":"url(#land)"},"#legend":{"data-size":12.74,"font-size":12.74,"data-font":"Arial","font-family":"Arial","stroke":"#909090","stroke-width":1.13,"stroke-dasharray":0,"stroke-linecap":"round","data-x":98.39,"data-y":12.67,"data-columns":null},"#legendBox":{},"#burgLabels > #cities":{"opacity":1,"fill":"#414141","data-size":7,"font-size":7,"data-font":"Arial","font-family":"Arial"},"#burgIcons > #cities":{"opacity":1,"fill":"#ffffff","fill-opacity":0.7,"size":1,"stroke":"#3e3e4b","stroke-width":0.24,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #cities":{"opacity":1,"fill":"#ffffff","size":2,"stroke":"#303030","stroke-width":1.7},"#burgLabels > #towns":{"opacity":1,"fill":"#414141","data-size":3,"font-size":3,"data-font":"Arial","font-family":"Arial"},"#burgIcons > #towns":{"opacity":1,"fill":"#ffffff","fill-opacity":0.7,"size":0.5,"stroke":"#3e3e4b","stroke-width":0.12,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #towns":{"opacity":1,"fill":"#ffffff","size":1,"stroke":"#3e3e4b","stroke-width":1.06},"#labels > #states":{"opacity":1,"fill":"#292929","stroke":"#303030","stroke-width":0,"data-size":10,"font-size":10,"data-font":"Arial","font-family":"Arial","filter":null},"#labels > #addedLabels":{"opacity":1,"fill":"#414141","stroke":"#3a3a3a","stroke-width":0,"data-size":18,"font-size":18,"data-font":"Arial","font-family":"Arial","filter":null},"#fogging-cont":{"opacity":null,"fill":null,"stroke-width":null}}`;
localStorage.setItem("styleClean", clean);
}
if (!localStorage.getItem("styleGloom")) {
- const gloom = `{"#map":{"background-color":"#000000","filter":null,"data-filter":null},"#biomes":{"opacity":null,"filter":"url(#blur5)","mask":"url(#land)"},"#stateBorders":{"opacity":1,"stroke":"#56566d","stroke-width":1,"stroke-dasharray":2,"stroke-linecap":"butt","filter":""},"#provinceBorders":{"opacity":1,"stroke":"#56566d","stroke-width":0.3,"stroke-dasharray":".7 1","stroke-linecap":"butt","filter":null},"#cells":{"opacity":null,"stroke":"#808080","stroke-width":0.1,"filter":null,"mask":null},"#gridOverlay":{"opacity":0.8,"size":10,"type":"pointyHex","stroke":"#808080","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"transform":null,"filter":null,"mask":null},"#coordinates":{"opacity":1,"data-size":14,"font-size":14,"stroke":"#4a4a4a","stroke-width":1,"stroke-dasharray":6,"stroke-linecap":null,"filter":"","mask":""},"#compass":{"opacity":0.6,"transform":null,"filter":null,"mask":"url(#water)","shape-rendering":"optimizespeed"},"#rose":{"transform":"translate(100 100) scale(0.3)"},"#relig":{"opacity":0.7,"stroke":"#404040","stroke-width":1,"filter":null},"#cults":{"opacity":0.7,"stroke":"#777777","stroke-width":1.5,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#landmass":{"opacity":1,"fill":"#e0e0e0","filter":null},"#markers":{"opacity":0.8,"rescale":1,"filter":"url(#dropShadow05)"},"#prec":{"opacity":null,"stroke":"#000000","stroke-width":0.1,"fill":"#003dff","filter":null},"#population":{"opacity":null,"stroke-width":1.6,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null},"#rural":{"stroke":"#0000aa"},"#urban":{"stroke":"#9d0000"},"#freshwater":{"opacity":0.5,"fill":"#a6c1fd","stroke":"#5f799d","stroke-width":0.7,"filter":null},"#salt":{"opacity":0.5,"fill":"#409b8a","stroke":"#388985","stroke-width":0.7,"filter":null},"#sinkhole":{"opacity":1,"fill":"#5bc9fd","stroke":"#53a3b0","stroke-width":0.7,"filter":null},"#frozen":{"opacity":0.95,"fill":"#cdd4e7","stroke":"#cfe0eb","stroke-width":0,"filter":null},"#lava":{"opacity":0.7,"fill":"#90270d","stroke":"#f93e0c","stroke-width":2,"filter":"url(#crumpled)"},"#sea_island":{"opacity":0.6,"stroke":"#1f3846","stroke-width":0.7,"filter":"url(#dropShadow)","auto-filter":1},"#lake_island":{"opacity":1,"stroke":"#7c8eaf","stroke-width":0.35,"filter":null},"#terrain":{"opacity":0.9,"set":"simple","size":1,"density":.4,filter":null,"mask":null},"#rivers":{"opacity":null,"filter":"","fill":"#779582"},"#ruler":{"opacity":null,"filter":null},"#roads":{"opacity":1,"stroke":"#8b4418","stroke-width":0.9,"stroke-dasharray":"2 3","stroke-linecap":"round","filter":"","mask":null},"#trails":{"opacity":1,"stroke":"#844017","stroke-width":0.2,"stroke-dasharray":".5 1","stroke-linecap":"round","filter":null,"mask":null},"#searoutes":{"opacity":0.8,"stroke":"#5e1865","stroke-width":0.6,"stroke-dasharray":"1.2 2.4","stroke-linecap":"round","filter":null,"mask":null},"#regions":{"opacity":0.4,"filter":"url(#dropShadow)"},"#statesHalo":{"opacity":1,"data-width":10.2,"stroke-width":10.2},"#provs":{"opacity":0.5,"filter":""},"#temperature":{"opacity":1,"font-size":"11px","fill":"#62001b","fill-opacity":0.3,"stroke":null,"stroke-width":2,"stroke-dasharray":2,"stroke-linecap":null,"filter":null},"#texture":{"opacity":null,"filter":null,"mask":"url(#land)"},"#textureImage":{"x":0,"y":0},"#zones":{"opacity":0.5,"stroke":"#333333","stroke-width":0,"stroke-dasharray":null,"stroke-linecap":"butt","filter":"url(#dropShadow01)","mask":null},"#ocean":{"opacity":1},"#oceanLayers":{"filter":null,"layers":"-6,-4,-2"},"#oceanBase":{"fill":"#4e6964"},"#oceanPattern":{"opacity":null},"#oceanicPattern":{"filter":"url(#pattern3)"},"#terrs":{"opacity":1,"scheme":"bright","terracing":0,"skip":0,"relax":1,"curve":1,"filter":"url(#filter-grayscale)","mask":"url(#land)"},"#legend":{"data-size":13,"font-size":13,"data-font":"Almendra+SC","font-family":"Almendra SC","stroke":"#812929","stroke-width":2.5,"stroke-dasharray":"0 4 10 4","stroke-linecap":"round","data-x":99,"data-y":93,"data-columns":8},"#legendBox":{},"#burgLabels > #cities":{"opacity":1,"fill":"#3e3e4b","data-size":7,"font-size":7,"data-font":"Bitter","font-family":"Bitter"},"#burgIcons > #cities":{"opacity":1,"fill":"#ffffff","fill-opacity":0.7,"size":2,"stroke":"#444444","stroke-width":0.25,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #cities":{"opacity":0.8,"fill":"#ffffff","size":4,"stroke":"#3e3e4b","stroke-width":1},"#burgLabels > #towns":{"opacity":1,"fill":"#3e3e4b","data-size":3,"font-size":3,"data-font":"Bitter","font-family":"Bitter"},"#burgIcons > #towns":{"opacity":0.95,"fill":"#ffffff","fill-opacity":0.7,"size":0.8,"stroke":"#3e3e4b","stroke-width":0.2,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #towns":{"opacity":1,"fill":"#ffffff","size":1.6,"stroke":"#3e3e4b","stroke-width":1.2},"#labels > #states":{"opacity":1,"fill":"#4e4e4e","stroke":"#b5b5b5","stroke-width":0,"data-size":22,"font-size":22,"data-font":"Almendra+SC","font-family":"Almendra SC","filter":""},"#labels > #addedLabels":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"data-size":18,"font-size":18,"data-font":"Almendra+SC","font-family":"Almendra SC","filter":null},"#fogging-cont":{"opacity":null,"fill":null,"stroke-width":null}}`;
+ const gloom = `{"#map":{"background-color":"#000000","filter":null,"data-filter":null},"#biomes":{"opacity":null,"filter":"url(#blur5)","mask":"url(#land)"},"#stateBorders":{"opacity":1,"stroke":"#56566d","stroke-width":1,"stroke-dasharray":2,"stroke-linecap":"butt","filter":""},"#provinceBorders":{"opacity":1,"stroke":"#56566d","stroke-width":0.3,"stroke-dasharray":".7 1","stroke-linecap":"butt","filter":null},"#cells":{"opacity":null,"stroke":"#808080","stroke-width":0.1,"filter":null,"mask":null},"#gridOverlay":{"opacity":0.8,"size":10,"type":"pointyHex","stroke":"#808080","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"transform":null,"filter":null,"mask":null},"#coordinates":{"opacity":1,"data-size":14,"font-size":14,"stroke":"#4a4a4a","stroke-width":1,"stroke-dasharray":6,"stroke-linecap":null,"filter":"","mask":""},"#compass":{"opacity":0.6,"transform":null,"filter":null,"mask":"url(#water)","shape-rendering":"optimizespeed"},"#rose":{"transform":"translate(100 100) scale(0.3)"},"#relig":{"opacity":0.7,"stroke":"#404040","stroke-width":1,"filter":null},"#cults":{"opacity":0.7,"stroke":"#777777","stroke-width":1.5,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#landmass":{"opacity":1,"fill":"#e0e0e0","filter":null},"#markers":{"opacity":0.8,"rescale":1,"filter":"url(#dropShadow05)"},"#prec":{"opacity":null,"stroke":"#000000","stroke-width":0.1,"fill":"#003dff","filter":null},"#population":{"opacity":null,"stroke-width":1.6,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null},"#rural":{"stroke":"#0000aa"},"#urban":{"stroke":"#9d0000"},"#freshwater":{"opacity":0.5,"fill":"#a6c1fd","stroke":"#5f799d","stroke-width":0.7,"filter":null},"#salt":{"opacity":0.5,"fill":"#409b8a","stroke":"#388985","stroke-width":0.7,"filter":null},"#sinkhole":{"opacity":1,"fill":"#5bc9fd","stroke":"#53a3b0","stroke-width":0.7,"filter":null},"#frozen":{"opacity":0.95,"fill":"#cdd4e7","stroke":"#cfe0eb","stroke-width":0,"filter":null},"#lava":{"opacity":0.7,"fill":"#90270d","stroke":"#f93e0c","stroke-width":2,"filter":"url(#crumpled)"},"#sea_island":{"opacity":0.6,"stroke":"#1f3846","stroke-width":0.7,"filter":"url(#dropShadow)","auto-filter":1},"#lake_island":{"opacity":1,"stroke":"#7c8eaf","stroke-width":0.35,"filter":null},"#terrain":{"opacity":0.9,"set":"simple","size":1,"density":0.4,"filter":null,"mask":null},"#rivers":{"opacity":null,"filter":"","fill":"#779582"},"#ruler":{"opacity":null,"filter":null},"#roads":{"opacity":1,"stroke":"#8b4418","stroke-width":0.9,"stroke-dasharray":"2 3","stroke-linecap":"round","filter":"","mask":null},"#trails":{"opacity":1,"stroke":"#844017","stroke-width":0.2,"stroke-dasharray":".5 1","stroke-linecap":"round","filter":null,"mask":null},"#searoutes":{"opacity":0.8,"stroke":"#5e1865","stroke-width":0.6,"stroke-dasharray":"1.2 2.4","stroke-linecap":"round","filter":null,"mask":null},"#regions":{"opacity":0.4,"filter":"url(#dropShadow)"},"#statesHalo":{"opacity":1,"data-width":10.2,"stroke-width":10.2},"#provs":{"opacity":0.5,"filter":""},"#temperature":{"opacity":1,"font-size":"11px","fill":"#62001b","fill-opacity":0.3,"stroke":null,"stroke-width":2,"stroke-dasharray":2,"stroke-linecap":null,"filter":null},"#texture":{"opacity":null,"filter":null,"mask":"url(#land)"},"#textureImage":{"x":0,"y":0},"#zones":{"opacity":0.5,"stroke":"#333333","stroke-width":0,"stroke-dasharray":null,"stroke-linecap":"butt","filter":"url(#dropShadow01)","mask":null},"#ocean":{"opacity":1},"#oceanLayers":{"filter":null,"layers":"-6,-4,-2"},"#oceanBase":{"fill":"#4e6964"},"#oceanPattern":{"opacity":null},"#oceanicPattern":{"filter":"url(#pattern3)"},"#terrs":{"opacity":1,"scheme":"bright","terracing":0,"skip":0,"relax":1,"curve":1,"filter":"url(#filter-grayscale)","mask":"url(#land)"},"#legend":{"data-size":13,"font-size":13,"data-font":"Almendra+SC","font-family":"Almendra SC","stroke":"#812929","stroke-width":2.5,"stroke-dasharray":"0 4 10 4","stroke-linecap":"round","data-x":99,"data-y":93,"data-columns":8},"#legendBox":{},"#burgLabels > #cities":{"opacity":1,"fill":"#3e3e4b","data-size":7,"font-size":7,"data-font":"Bitter","font-family":"Bitter"},"#burgIcons > #cities":{"opacity":1,"fill":"#ffffff","fill-opacity":0.7,"size":2,"stroke":"#444444","stroke-width":0.25,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #cities":{"opacity":0.8,"fill":"#ffffff","size":4,"stroke":"#3e3e4b","stroke-width":1},"#burgLabels > #towns":{"opacity":1,"fill":"#3e3e4b","data-size":3,"font-size":3,"data-font":"Bitter","font-family":"Bitter"},"#burgIcons > #towns":{"opacity":0.95,"fill":"#ffffff","fill-opacity":0.7,"size":0.8,"stroke":"#3e3e4b","stroke-width":0.2,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #towns":{"opacity":1,"fill":"#ffffff","size":1.6,"stroke":"#3e3e4b","stroke-width":1.2},"#labels > #states":{"opacity":1,"fill":"#4e4e4e","stroke":"#b5b5b5","stroke-width":0,"data-size":22,"font-size":22,"data-font":"Almendra+SC","font-family":"Almendra SC","filter":""},"#labels > #addedLabels":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"data-size":18,"font-size":18,"data-font":"Almendra+SC","font-family":"Almendra SC","filter":null},"#fogging-cont":{"opacity":null,"fill":null,"stroke-width":null}}`;
localStorage.setItem("styleGloom", gloom);
}
if (!localStorage.getItem("styleAncient")) {
- const ancient = `{"#map":{"background-color":"#000000","filter":"url(#filter-sepia)","data-filter":"sepia"},"#biomes":{"opacity":null,"filter":null,"mask":null},"#stateBorders":{"opacity":0.8,"stroke":"#56566d","stroke-width":1,"stroke-dasharray":2,"stroke-linecap":"butt","filter":null},"#provinceBorders":{"opacity":0.8,"stroke":"#56566d","stroke-width":0.2,"stroke-dasharray":1,"stroke-linecap":"butt","filter":null},"#cells":{"opacity":null,"stroke":"#808080","stroke-width":0.1,"filter":null,"mask":null},"#gridOverlay":{"opacity":0.8,"size":10,"type":"pointyHex","stroke":"#808080","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"transform":null,"filter":null,"mask":null},"#coordinates":{"opacity":1,"data-size":12,"font-size":12,"stroke":"#d4d4d4","stroke-width":1,"stroke-dasharray":5,"stroke-linecap":null,"filter":null,"mask":null},"#compass":{"opacity":0.8,"transform":null,"filter":null,"mask":"url(#water)","shape-rendering":"optimizespeed"},"#rose":{"transform":"translate(80 80) scale(.25)"},"#relig":{"opacity":0.7,"stroke":"#404040","stroke-width":0.7,"filter":null},"#cults":{"opacity":0.6,"stroke":"#777777","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#landmass":{"opacity":1,"fill":"#eee9d7","filter":null},"#markers":{"opacity":null,"rescale":1,"filter":"url(#dropShadow01)"},"#prec":{"opacity":null,"stroke":"#000000","stroke-width":0.1,"fill":"#003dff","filter":null},"#population":{"opacity":null,"stroke-width":1.6,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null},"#rural":{"stroke":"#0000ff"},"#urban":{"stroke":"#ff0000"},"#freshwater":{"opacity":0.5,"fill":"#a6c1fd","stroke":"#5f799d","stroke-width":0.7,"filter":null},"#salt":{"opacity":0.5,"fill":"#409b8a","stroke":"#388985","stroke-width":0.7,"filter":null},"#sinkhole":{"opacity":1,"fill":"#5bc9fd","stroke":"#53a3b0","stroke-width":0.7,"filter":null},"#frozen":{"opacity":0.95,"fill":"#cdd4e7","stroke":"#cfe0eb","stroke-width":0,"filter":null},"#lava":{"opacity":0.7,"fill":"#90270d","stroke":"#f93e0c","stroke-width":2,"filter":"url(#crumpled)"},"#sea_island":{"opacity":0.5,"stroke":"#1f3846","stroke-width":0.7,"filter":"url(#dropShadow)","auto-filter":1},"#lake_island":{"opacity":1,"stroke":"#7c8eaf","stroke-width":0.35,"filter":null},"#terrain":{"opacity":null,"set":"simple","size":1,"density":.4,filter":null,"mask":null},"#rivers":{"opacity":null,"filter":null,"fill":"#5d97bb"},"#ruler":{"opacity":null,"filter":null},"#roads":{"opacity":0.8,"stroke":"#2e1607","stroke-width":1.23,"stroke-dasharray":3,"stroke-linecap":"inherit","filter":null,"mask":null},"#trails":{"opacity":0.8,"stroke":"#331809","stroke-width":0.5,"stroke-dasharray":"1 2","stroke-linecap":"butt","filter":null,"mask":null},"#searoutes":{"opacity":0.8,"stroke":"#ffffff","stroke-width":0.8,"stroke-dasharray":"1 2","stroke-linecap":"round","filter":null,"mask":null},"#regions":{"opacity":0.4,"filter":""},"#statesHalo":{"opacity":1,"data-width":10,"stroke-width":10},"#provs":{"opacity":0.6,"filter":null},"#temperature":{"opacity":null,"font-size":"8px","fill":"#000000","fill-opacity":0.3,"stroke":null,"stroke-width":1.8,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#texture":{"opacity":null,"filter":null,"mask":"url(#land)"},"#textureImage":{},"#zones":{"opacity":0.6,"stroke":"#333333","stroke-width":0,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null,"mask":null},"#ocean":{"opacity":1},"#oceanLayers":{"filter":"url(#blur5)","layers":"-6,-4,-2"},"#oceanBase":{"fill":"#a7a01f"},"#oceanPattern":{"opacity":null},"#oceanicPattern":{"filter":"url(#pattern1)"},"#terrs":{"opacity":null,"scheme":"light","terracing":0,"skip":0,"relax":0,"curve":0,"filter":null,"mask":"url(#land)"},"#legend":{"data-size":13,"font-size":13,"data-font":"Almendra+SC","font-family":"Almendra SC","stroke":"#812929","stroke-width":2.5,"stroke-dasharray":"0 4 10 4","stroke-linecap":"round","data-x":99,"data-y":93,"data-columns":8},"#legendBox":{},"#burgLabels > #cities":{"opacity":1,"fill":"#3e3e4b","data-size":8,"font-size":8,"data-font":"Almendra+SC","font-family":"Almendra SC"},"#burgIcons > #cities":{"opacity":1,"fill":"#fdfab9","fill-opacity":0.7,"size":1,"stroke":"#54251d","stroke-width":0.3,"stroke-dasharray":".3 .4","stroke-linecap":"butt"},"#anchors > #cities":{"opacity":1,"fill":"#ffffff","size":2,"stroke":"#3e3e4b","stroke-width":1.2},"#burgLabels > #towns":{"opacity":1,"fill":"#3e3e4b","data-size":4,"font-size":4,"data-font":"Almendra+SC","font-family":"Almendra SC"},"#burgIcons > #towns":{"opacity":1,"fill":"#fef4d8","fill-opacity":0.7,"size":0.5,"stroke":"#463124","stroke-width":0.12,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #towns":{"opacity":1,"fill":"#ffffff","size":1,"stroke":"#3e3e4b","stroke-width":1.2},"#labels > #states":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"data-size":22,"font-size":22,"data-font":"Almendra+SC","font-family":"Almendra SC","filter":null},"#labels > #addedLabels":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"data-size":18,"font-size":18,"data-font":"Almendra+SC","font-family":"Almendra SC","filter":null},"#fogging-cont":{"opacity":null,"fill":null,"stroke-width":null}}`;
+ const ancient = `{"#map":{"background-color":"#000000","filter":"url(#filter-sepia)","data-filter":"sepia"},"#biomes":{"opacity":null,"filter":null,"mask":null},"#stateBorders":{"opacity":0.8,"stroke":"#56566d","stroke-width":1,"stroke-dasharray":2,"stroke-linecap":"butt","filter":null},"#provinceBorders":{"opacity":0.8,"stroke":"#56566d","stroke-width":0.2,"stroke-dasharray":1,"stroke-linecap":"butt","filter":null},"#cells":{"opacity":null,"stroke":"#808080","stroke-width":0.1,"filter":null,"mask":null},"#gridOverlay":{"opacity":0.8,"size":10,"type":"pointyHex","stroke":"#808080","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"transform":null,"filter":null,"mask":null},"#coordinates":{"opacity":1,"data-size":12,"font-size":12,"stroke":"#d4d4d4","stroke-width":1,"stroke-dasharray":5,"stroke-linecap":null,"filter":null,"mask":null},"#compass":{"opacity":0.8,"transform":null,"filter":null,"mask":"url(#water)","shape-rendering":"optimizespeed"},"#rose":{"transform":"translate(80 80) scale(.25)"},"#relig":{"opacity":0.7,"stroke":"#404040","stroke-width":0.7,"filter":null},"#cults":{"opacity":0.6,"stroke":"#777777","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#landmass":{"opacity":1,"fill":"#eee9d7","filter":null},"#markers":{"opacity":null,"rescale":1,"filter":"url(#dropShadow01)"},"#prec":{"opacity":null,"stroke":"#000000","stroke-width":0.1,"fill":"#003dff","filter":null},"#population":{"opacity":null,"stroke-width":1.6,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null},"#rural":{"stroke":"#0000ff"},"#urban":{"stroke":"#ff0000"},"#freshwater":{"opacity":0.5,"fill":"#a6c1fd","stroke":"#5f799d","stroke-width":0.7,"filter":null},"#salt":{"opacity":0.5,"fill":"#409b8a","stroke":"#388985","stroke-width":0.7,"filter":null},"#sinkhole":{"opacity":1,"fill":"#5bc9fd","stroke":"#53a3b0","stroke-width":0.7,"filter":null},"#frozen":{"opacity":0.95,"fill":"#cdd4e7","stroke":"#cfe0eb","stroke-width":0,"filter":null},"#lava":{"opacity":0.7,"fill":"#90270d","stroke":"#f93e0c","stroke-width":2,"filter":"url(#crumpled)"},"#sea_island":{"opacity":0.5,"stroke":"#1f3846","stroke-width":0.7,"filter":"url(#dropShadow)","auto-filter":1},"#lake_island":{"opacity":1,"stroke":"#7c8eaf","stroke-width":0.35,"filter":null},"#terrain":{"opacity":null,"set":"simple","size":1,"density":0.4,"filter":null,"mask":null},"#rivers":{"opacity":null,"filter":null,"fill":"#5d97bb"},"#ruler":{"opacity":null,"filter":null},"#roads":{"opacity":0.8,"stroke":"#2e1607","stroke-width":1.23,"stroke-dasharray":3,"stroke-linecap":"inherit","filter":null,"mask":null},"#trails":{"opacity":0.8,"stroke":"#331809","stroke-width":0.5,"stroke-dasharray":"1 2","stroke-linecap":"butt","filter":null,"mask":null},"#searoutes":{"opacity":0.8,"stroke":"#ffffff","stroke-width":0.8,"stroke-dasharray":"1 2","stroke-linecap":"round","filter":null,"mask":null},"#regions":{"opacity":0.4,"filter":""},"#statesHalo":{"opacity":1,"data-width":10,"stroke-width":10},"#provs":{"opacity":0.6,"filter":null},"#temperature":{"opacity":null,"font-size":"8px","fill":"#000000","fill-opacity":0.3,"stroke":null,"stroke-width":1.8,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#texture":{"opacity":null,"filter":null,"mask":"url(#land)"},"#textureImage":{},"#zones":{"opacity":0.6,"stroke":"#333333","stroke-width":0,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null,"mask":null},"#ocean":{"opacity":1},"#oceanLayers":{"filter":"url(#blur5)","layers":"-6,-4,-2"},"#oceanBase":{"fill":"#a7a01f"},"#oceanPattern":{"opacity":null},"#oceanicPattern":{"filter":"url(#pattern1)"},"#terrs":{"opacity":null,"scheme":"light","terracing":0,"skip":0,"relax":0,"curve":0,"filter":null,"mask":"url(#land)"},"#legend":{"data-size":13,"font-size":13,"data-font":"Almendra+SC","font-family":"Almendra SC","stroke":"#812929","stroke-width":2.5,"stroke-dasharray":"0 4 10 4","stroke-linecap":"round","data-x":99,"data-y":93,"data-columns":8},"#legendBox":{},"#burgLabels > #cities":{"opacity":1,"fill":"#3e3e4b","data-size":8,"font-size":8,"data-font":"Almendra+SC","font-family":"Almendra SC"},"#burgIcons > #cities":{"opacity":1,"fill":"#fdfab9","fill-opacity":0.7,"size":1,"stroke":"#54251d","stroke-width":0.3,"stroke-dasharray":".3 .4","stroke-linecap":"butt"},"#anchors > #cities":{"opacity":1,"fill":"#ffffff","size":2,"stroke":"#3e3e4b","stroke-width":1.2},"#burgLabels > #towns":{"opacity":1,"fill":"#3e3e4b","data-size":4,"font-size":4,"data-font":"Almendra+SC","font-family":"Almendra SC"},"#burgIcons > #towns":{"opacity":1,"fill":"#fef4d8","fill-opacity":0.7,"size":0.5,"stroke":"#463124","stroke-width":0.12,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #towns":{"opacity":1,"fill":"#ffffff","size":1,"stroke":"#3e3e4b","stroke-width":1.2},"#labels > #states":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"data-size":22,"font-size":22,"data-font":"Almendra+SC","font-family":"Almendra SC","filter":null},"#labels > #addedLabels":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"data-size":18,"font-size":18,"data-font":"Almendra+SC","font-family":"Almendra SC","filter":null},"#fogging-cont":{"opacity":null,"fill":null,"stroke-width":null}}`;
localStorage.setItem("styleAncient", ancient);
}
if (!localStorage.getItem("styleMonochrome")) {
- const monochrome = `{"#map":{"background-color":"#000000","filter":"url(#filter-grayscale)","data-filter":"grayscale"},"#biomes":{"opacity":null,"filter":"url(#blur5)","mask":null},"#stateBorders":{"opacity":1,"stroke":"#56566d","stroke-width":1,"stroke-dasharray":2,"stroke-linecap":"butt","filter":null},"#provinceBorders":{"opacity":1,"stroke":"#56566d","stroke-width":0.4,"stroke-dasharray":1,"stroke-linecap":"butt","filter":null},"#cells":{"opacity":null,"stroke":"#808080","stroke-width":0.1,"filter":null,"mask":null},"#gridOverlay":{"opacity":0.8,"size":10,"type":"pointyHex","stroke":"#808080","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"transform":null,"filter":null,"mask":null},"#coordinates":{"opacity":1,"data-size":12,"font-size":12,"stroke":"#d4d4d4","stroke-width":1,"stroke-dasharray":5,"stroke-linecap":null,"filter":null,"mask":null},"#compass":{"opacity":0.8,"transform":null,"filter":null,"mask":"url(#water)","shape-rendering":"optimizespeed"},"#rose":{"transform":null},"#relig":{"opacity":0.7,"stroke":"#404040","stroke-width":0.7,"filter":null},"#cults":{"opacity":0.6,"stroke":"#777777","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#landmass":{"opacity":1,"fill":"#000000","filter":null},"#markers":{"opacity":null,"rescale":1,"filter":"url(#dropShadow01)"},"#prec":{"opacity":null,"stroke":"#000000","stroke-width":0.1,"fill":"#003dff","filter":null},"#population":{"opacity":null,"stroke-width":1.6,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null},"#rural":{"stroke":"#0000ff"},"#urban":{"stroke":"#ff0000"},"#freshwater":{"opacity":1,"fill":"#000000","stroke":"#515151","stroke-width":0,"filter":null},"#salt":{"opacity":1,"fill":"#000000","stroke":"#484848","stroke-width":0,"filter":null},"#sinkhole":{"opacity":1,"fill":"#000000","stroke":"#5f5f5f","stroke-width":0.5,"filter":null},"#frozen":{"opacity":1,"fill":"#000000","stroke":"#6f6f6f","stroke-width":0,"filter":null},"#lava":{"opacity":1,"fill":"#000000","stroke":"#5d5d5d","stroke-width":0,"filter":""},"#sea_island":{"opacity":1,"stroke":"#1f3846","stroke-width":0,"filter":"","auto-filter":0},"#lake_island":{"opacity":0,"stroke":"#7c8eaf","stroke-width":0,"filter":null},"#terrain":{"opacity":null,"set":"simple","size":1,"density":.4,filter":null,"mask":null},"#rivers":{"opacity":0.2,"filter":"url(#blur1)","fill":"#000000"},"#ruler":{"opacity":null,"filter":null},"#roads":{"opacity":0.9,"stroke":"#d06324","stroke-width":0.7,"stroke-dasharray":2,"stroke-linecap":"butt","filter":null,"mask":null},"#trails":{"opacity":0.9,"stroke":"#d06324","stroke-width":0.25,"stroke-dasharray":".8 1.6","stroke-linecap":"butt","filter":null,"mask":null},"#searoutes":{"opacity":0.8,"stroke":"#ffffff","stroke-width":0.45,"stroke-dasharray":"1 2","stroke-linecap":"round","filter":null,"mask":null},"#regions":{"opacity":0.4,"filter":null},"#statesHalo":{"opacity":1,"data-width":10,"stroke-width":10},"#provs":{"opacity":0.6,"filter":null},"#temperature":{"opacity":null,"font-size":"8px","fill":"#000000","fill-opacity":0.3,"stroke":null,"stroke-width":1.8,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#texture":{"opacity":1,"filter":null,"mask":"url(#land)"},"#textureImage":{},"#zones":{"opacity":0.6,"stroke":"#333333","stroke-width":0,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null,"mask":null},"#ocean":{"opacity":0},"#oceanLayers":{"filter":null,"layers":"none"},"#oceanBase":{"fill":"#000000"},"#oceanPattern":{"opacity":null},"#oceanicPattern":{"filter":"url(#emptyImage)"},"#terrs":{"opacity":1,"scheme":"monochrome","terracing":0,"skip":5,"relax":0,"curve":0,"filter":"url(#blur3)","mask":"url(#land)"},"#legend":{"data-size":13,"font-size":13,"data-font":"Almendra+SC","font-family":"Almendra SC","stroke":"#812929","stroke-width":2.5,"stroke-dasharray":"0 4 10 4","stroke-linecap":"round","data-x":99,"data-y":93,"data-columns":8},"#legendBox":{},"#burgLabels > #cities":{"opacity":1,"fill":"#3e3e4b","data-size":7,"font-size":7,"data-font":"Almendra+SC","font-family":"Almendra SC"},"#burgIcons > #cities":{"opacity":1,"fill":"#ffffff","fill-opacity":0.7,"size":1,"stroke":"#3e3e4b","stroke-width":0.24,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #cities":{"opacity":1,"fill":"#ffffff","size":2,"stroke":"#3e3e4b","stroke-width":1.2},"#burgLabels > #towns":{"opacity":1,"fill":"#3e3e4b","data-size":4,"font-size":4,"data-font":"Almendra+SC","font-family":"Almendra SC"},"#burgIcons > #towns":{"opacity":1,"fill":"#ffffff","fill-opacity":0.7,"size":0.5,"stroke":"#3e3e4b","stroke-width":0.12,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #towns":{"opacity":1,"fill":"#ffffff","size":1,"stroke":"#3e3e4b","stroke-width":1.2},"#labels > #states":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"data-size":22,"font-size":22,"data-font":"Almendra+SC","font-family":"Almendra SC","filter":null},"#labels > #addedLabels":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"data-size":18,"font-size":18,"data-font":"Almendra+SC","font-family":"Almendra SC","filter":null},"#fogging-cont":{"opacity":null,"fill":null,"stroke-width":null}}`;
+ const monochrome = `{"#map":{"background-color":"#000000","filter":"url(#filter-grayscale)","data-filter":"grayscale"},"#biomes":{"opacity":null,"filter":"url(#blur5)","mask":null},"#stateBorders":{"opacity":1,"stroke":"#56566d","stroke-width":1,"stroke-dasharray":2,"stroke-linecap":"butt","filter":null},"#provinceBorders":{"opacity":1,"stroke":"#56566d","stroke-width":0.4,"stroke-dasharray":1,"stroke-linecap":"butt","filter":null},"#cells":{"opacity":null,"stroke":"#808080","stroke-width":0.1,"filter":null,"mask":null},"#gridOverlay":{"opacity":0.8,"size":10,"type":"pointyHex","stroke":"#808080","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"transform":null,"filter":null,"mask":null},"#coordinates":{"opacity":1,"data-size":12,"font-size":12,"stroke":"#d4d4d4","stroke-width":1,"stroke-dasharray":5,"stroke-linecap":null,"filter":null,"mask":null},"#compass":{"opacity":0.8,"transform":null,"filter":null,"mask":"url(#water)","shape-rendering":"optimizespeed"},"#rose":{"transform":null},"#relig":{"opacity":0.7,"stroke":"#404040","stroke-width":0.7,"filter":null},"#cults":{"opacity":0.6,"stroke":"#777777","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#landmass":{"opacity":1,"fill":"#000000","filter":null},"#markers":{"opacity":null,"rescale":1,"filter":"url(#dropShadow01)"},"#prec":{"opacity":null,"stroke":"#000000","stroke-width":0.1,"fill":"#003dff","filter":null},"#population":{"opacity":null,"stroke-width":1.6,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null},"#rural":{"stroke":"#0000ff"},"#urban":{"stroke":"#ff0000"},"#freshwater":{"opacity":1,"fill":"#000000","stroke":"#515151","stroke-width":0,"filter":null},"#salt":{"opacity":1,"fill":"#000000","stroke":"#484848","stroke-width":0,"filter":null},"#sinkhole":{"opacity":1,"fill":"#000000","stroke":"#5f5f5f","stroke-width":0.5,"filter":null},"#frozen":{"opacity":1,"fill":"#000000","stroke":"#6f6f6f","stroke-width":0,"filter":null},"#lava":{"opacity":1,"fill":"#000000","stroke":"#5d5d5d","stroke-width":0,"filter":""},"#sea_island":{"opacity":1,"stroke":"#1f3846","stroke-width":0,"filter":"","auto-filter":0},"#lake_island":{"opacity":0,"stroke":"#7c8eaf","stroke-width":0,"filter":null},"#terrain":{"opacity":null,"set":"simple","size":1,"density":0.4,"filter":null,"mask":null},"#rivers":{"opacity":0.2,"filter":"url(#blur1)","fill":"#000000"},"#ruler":{"opacity":null,"filter":null},"#roads":{"opacity":0.9,"stroke":"#d06324","stroke-width":0.7,"stroke-dasharray":2,"stroke-linecap":"butt","filter":null,"mask":null},"#trails":{"opacity":0.9,"stroke":"#d06324","stroke-width":0.25,"stroke-dasharray":".8 1.6","stroke-linecap":"butt","filter":null,"mask":null},"#searoutes":{"opacity":0.8,"stroke":"#ffffff","stroke-width":0.45,"stroke-dasharray":"1 2","stroke-linecap":"round","filter":null,"mask":null},"#regions":{"opacity":0.4,"filter":null},"#statesHalo":{"opacity":1,"data-width":10,"stroke-width":10},"#provs":{"opacity":0.6,"filter":null},"#temperature":{"opacity":null,"font-size":"8px","fill":"#000000","fill-opacity":0.3,"stroke":null,"stroke-width":1.8,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#texture":{"opacity":1,"filter":null,"mask":"url(#land)"},"#textureImage":{},"#zones":{"opacity":0.6,"stroke":"#333333","stroke-width":0,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null,"mask":null},"#ocean":{"opacity":0},"#oceanLayers":{"filter":null,"layers":"none"},"#oceanBase":{"fill":"#000000"},"#oceanPattern":{"opacity":null},"#oceanicPattern":{"filter":"url(#emptyImage)"},"#terrs":{"opacity":1,"scheme":"monochrome","terracing":0,"skip":5,"relax":0,"curve":0,"filter":"url(#blur3)","mask":"url(#land)"},"#legend":{"data-size":13,"font-size":13,"data-font":"Almendra+SC","font-family":"Almendra SC","stroke":"#812929","stroke-width":2.5,"stroke-dasharray":"0 4 10 4","stroke-linecap":"round","data-x":99,"data-y":93,"data-columns":8},"#legendBox":{},"#burgLabels > #cities":{"opacity":1,"fill":"#3e3e4b","data-size":7,"font-size":7,"data-font":"Almendra+SC","font-family":"Almendra SC"},"#burgIcons > #cities":{"opacity":1,"fill":"#ffffff","fill-opacity":0.7,"size":1,"stroke":"#3e3e4b","stroke-width":0.24,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #cities":{"opacity":1,"fill":"#ffffff","size":2,"stroke":"#3e3e4b","stroke-width":1.2},"#burgLabels > #towns":{"opacity":1,"fill":"#3e3e4b","data-size":4,"font-size":4,"data-font":"Almendra+SC","font-family":"Almendra SC"},"#burgIcons > #towns":{"opacity":1,"fill":"#ffffff","fill-opacity":0.7,"size":0.5,"stroke":"#3e3e4b","stroke-width":0.12,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #towns":{"opacity":1,"fill":"#ffffff","size":1,"stroke":"#3e3e4b","stroke-width":1.2},"#labels > #states":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"data-size":22,"font-size":22,"data-font":"Almendra+SC","font-family":"Almendra SC","filter":null},"#labels > #addedLabels":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"data-size":18,"font-size":18,"data-font":"Almendra+SC","font-family":"Almendra SC","filter":null},"#fogging-cont":{"opacity":null,"fill":null,"stroke-width":null}}`;
localStorage.setItem("styleMonochrome", monochrome);
}
}