mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-22 12:01:23 +01:00
Merge branch 'master' into mosuzi-dev
This commit is contained in:
commit
fe5f2133c0
160 changed files with 29893 additions and 427 deletions
|
|
@ -1,7 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
window.BurgsAndStates = (function () {
|
||||
const generate = function () {
|
||||
window.BurgsAndStates = (() => {
|
||||
const generate = () => {
|
||||
const {cells, cultures} = pack;
|
||||
const n = cells.i.length;
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ window.BurgsAndStates = (function () {
|
|||
const colors = getColors(burgs.length - 1);
|
||||
const each5th = each(5);
|
||||
|
||||
burgs.forEach(function (b, i) {
|
||||
burgs.forEach((b, i) => {
|
||||
if (!i) return; // skip first element
|
||||
|
||||
// burgs data
|
||||
|
|
@ -164,12 +164,10 @@ window.BurgsAndStates = (function () {
|
|||
};
|
||||
|
||||
// define burg coordinates, coa, port status and define details
|
||||
const specifyBurgs = function () {
|
||||
const specifyBurgs = () => {
|
||||
TIME && console.time("specifyBurgs");
|
||||
const cells = pack.cells,
|
||||
vertices = pack.vertices,
|
||||
features = pack.features,
|
||||
temp = grid.cells.temp;
|
||||
const {cells, features} = pack;
|
||||
const temp = grid.cells.temp;
|
||||
|
||||
for (const b of pack.burgs) {
|
||||
if (!b.i || b.lock) continue;
|
||||
|
|
@ -231,7 +229,7 @@ window.BurgsAndStates = (function () {
|
|||
TIME && console.timeEnd("specifyBurgs");
|
||||
};
|
||||
|
||||
const getType = function (i, port) {
|
||||
const getType = (i, port) => {
|
||||
const cells = pack.cells;
|
||||
if (port) return "Naval";
|
||||
if (cells.haven[i] && pack.features[cells.f[cells.haven[i]]].type === "lake") return "Lake";
|
||||
|
|
@ -246,10 +244,11 @@ window.BurgsAndStates = (function () {
|
|||
return "Generic";
|
||||
};
|
||||
|
||||
const defineBurgFeatures = function (newburg) {
|
||||
const cells = pack.cells;
|
||||
const defineBurgFeatures = newburg => {
|
||||
const {cells} = pack;
|
||||
|
||||
pack.burgs
|
||||
.filter(b => (newburg ? b.i == newburg.i : b.i && !b.removed))
|
||||
.filter(b => (newburg ? b.i == newburg.i : b.i && !b.removed && !b.lock))
|
||||
.forEach(b => {
|
||||
const pop = b.population;
|
||||
b.citadel = Number(b.capital || (pop > 50 && P(0.75)) || (pop > 15 && P(0.5)) || P(0.1));
|
||||
|
|
@ -264,7 +263,7 @@ window.BurgsAndStates = (function () {
|
|||
});
|
||||
};
|
||||
|
||||
const drawBurgs = function () {
|
||||
const drawBurgs = () => {
|
||||
TIME && console.time("drawBurgs");
|
||||
|
||||
// remove old data
|
||||
|
|
@ -362,7 +361,7 @@ window.BurgsAndStates = (function () {
|
|||
};
|
||||
|
||||
// expand cultures across the map (Dijkstra-like algorithm)
|
||||
const expandStates = function () {
|
||||
const expandStates = () => {
|
||||
TIME && console.time("expandStates");
|
||||
const {cells, states, cultures, burgs} = pack;
|
||||
|
||||
|
|
@ -458,7 +457,7 @@ window.BurgsAndStates = (function () {
|
|||
TIME && console.timeEnd("expandStates");
|
||||
};
|
||||
|
||||
const normalizeStates = function () {
|
||||
const normalizeStates = () => {
|
||||
TIME && console.time("normalizeStates");
|
||||
const cells = pack.cells,
|
||||
burgs = pack.burgs;
|
||||
|
|
@ -480,7 +479,7 @@ window.BurgsAndStates = (function () {
|
|||
|
||||
// Resets the cultures of all burgs and states to their
|
||||
// cell or center cell's (respectively) culture.
|
||||
const updateCultures = function () {
|
||||
const updateCultures = () => {
|
||||
TIME && console.time("updateCulturesForBurgsAndStates");
|
||||
|
||||
// Assign the culture associated with the burgs cell.
|
||||
|
|
@ -505,7 +504,7 @@ window.BurgsAndStates = (function () {
|
|||
};
|
||||
|
||||
// calculate states data like area, population etc.
|
||||
const collectStatistics = function () {
|
||||
const collectStatistics = () => {
|
||||
TIME && console.time("collectStatistics");
|
||||
const {cells, states} = pack;
|
||||
|
||||
|
|
@ -543,7 +542,7 @@ window.BurgsAndStates = (function () {
|
|||
TIME && console.timeEnd("collectStatistics");
|
||||
};
|
||||
|
||||
const assignColors = function () {
|
||||
const assignColors = () => {
|
||||
TIME && console.time("assignColors");
|
||||
const colors = ["#66c2a5", "#fc8d62", "#8da0cb", "#e78ac3", "#a6d854", "#ffd92f"]; // d3.schemeSet2;
|
||||
|
||||
|
|
@ -579,6 +578,7 @@ window.BurgsAndStates = (function () {
|
|||
Expedition: 1,
|
||||
Crusade: 1
|
||||
};
|
||||
|
||||
const generateCampaign = state => {
|
||||
const neighbors = state.neighbors.length ? state.neighbors : [0];
|
||||
return neighbors
|
||||
|
|
@ -592,7 +592,7 @@ window.BurgsAndStates = (function () {
|
|||
};
|
||||
|
||||
// generate historical conflicts of each state
|
||||
const generateCampaigns = function () {
|
||||
const generateCampaigns = () => {
|
||||
pack.states.forEach(s => {
|
||||
if (!s.i || s.removed) return;
|
||||
s.campaigns = generateCampaign(s);
|
||||
|
|
@ -600,7 +600,7 @@ window.BurgsAndStates = (function () {
|
|||
};
|
||||
|
||||
// generate Diplomatic Relationships
|
||||
const generateDiplomacy = function () {
|
||||
const generateDiplomacy = () => {
|
||||
TIME && console.time("generateDiplomacy");
|
||||
const cells = pack.cells,
|
||||
states = pack.states;
|
||||
|
|
@ -785,7 +785,7 @@ window.BurgsAndStates = (function () {
|
|||
};
|
||||
|
||||
// select a forms for listed or all valid states
|
||||
const defineStateForms = function (list) {
|
||||
const defineStateForms = list => {
|
||||
TIME && console.time("defineStateForms");
|
||||
const states = pack.states.filter(s => s.i && !s.removed && !s.lock);
|
||||
if (states.length < 1) return;
|
||||
|
|
@ -933,14 +933,14 @@ window.BurgsAndStates = (function () {
|
|||
"Marches"
|
||||
];
|
||||
|
||||
const getFullName = function (s) {
|
||||
if (!s.formName) return s.name;
|
||||
if (!s.name && s.formName) return "The " + s.formName;
|
||||
const adjName = adjForms.includes(s.formName) && !/-| /.test(s.name);
|
||||
return adjName ? `${getAdjective(s.name)} ${s.formName}` : `${s.formName} of ${s.name}`;
|
||||
const getFullName = state => {
|
||||
if (!state.formName) return state.name;
|
||||
if (!state.name && state.formName) return "The " + state.formName;
|
||||
const adjName = adjForms.includes(state.formName) && !/-| /.test(state.name);
|
||||
return adjName ? `${getAdjective(state.name)} ${state.formName}` : `${state.formName} of ${state.name}`;
|
||||
};
|
||||
|
||||
const generateProvinces = function (regenerate = false, regenerateInLockedStates = false) {
|
||||
const generateProvinces = (regenerate = false, regenerateInLockedStates = false) => {
|
||||
TIME && console.time("generateProvinces");
|
||||
const localSeed = regenerate ? generateSeed() : seed;
|
||||
Math.random = aleaPRNG(localSeed);
|
||||
|
|
@ -1128,14 +1128,14 @@ window.BurgsAndStates = (function () {
|
|||
const isleGroup = !singleIsle && !provCells.find(i => pack.features[cells.f[i]].group !== "isle");
|
||||
const colony = !singleIsle && !isleGroup && P(0.5) && !isPassable(s.center, center);
|
||||
|
||||
const name = (function () {
|
||||
const name = (() => {
|
||||
const colonyName = colony && P(0.8) && getColonyName();
|
||||
if (colonyName) return colonyName;
|
||||
if (burgCell && P(0.5)) return burgs[burg].name;
|
||||
return Names.getState(Names.getCultureShort(c), c);
|
||||
})();
|
||||
|
||||
const formName = (function () {
|
||||
const formName = (() => {
|
||||
if (singleIsle) return "Island";
|
||||
if (isleGroup) return "Islands";
|
||||
if (colony) return "Colony";
|
||||
|
|
|
|||
|
|
@ -752,6 +752,8 @@ export function resolveVersionConflicts(version) {
|
|||
const curve = curveTypes[terrs.attr("curve")] || "curveBasisClosed";
|
||||
|
||||
terrs
|
||||
.attr("opacity", null)
|
||||
.attr("filter", null)
|
||||
.attr("mask", null)
|
||||
.attr("scheme", null)
|
||||
.attr("terracing", null)
|
||||
|
|
@ -770,6 +772,7 @@ export function resolveVersionConflicts(version) {
|
|||
.attr("skip", 0)
|
||||
.attr("relax", 1)
|
||||
.attr("curve", curve);
|
||||
|
||||
terrs
|
||||
.append("g")
|
||||
.attr("id", "landHeights")
|
||||
|
|
@ -843,4 +846,16 @@ export function resolveVersionConflicts(version) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (version < 1.98) {
|
||||
// v1.98.00 changed compass layer and rose element id
|
||||
const rose = compass.select("use");
|
||||
rose.attr("xlink:href", "#defs-compass-rose");
|
||||
|
||||
if (!compass.selectAll("*").size()) {
|
||||
compass.style("display", "none");
|
||||
compass.append("use").attr("xlink:href", "#defs-compass-rose");
|
||||
shiftCompass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1427,7 +1427,7 @@ function openStateMergeDialog() {
|
|||
if (element) {
|
||||
element.id = newId;
|
||||
element.dataset.state = rulingStateId;
|
||||
element.dataset.i = newIndex;
|
||||
element.dataset.id = newIndex;
|
||||
rulingStateArmy.appendChild(element);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ function getMapInfo() {
|
|||
description: "Azgaar's Fantasy Map Generator output: azgaar.github.io/Fantasy-map-generator",
|
||||
exportedAt: new Date().toISOString(),
|
||||
mapName: mapName.value,
|
||||
width: graphWidth,
|
||||
height: graphHeight,
|
||||
seed,
|
||||
mapId
|
||||
};
|
||||
|
|
|
|||
|
|
@ -546,4 +546,32 @@ Noah Morris
|
|||
Phil Karecki
|
||||
Matthew Jarocki
|
||||
Lucius Licinius Lucullus
|
||||
Andrew Haney`;
|
||||
Andrew Haney
|
||||
Noah Morris
|
||||
Phil Karecki
|
||||
Matthew Jarocki
|
||||
Lucius Licinius Lucullus
|
||||
Andrew Haney
|
||||
Jesse Luke
|
||||
Lord_Luce
|
||||
Neko no Maigo
|
||||
Hossyboy
|
||||
Yasui Masatake
|
||||
Jesse Roy
|
||||
Remain
|
||||
Douglas Rector
|
||||
J Clark
|
||||
Raine Logan
|
||||
Matty Ice
|
||||
DieMuetze
|
||||
Dan Popoli
|
||||
Marwyn
|
||||
Kederalia
|
||||
Whyse Wytch
|
||||
Elliyevee
|
||||
James Miller
|
||||
Pirate Fish
|
||||
David Leitner
|
||||
Vyritecht
|
||||
emre
|
||||
Don't mail me`;
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ async function getMapURL(type, options) {
|
|||
|
||||
// add wind rose
|
||||
if (cloneEl.getElementById("compass")) {
|
||||
const rose = svgDefs.getElementById("rose");
|
||||
const rose = svgDefs.getElementById("defs-compass-rose");
|
||||
if (rose) cloneDefs.appendChild(rose.cloneNode(true));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ async function parseLoadedData(data, mapVersion) {
|
|||
{
|
||||
// dynamically import and run auto-update script
|
||||
const versionNumber = parseFloat(params[0]);
|
||||
const {resolveVersionConflicts} = await import("../dynamic/auto-update.js?v=1.97.04");
|
||||
const {resolveVersionConflicts} = await import("../dynamic/auto-update.js?v=1.98.00");
|
||||
resolveVersionConflicts(versionNumber);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -358,7 +358,9 @@ window.Military = (function () {
|
|||
.attr("id", d => "regiment" + s + "-" + d.i)
|
||||
.attr("data-name", d => d.name)
|
||||
.attr("data-state", s)
|
||||
.attr("data-id", d => d.i);
|
||||
.attr("data-id", d => d.i)
|
||||
.attr("transform", d => (d.angle ? `rotate(${d.angle})` : null))
|
||||
.attr("transform-origin", d => `${d.x}px ${d.y}px`);
|
||||
g.append("rect")
|
||||
.attr("x", d => x(d))
|
||||
.attr("y", d => y(d))
|
||||
|
|
@ -404,7 +406,9 @@ window.Military = (function () {
|
|||
.attr("id", "regiment" + stateId + "-" + reg.i)
|
||||
.attr("data-name", reg.name)
|
||||
.attr("data-state", stateId)
|
||||
.attr("data-id", reg.i);
|
||||
.attr("data-id", reg.i)
|
||||
.attr("transform", `rotate(${reg.angle || 0})`)
|
||||
.attr("transform-origin", `${reg.x}px ${reg.y}px`);
|
||||
g.append("rect").attr("x", x1).attr("y", y1).attr("width", w).attr("height", h);
|
||||
g.append("text").attr("x", reg.x).attr("y", reg.y).text(getTotal(reg));
|
||||
g.append("rect")
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ window.Names = (function () {
|
|||
{name: "Iranian", i: 24, min: 5, max: 11, d: "", m: .1, b: "Abali,Abrisham,Absard,Abuzeydabad,Afus,Alavicheh,Alikosh,Amol,Anarak,Anbar,Andisheh,Anshan,Aran,Ardabil,Arderica,Ardestan,Arjomand,Asgaran,Asgharabad,Ashian,Awan,Babajan,Badrud,Bafran,Baghestan,Baghshad,Bahadoran,Baharan Shahr,Baharestan,Bakun,Bam,Baqershahr,Barzok,Bastam,Behistun,Bitistar,Bumahen,Bushehr,Chadegan,Chahardangeh,Chamgardan,Chermahin,Choghabonut,Chugan,Damaneh,Damavand,Darabgard,Daran,Dastgerd,Dehaq,Dehaqan,Dezful,Dizicheh,Dorcheh,Dowlatabad,Duruntash,Ecbatana,Eslamshahr,Estakhr,Ezhiyeh,Falavarjan,Farrokhi,Fasham,Ferdowsieh,Fereydunshahr,Ferunabad,Firuzkuh,Fuladshahr,Ganjdareh,Ganzak,Gaz,Geoy,Godin,Goldasht,Golestan,Golpayegan,Golshahr,Golshan,Gorgab,Guged,Habibabad,Hafshejan,Hajjifiruz,Hana,Harand,Hasanabad,Hasanlu,Hashtgerd,Hecatompylos,Hormirzad,Imanshahr,Isfahan,Jandaq,Javadabad,Jiroft,Jowsheqan ,Jowzdan,Kabnak,Kahrizak,Kahriz Sang,Kangavar,Karaj,Karkevand,Kashan,Kelishad,Kermanshah,Khaledabad,Khansar,Khorramabad,Khur,Khvorzuq,Kilan,Komeh,Komeshcheh,Konar,Kuhpayeh,Kul,Kushk,Lavasan,Laybid,Liyan,Lyan,Mahabad,Mahallat,Majlesi,Malard,Manzariyeh,Marlik,Meshkat,Meymeh,Miandasht,Mish,Mobarakeh,Nahavand,Nain,Najafabad,Naqshe,Narezzash,Nasimshahr,Nasirshahr,Nasrabad,Natanz,Neyasar,Nikabad,Nimvar,Nushabad,Pakdasht,Parand,Pardis,Parsa,Pasargadai,Patigrabana,Pir Bakran,Pishva,Qahderijan,Qahjaverestan,Qamsar,Qarchak,Qods,Rabat,Ray-shahr,Rezvanshahr,Rhages,Robat Karim,Rozveh,Rudehen,Sabashahr,Safadasht,Sagzi,Salehieh,Sandal,Sarvestan,Sedeh,Sefidshahr,Semirom,Semnan,Shadpurabad,Shah,Shahdad,Shahedshahr,Shahin,Shahpour,Shahr,Shahreza,Shahriar,Sharifabad,Shemshak,Shiraz,Shushan,Shushtar,Sialk,Sin,Sukhteh,Tabas,Tabriz,Takhte,Talkhuncheh,Talli,Tarq,Temukan,Tepe,Tiran,Tudeshk,Tureng,Urmia,Vahidieh,Vahrkana,Vanak,Varamin,Varnamkhast,Varzaneh,Vazvan,Yahya,Yarim,Yasuj,Zarrin Shahr,Zavareh,Zayandeh,Zazeran,Ziar,Zibashahr,Zranka"},
|
||||
{name: "Hawaiian", i: 25, min: 5, max: 10, d: "auo", m: 1, b: "Aapueo,Ahoa,Ahuakaio,Ahupau,Alaakua,Alae,Alaeloa,Alamihi,Aleamai,Alena,Alio,Aupokopoko,Halakaa,Haleu,Haliimaile,Hamoa,Hanakaoo,Hanaulu,Hanawana,Hanehoi,Haou,Hikiaupea,Hokuula,Honohina,Honokahua,Honokeana,Honokohau,Honolulu,Honomaele,Hononana,Honopou,Hoolawa,Huelo,Kaalaea,Kaapahu,Kaeo,Kahalehili,Kahana,Kahuai,Kailua,Kainehe,Kakalahale,Kakanoni,Kalenanui,Kaleoaihe,Kalialinui,Kalihi,Kalimaohe,Kaloi,Kamani,Kamehame,Kanahena,Kaniaula,Kaonoulu,Kapaloa,Kapohue,Kapuaikini,Kapunakea,Kauau,Kaulalo,Kaulanamoa,Kauluohana,Kaumakani,Kaumanu,Kaunauhane,Kaupakulua,Kawaloa,Keaa,Keaaula,Keahua,Keahuapono,Kealahou,Keanae,Keauhou,Kelawea,Keokea,Keopuka,Kikoo,Kipapa,Koakupuna,Koali,Kolokolo,Kopili,Kou,Kualapa,Kuhiwa,Kuholilea,Kuhua,Kuia,Kuikui,Kukoae,Kukohia,Kukuiaeo,Kukuipuka,Kukuiula,Kulahuhu,Lapakea,Lapueo,Launiupoko,Lole,Maalo,Mahinahina,Mailepai,Makaakini,Makaalae,Makaehu,Makaiwa,Makaliua,Makapipi,Makapuu,Maluaka,Manawainui,Mehamenui,Moalii,Moanui,Mohopili,Mokae,Mokuia,Mokupapa,Mooiki,Mooloa,Moomuku,Muolea,Nakaaha,Nakalepo,Nakaohu,Nakapehu,Nakula,Napili,Niniau,Nuu,Oloewa,Olowalu,Omaopio,Onau,Onouli,Opaeula,Opana,Opikoula,Paakea,Paeahu,Paehala,Paeohi,Pahoa,Paia,Pakakia,Palauea,Palemo,Paniau,Papaaea,Papaanui,Papaauhau,Papaka,Papauluana,Pauku,Paunau,Pauwalu,Pauwela,Pohakanele,Polaiki,Polanui,Polapola,Poopoo,Poponui,Poupouwela,Puahoowali,Puakea,Puako,Pualaea,Puehuehu,Pueokauiki,Pukaauhuhu,Pukuilua,Pulehu,Puolua,Puou,Puuhaehae,Puuiki,Puuki,Puulani,Puunau,Puuomaile,Uaoa,Uhao,Ukumehame,Ulaino,Ulumalu,Wahikuli,Waianae,Waianu,Waiawa,Waiehu,Waieli,Waikapu,Wailamoa,Wailaulau,Wainee,Waiohole,Waiohonu,Waiohuli,Waiokama,Waiokila,Waiopai,Waiopua,Waipao,Waipionui,Waipouli"},
|
||||
{name: "Karnataka", i: 26, min: 5, max: 11, d: "tnl", m: 0, b: "Adityapatna,Adyar,Afzalpur,Aland,Alnavar,Alur,Ambikanagara,Anekal,Ankola,Annigeri,Arkalgud,Arsikere,Athni,Aurad,Badami,Bagalkot,Bagepalli,Bail,Bajpe,Bangalore,Bangarapet,Bankapura,Bannur,Bantval,Basavakalyan,Basavana,Belgaum,Beltangadi,Belur,Bhadravati,Bhalki,Bhatkal,Bhimarayanagudi,Bidar,Bijapur,Bilgi,Birur,Bommasandra,Byadgi,Challakere,Chamarajanagar,Channagiri,Channapatna,Channarayapatna,Chik,Chikmagalur,Chiknayakanhalli,Chikodi,Chincholi,Chintamani,Chitapur,Chitgoppa,Chitradurga,Dandeli,Dargajogihalli,Devadurga,Devanahalli,Dod,Donimalai,Gadag,Gajendragarh,Gangawati,Gauribidanur,Gokak,Gonikoppal,Gubbi,Gudibanda,Gulbarga,Guledgudda,Gundlupet,Gurmatkal,Haliyal,Hangal,Harapanahalli,Harihar,Hassan,Hatti,Haveri,Hebbagodi,Heggadadevankote,Hirekerur,Holalkere,Hole,Homnabad,Honavar,Honnali,Hoovina,Hosakote,Hosanagara,Hosdurga,Hospet,Hubli,Hukeri,Hungund,Hunsur,Ilkal,Indi,Jagalur,Jamkhandi,Jevargi,Jog,Kadigenahalli,Kadur,Kalghatgi,Kamalapuram,Kampli,Kanakapura,Karkal,Karwar,Khanapur,Kodiyal,Kolar,Kollegal,Konnur,Koppa,Koppal,Koratagere,Kotturu,Krishnarajanagara,Krishnarajasagara,Krishnarajpet,Kudchi,Kudligi,Kudremukh,Kumta,Kundapura,Kundgol,Kunigal,Kurgunta,Kushalnagar,Kushtagi,Lakshmeshwar,Lingsugur,Londa,Maddur,Madhugiri,Madikeri,Mahalingpur,Malavalli,Mallar,Malur,Mandya,Mangalore,Manvi,Molakalmuru,Mudalgi,Mudbidri,Muddebihal,Mudgal,Mudhol,Mudigere,Mulbagal,Mulgund,Mulki,Mulur,Mundargi,Mundgod,Munirabad,Mysore,Nagamangala,Nanjangud,Narasimharajapura,Naregal,Nargund,Navalgund,Nipani,Pandavapura,Pavagada,Piriyapatna,Pudu,Puttur,Rabkavi,Raichur,Ramanagaram,Ramdurg,Ranibennur,Raybag,Robertson,Ron,Sadalgi,Sagar,Sakleshpur,Saligram,Sandur,Sankeshwar,Saundatti,Savanur,Sedam,Shahabad,Shahpur,Shaktinagar,Shiggaon,Shikarpur,Shirhatti,Shorapur,Shrirangapattana,Siddapur,Sidlaghatta,Sindgi,Sindhnur,Sira,Siralkoppa,Sirsi,Siruguppa,Somvarpet,Sorab,Sringeri,Srinivaspur,Sulya,Talikota,Tarikere,Tekkalakote,Terdal,Thumbe,Tiptur,Tirthahalli,Tirumakudal,Tumkur,Turuvekere,Udupi,Vijayapura,Wadi,Yadgir,Yelandur,Yelbarga,Yellapur,Yenagudde"},
|
||||
{name: "Quechua", i: 27, min: 6, max: 12, d: "l", m: 0, b: "Alpahuaycco,Anchihuay,Anqea,Apurimac,Arequipa,Atahuallpa,Atawalpa,Atico,Ayacucho,Ayahuanco,Ayllu,Cajamarca,Canayre,Canchacancha,Carhuac,Carhuacatac,Cashan,Caullaraju,Caxamalca,Cayesh,Ccahuasno,Ccarhuacc,Ccopayoc,Chacchapunta,Chacraraju,Challhuamayo,Champara,Chanchan,Chekiacraju,Chillihua,Chinchey,Chontah,Chopicalqui,Chucuito,Chuito,Chullo,Chumpi,Chuncho,Chupahuacho,Chuquiapo,Chuquisaca,Churup,Cocapata,Cochabamba,Cojup,Collota,Conococha,Corihuayrachina,Cuchoquesera,Cusichaca,Haika,Hanpiq,Hatun,Haywarisqa,Huaca,Huachinga,Hualcan,Hualchancca,Huamanga,Huamashraju,Huancarhuas,Huandoy,Huantsan,Huanupampa,Huarmihuanusca,Huascaran,Huaylas,Huayllabamba,Huayrana,Huaytara,Huichajanca,Huinayhuayna,Huinche,Huinioch,Illiasca,Intipunku,Iquicha,Ishinca,Jahuacocha,Jirishanca,Juli,Jurau,Kakananpunta,Kamasqa,Karpay,Kausay,Khuya,Kuelap,Lanccochayocc,Llaca,Llactapata,Llanganuco,Llaqta,Lloqllasca,Llupachayoc,Luricocha,Machu,Mallku,Matarraju,Mechecc,Mikhuy,Milluacocha,Morochuco,Munay,Ocshapalca,Ollantaytambo,Oroccahua,Oronccoy,Oyolo,Pacamayo,Pacaycasa.Carapo,Paccharaju,Pachacamac,Pachakamaq,Pachakuteq,Pachakuti,Pachamama,Paititi,Pajaten,Palcaraju,Pallccas,Pampa,Panaka,Paqarina,Paqo,Parap,Paria,Patahuasi,Patallacta,Patibamba,Pisac,Pisco,Pongos,Pucacolpa,Pucahirca,Pucaranra,Pumatambo,Puscanturpa,Putaca,Puyupatamarca,Qawaq,Qayqa,Qochamoqo,Qollana,Qorihuayrachina,Qorimoqo,Qotupuquio,Quenuaracra,Queshque,Quillcayhuanca,Quillya,Quitaracsa,Quitaraju,Qusqu,Rajucolta,Rajutakanan,Rajutuna,Ranrahirca,Ranrapalca,Raria,Rasac,Rimarima,Riobamba,Runkuracay,Rurec,Sacsa,Sacsamarca,Saiwa,Sarapo,Sayacmarca,Sayripata,Sinakara,Sonccopa,Taripaypacha,Taulliraju,Tawantinsuyu,Taytanchis,Tiwanaku,Tocllaraju,Tsacra,Tuco,Tucubamba,Tullparaju,Tumbes,Uchuraccay,Uchuraqay,Ulta,Urihuana,Uruashraju,Vallunaraju,Vilcabamba,Wacho,Wankawillka,Wayra,Yachay,Yahuarraju,Yanamarey,Yanaqucha,Yanesha,Yerupaja"},
|
||||
{name: "Quechua", i: 27, min: 6, max: 12, d: "l", m: 0, b: "Alpahuaycco,Anchihuay,Anqea,Apurimac,Arequipa,Atahuallpa,Atawalpa,Atico,Ayacucho,Ayahuanco,Ayllu,Cajamarca,Canayre,Canchacancha,Carapo,Carhuac,Carhuacatac,Cashan,Caullaraju,Caxamalca,Cayesh,Ccahuasno,Ccarhuacc,Ccopayoc,Chacchapunta,Chacraraju,Challhuamayo,Champara,Chanchan,Chekiacraju,Chillihua,Chinchey,Chontah,Chopicalqui,Chucuito,Chuito,Chullo,Chumpi,Chuncho,Chupahuacho,Chuquiapo,Chuquisaca,Churup,Cocapata,Cochabamba,Cojup,Collota,Conococha,Corihuayrachina,Cuchoquesera,Cusichaca,Haika,Hanpiq,Hatun,Haywarisqa,Huaca,Huachinga,Hualcan,Hualchancca,Huamanga,Huamashraju,Huancarhuas,Huandoy,Huantsan,Huanupampa,Huarmihuanusca,Huascaran,Huaylas,Huayllabamba,Huayrana,Huaytara,Huichajanca,Huinayhuayna,Huinche,Huinioch,Illiasca,Intipunku,Iquicha,Ishinca,Jahuacocha,Jirishanca,Juli,Jurau,Kakananpunta,Kamasqa,Karpay,Kausay,Khuya,Kuelap,Lanccochayocc,Llaca,Llactapata,Llanganuco,Llaqta,Lloqllasca,Llupachayoc,Luricocha,Machu,Mallku,Matarraju,Mechecc,Mikhuy,Milluacocha,Morochuco,Munay,Ocshapalca,Ollantaytambo,Oroccahua,Oronccoy,Oyolo,Pacamayo,Pacaycasa,Paccharaju,Pachacamac,Pachakamaq,Pachakuteq,Pachakuti,Pachamama,Paititi,Pajaten,Palcaraju,Pallccas,Pampa,Panaka,Paqarina,Paqo,Parap,Paria,Patahuasi,Patallacta,Patibamba,Pisac,Pisco,Pongos,Pucacolpa,Pucahirca,Pucaranra,Pumatambo,Puscanturpa,Putaca,Puyupatamarca,Qawaq,Qayqa,Qochamoqo,Qollana,Qorihuayrachina,Qorimoqo,Qotupuquio,Quenuaracra,Queshque,Quillcayhuanca,Quillya,Quitaracsa,Quitaraju,Qusqu,Rajucolta,Rajutakanan,Rajutuna,Ranrahirca,Ranrapalca,Raria,Rasac,Rimarima,Riobamba,Runkuracay,Rurec,Sacsa,Sacsamarca,Saiwa,Sarapo,Sayacmarca,Sayripata,Sinakara,Sonccopa,Taripaypacha,Taulliraju,Tawantinsuyu,Taytanchis,Tiwanaku,Tocllaraju,Tsacra,Tuco,Tucubamba,Tullparaju,Tumbes,Uchuraccay,Uchuraqay,Ulta,Urihuana,Uruashraju,Vallunaraju,Vilcabamba,Wacho,Wankawillka,Wayra,Yachay,Yahuarraju,Yanamarey,Yanaqucha,Yanesha,Yerupaja"},
|
||||
{name: "Swahili", i: 28, min: 4, max: 9, d: "", m: 0, b: "Abim,Adjumani,Alebtong,Amolatar,Amuru,Apac,Arua,Arusha,Babati,Baragoi,Bombo,Budaka,Bugembe,Bugiri,Buikwe,Bukedea,Bukoba,Bukomansimbi,Bukungu,Buliisa,Bundibugyo,Bungoma,Busembatya,Bushenyi,Busia,Busolwe,Butaleja,Butambala,Butere,Buwenge,Buyende,Dadaab,Dodoma,Dokolo,Eldoret,Elegu,Emali,Embu,Entebbe,Garissa,Gede,Gulu,Handeni,Hima,Hoima,Hola,Ibanda,Iganga,Iringa,Isingiro,Isiolo,Jinja,Kaabong,Kabuyanda,Kabwohe,Kagadi,Kajiado,Kakinga,Kakiri,Kakuma,Kalangala,Kaliro,Kalongo,Kalungu,Kampala,Kamwenge,Kanungu,Kapchorwa,Kasese,Kasulu,Katakwi,Kayunga,Keroka,Kiambu,Kibaale,Kibaha,Kibingo,Kibwezi,Kigoma,Kihiihi,Kilifi,Kiruhura,Kiryandongo,Kisii,Kisoro,Kisumu,Kitale,Kitgum,Kitui,Koboko,Korogwe,Kotido,Kumi,Kyazanga,Kyegegwa,Kyenjojo,Kyotera,Lamu,Langata,Lindi,Lodwar,Lokichoggio,Londiani,Loyangalani,Lugazi,Lukaya,Luweero,Lwakhakha,Lwengo,Lyantonde,Machakos,Mafinga,Makambako,Makindu,Malaba,Malindi,Manafwa,Mandera,Marsabit,Masaka,Masindi,Masulita,Matugga,Mayuge,Mbale,Mbarara,Mbeya,Meru,Mitooma,Mityana,Mombasa,Morogoro,Moroto,Moyale,Moyo,Mpanda,Mpigi,Mpondwe,Mtwara,Mubende,Mukono,Muranga,Musoma,Mutomo,Mutukula,Mwanza,Nagongera,Nairobi,Naivasha,Nakapiripirit,Nakaseke,Nakasongola,Nakuru,Namanga,Namayingo,Namutumba,Nansana,Nanyuki,Narok,Naromoru,Nebbi,Ngora,Njeru,Njombe,Nkokonjeru,Ntungamo,Nyahururu,Nyeri,Oyam,Pader,Paidha,Pakwach,Pallisa,Rakai,Ruiru,Rukungiri,Rwimi,Sanga,Sembabule,Shimoni,Shinyanga,Singida,Sironko,Songea,Soroti,Ssabagabo,Sumbawanga,Tabora,Takaungu,Tanga,Thika,Tororo,Tunduma,Vihiga,Voi,Wajir,Wakiso,Watamu,Webuye,Wobulenzi,Wote,Wundanyi,Yumbe,Zanzibar"},
|
||||
{name: "Vietnamese", i: 29, min: 3, max: 12, d: "", m: 1, b: "An Giang,Anh Son,An Khe,An Nhon,Ayun Pa,Bac Giang,Bac Kan,Bac Lieu,Bac Ninh,Ba Don,Bao Loc,Ba Ria,Ba Ria-Vung Tau,Ba Thuoc,Ben Cat,Ben Tre,Bien Hoa,Bim Son,Binh Dinh,Binh Duong,Binh Long,Binh Minh,Binh Phuoc,Binh Thuan,Buon Ho,Buon Ma Thuot,Cai Lay,Ca Mau,Cam Khe,Cam Pha,Cam Ranh,Cam Thuy,Can Tho,Cao Bang,Cao Lanh,Cao Phong,Chau Doc,Chi Linh,Con Cuong,Cua Lo,Da Bac,Dak Lak,Da Lat,Da Nang,Di An,Dien Ban,Dien Bien,Dien Bien Phu,Dien Chau,Do Luong,Dong Ha,Dong Hoi,Dong Trieu,Duc Pho,Duyen Hai,Duy Tien,Gia Lai,Gia Nghia,Gia Rai,Go Cong,Ha Giang,Ha Hoa,Hai Duong,Hai Phong,Ha Long,Ha Nam,Ha Noi,Ha Tinh,Ha Trung,Hau Giang,Hoa Binh,Hoang Mai,Hoa Thanh,Ho Chi Minh,Hoi An,Hong Linh,Hong Ngu,Hue,Hung Nguyen,Hung Yen,Huong Thuy,Huong Tra,Khanh Hoa,Kien Tuong,Kim Boi,Kinh Mon,Kon Tum,Ky Anh,Ky Son,Lac Son,Lac Thuy,La Gi,Lai Chau,Lam Thao,Lang Chanh,Lang Son,Lao Cai,Long An,Long Khanh,Long My,Long Xuyen,Luong Son,Mai Chau,Mong Cai,Muong Lat,Muong Lay,My Hao,My Tho,Nam Dan,Nam Dinh,Nga Bay,Nga Nam,Nga Son,Nghe An,Nghia Dan,Nghia Lo,Nghi Loc,Nghi Son,Ngoc Lac,Nha Trang,Nhu Thanh,Nhu Xuan,Ninh Binh,Ninh Hoa,Nong Cong,Phan Rang Thap Cham,Phan Thiet,Pho Yen,Phu Ly,Phu My,Phu Ninh,Phuoc Long,Phu Tho,Phu Yen,Pleiku,Quang Binh,Quang Nam,Quang Ngai,Quang Ninh,Quang Tri,Quang Xuong,Quang Yen,Quan Hoa,Quan Son,Que Phong,Quy Chau,Quy Hop,Quynh Luu,Quy Nhon,Rach Gia,Sa Dec,Sai Gon,Sam Son,Sa Pa,Soc Trang,Song Cau,Song Cong,Son La,Son Tay,Tam Diep,Tam Ky,Tan An,Tan Chau,Tan Ky,Tan Lac,Tan Son,Tan Uyen,Tay Ninh,Thach Thanh,Thai Binh,Thai Hoa,Thai Nguyen,Thanh Chuong,Thanh Hoa,Thieu Hoa,Thuan An,Thua Thien-Hue,Thu Dau Mot,Thu Duc,Thuong Xuan,Tien Giang,Trang Bang,Tra Vinh,Trieu Son,Tu Son,Tuyen Quang,Tuy Hoa,Uong Bi,Viet Tri,Vinh,Vinh Chau,Vinh Loc,Vinh Long,Vinh Yen,Vi Thanh,Vung Tau,Yen Bai,Yen Dinh,Yen Thanh,Yen Thuy"},
|
||||
{name: "Cantonese", i: 30, min: 5, max: 11, d: "", m: 0, b: "Chaiwan,Chingchung,Chinghoi,Chingsen,Chingshing,Chiunam,Chiuon,Chiuyeung,Chiyuen,Choihung,Chuehoi,Chuiman,Chungfu,Chungsan,Chunguktsuen,Dakhing,Daopo,Daumun,Dingwu,Dinpak,Donggun,Dongyuen,Duenchau,Fachau,Fanling,Fatgong,Fatshan,Fotan,Fuktien,Fumun,Funggong,Funghoi,Fungshun,Fungtei,Gamtin,Gochau,Goming,Gonghoi,Gongshing,Goyiu,Hanghau,Hangmei,Hengon,Heungchau,Heunggong,Heungkiu,Hingning,Hohfuktong,Hoichue,Hoifung,Hoiping,Hokong,Hokshan,Hoyuen,Hunghom,Hungshuikiu,Jiuling,Kamsheung,Kamwan,Kaulongtong,Keilun,Kinon,Kinsang,Kityeung,Kongmun,Kukgong,Kwaifong,Kwaihing,Kwongchau,Kwongling,Kwongming,Kwuntong,Laichikok,Laiking,Laiwan,Lamtei,Lamtin,Leitung,Leungking,Limkong,Linping,Linshan,Loding,Lokcheong,Lokfu,Longchuen,Longgong,Longmun,Longping,Longwa,Longwu,Lowu,Luichau,Lukfung,Lukho,Lungmun,Macheung,Maliushui,Maonshan,Mauming,Maunam,Meifoo,Mingkum,Mogong,Mongkok,Muichau,Muigong,Muiyuen,Naiwai,Namcheong,Namhoi,Namhong,Namsha,Nganwai,Ngautaukok,Ngchuen,Ngwa,Onting,Pakwun,Paotoishan,Pingshan,Pingyuen,Poklo,Pongon,Poning,Potau,Puito,Punyue,Saiwanho,Saiyingpun,Samshing,Samshui,Samtsen,Samyuenlei,Sanfung,Sanhing,Sanhui,Sanwai,Seiwui,Shamshuipo,Shanmei,Shantau,Shauking,Shekmun,Shekpai,Sheungshui,Shingkui,Shiuhing,Shundak,Shunyi,Shupinwai,Simshing,Siuhei,Siuhong,Siukwan,Siulun,Suikai,Taihing,Taikoo,Taipo,Taishuihang,Taiwai,Taiwohau,Tinhau,Tinshuiwai,Tiukengleng,Toishan,Tongfong,Tonglowan,Tsakyoochung,Tsamgong,Tsangshing,Tseungkwano,Tsimshatsui,Tsinggong,Tsingshantsuen,Tsingwun,Tsingyi,Tsingyuen,Tsiuchau,Tsuenshekshan,Tsuenwan,Tuenmun,Tungchung,Waichap,Waichau,Waidong,Wailoi,Waishing,Waiyeung,Wanchai,Wanfau,Wanshing,Wingon,Wongpo,Wongtaisin,Woping,Wukaisha,Yano,Yaumatei,Yautong,Yenfa,Yeungchun,Yeungdong,Yeungsai,Yeungshan,Yimtin,Yingdak,Yiuping,Yongshing,Yongyuen,Yuenlong,Yuenshing,Yuetsau,Yuknam,Yunping"},
|
||||
|
|
|
|||
|
|
@ -223,18 +223,19 @@ function addBurgsGroup(group) {
|
|||
}
|
||||
|
||||
function removeBurg(id) {
|
||||
const label = document.querySelector("#burgLabels [data-id='" + id + "']");
|
||||
const icon = document.querySelector("#burgIcons [data-id='" + id + "']");
|
||||
const anchor = document.querySelector("#anchors [data-id='" + id + "']");
|
||||
if (label) label.remove();
|
||||
if (icon) icon.remove();
|
||||
if (anchor) anchor.remove();
|
||||
document.querySelector("#burgLabels [data-id='" + id + "']")?.remove();
|
||||
document.querySelector("#burgIcons [data-id='" + id + "']")?.remove();
|
||||
document.querySelector("#anchors [data-id='" + id + "']")?.remove();
|
||||
|
||||
const cells = pack.cells;
|
||||
const burg = pack.burgs[id];
|
||||
|
||||
const cells = pack.cells,
|
||||
burg = pack.burgs[id];
|
||||
burg.removed = true;
|
||||
cells.burg[burg.cell] = 0;
|
||||
|
||||
const noteId = notes.findIndex(note => note.id === `burg${id}`);
|
||||
if (noteId !== -1) notes.splice(noteId, 1);
|
||||
|
||||
if (burg.coa) {
|
||||
const coaId = "burgCOA" + id;
|
||||
if (byId(coaId)) byId(coaId).remove();
|
||||
|
|
@ -1224,7 +1225,7 @@ function refreshAllEditors() {
|
|||
// dynamically loaded editors
|
||||
async function editStates() {
|
||||
if (customization) return;
|
||||
const Editor = await import("../dynamic/editors/states-editor.js?v=1.96.06");
|
||||
const Editor = await import("../dynamic/editors/states-editor.js?v=1.97.06");
|
||||
Editor.open();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,8 +109,8 @@ function showElevationProfile(data, routeLen, isRiver) {
|
|||
draw();
|
||||
|
||||
function downloadCSV() {
|
||||
let data =
|
||||
"Point,X,Y,Cell,Height,Height value,Population,Burg,Burg population,Biome,Biome color,Culture,Culture color,Religion,Religion color,Province,Province color,State,State color\n"; // headers
|
||||
let csv =
|
||||
"Id,x,y,lat,lon,Cell,Height,Height value,Population,Burg,Burg population,Biome,Biome color,Culture,Culture color,Religion,Religion color,Province,Province color,State,State color\n"; // headers
|
||||
|
||||
for (let k = 0; k < chartData.points.length; k++) {
|
||||
let cell = chartData.cell[k];
|
||||
|
|
@ -123,35 +123,39 @@ function showElevationProfile(data, routeLen, isRiver) {
|
|||
let pop = pack.cells.pop[cell];
|
||||
let h = pack.cells.h[cell];
|
||||
|
||||
data += k + 1 + ",";
|
||||
data += chartData.points[k][0] + ",";
|
||||
data += chartData.points[k][1] + ",";
|
||||
data += cell + ",";
|
||||
data += getHeight(h) + ",";
|
||||
data += h + ",";
|
||||
data += rn(pop * populationRate) + ",";
|
||||
csv += k + 1 + ",";
|
||||
const [x, y] = pack.cells.p[data[k]];
|
||||
csv += x + ",";
|
||||
csv += y + ",";
|
||||
const lat = getLatitude(y, 2);
|
||||
const lon = getLongitude(x, 2);
|
||||
csv += lat + ",";
|
||||
csv += lon + ",";
|
||||
csv += cell + ",";
|
||||
csv += getHeight(h) + ",";
|
||||
csv += h + ",";
|
||||
csv += rn(pop * populationRate) + ",";
|
||||
if (burg) {
|
||||
data += pack.burgs[burg].name + ",";
|
||||
data += pack.burgs[burg].population * populationRate * urbanization + ",";
|
||||
csv += pack.burgs[burg].name + ",";
|
||||
csv += pack.burgs[burg].population * populationRate * urbanization + ",";
|
||||
} else {
|
||||
data += ",0,";
|
||||
csv += ",0,";
|
||||
}
|
||||
data += biomesData.name[biome] + ",";
|
||||
data += biomesData.color[biome] + ",";
|
||||
data += pack.cultures[culture].name + ",";
|
||||
data += pack.cultures[culture].color + ",";
|
||||
data += pack.religions[religion].name + ",";
|
||||
data += pack.religions[religion].color + ",";
|
||||
data += pack.provinces[province].name + ",";
|
||||
data += pack.provinces[province].color + ",";
|
||||
data += pack.states[state].name + ",";
|
||||
data += pack.states[state].color + ",";
|
||||
|
||||
data = data + "\n";
|
||||
csv += biomesData.name[biome] + ",";
|
||||
csv += biomesData.color[biome] + ",";
|
||||
csv += pack.cultures[culture].name + ",";
|
||||
csv += pack.cultures[culture].color + ",";
|
||||
csv += pack.religions[religion].name + ",";
|
||||
csv += pack.religions[religion].color + ",";
|
||||
csv += pack.provinces[province].name + ",";
|
||||
csv += pack.provinces[province].color + ",";
|
||||
csv += pack.states[state].name + ",";
|
||||
csv += pack.states[state].color + ",";
|
||||
csv += "\n";
|
||||
}
|
||||
|
||||
const name = getFileName("elevation profile") + ".csv";
|
||||
downloadFile(data, name);
|
||||
downloadFile(csv, name);
|
||||
}
|
||||
|
||||
function draw() {
|
||||
|
|
@ -335,10 +339,7 @@ function showElevationProfile(data, routeLen, isRiver) {
|
|||
.attr("transform", "translate(" + xOffset + "," + parseInt(chartHeight + +yOffset + 20) + ")")
|
||||
.call(xAxis)
|
||||
.selectAll("text")
|
||||
.style("text-anchor", "center")
|
||||
.attr("transform", function (d) {
|
||||
return "rotate(0)"; // used to rotate labels, - anti-clockwise, + clockwise
|
||||
});
|
||||
.style("text-anchor", "center");
|
||||
|
||||
chart
|
||||
.append("g")
|
||||
|
|
|
|||
|
|
@ -1525,10 +1525,6 @@ function toggleCompass(event) {
|
|||
if (!layerIsOn("toggleCompass")) {
|
||||
turnButtonOn("toggleCompass");
|
||||
$("#compass").fadeIn();
|
||||
if (!compass.selectAll("*").size()) {
|
||||
compass.append("use").attr("xlink:href", "#rose");
|
||||
shiftCompass();
|
||||
}
|
||||
if (event && isCtrlClick(event)) editStyle("compass");
|
||||
} else {
|
||||
if (event && isCtrlClick(event)) {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,9 @@ function overviewMilitary() {
|
|||
for (const u of options.military) {
|
||||
const label = capitalize(u.name.replace(/_/g, " "));
|
||||
insert(
|
||||
`<div data-tip="State ${u.name} units number. Click to sort" class="sortable removable" data-sortby="${u.name}">${label} </div>`
|
||||
`<div data-tip="State ${
|
||||
u.name
|
||||
} units number. Click to sort" class="sortable removable" data-sortby="${u.name.toLowerCase()}">${label} </div>`
|
||||
);
|
||||
}
|
||||
header.querySelectorAll(".removable").forEach(function (e) {
|
||||
|
|
@ -77,7 +79,7 @@ function overviewMilitary() {
|
|||
const total = options.military.reduce((s, u) => s + getForces(u) * u.crew, 0);
|
||||
const rate = (total / population) * 100;
|
||||
|
||||
const sortData = options.military.map(u => `data-${u.name}="${getForces(u)}"`).join(" ");
|
||||
const sortData = options.military.map(u => `data-${u.name.toLowerCase()}="${getForces(u)}"`).join(" ");
|
||||
const lineData = options.military
|
||||
.map(u => `<div data-type="${u.name}" data-tip="State ${u.name} units number">${getForces(u)}</div>`)
|
||||
.join(" ");
|
||||
|
|
@ -469,7 +471,7 @@ function overviewMilitary() {
|
|||
body.querySelectorAll(":scope > div").forEach(function (el) {
|
||||
data += el.dataset.id + ",";
|
||||
data += el.dataset.state + ",";
|
||||
data += units.map(u => el.dataset[u]).join(",") + ",";
|
||||
data += units.map(u => el.dataset[u.toLowerCase()]).join(",") + ",";
|
||||
data += el.dataset.total + ",";
|
||||
data += el.dataset.population + ",";
|
||||
data += rn(el.dataset.rate, 2) + "%,";
|
||||
|
|
|
|||
|
|
@ -79,11 +79,13 @@ function editNotes(id, name) {
|
|||
}
|
||||
|
||||
if (window.tinymce) {
|
||||
window.tinymce._setBaseUrl("https://azgaar.github.io/Fantasy-Map-Generator/libs/tinymce");
|
||||
tinymce.init({
|
||||
license_key: "gpl",
|
||||
selector: "#notesLegend",
|
||||
height: "90%",
|
||||
menubar: false,
|
||||
plugins: `autolink lists link charmap print code fullscreen image link media table paste hr wordcount`,
|
||||
plugins: `autolink lists link charmap code fullscreen image link media table wordcount`,
|
||||
toolbar: `code | undo redo | removeformat | bold italic strikethrough | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image media table | fontselect fontsizeselect | blockquote hr charmap | print fullscreen`,
|
||||
media_alt_source: false,
|
||||
media_poster: false,
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ document
|
|||
|
||||
// show popup with a list of Patreon supportes (updated manually)
|
||||
async function showSupporters() {
|
||||
const {supporters} = await import("../dynamic/supporters.js?v=1.93.08");
|
||||
const {supporters} = await import("../dynamic/supporters.js?v=1.97.14");
|
||||
const list = supporters.split("\n").sort();
|
||||
const columns = window.innerWidth < 800 ? 2 : 5;
|
||||
|
||||
|
|
@ -119,9 +119,9 @@ function updateOutputToFollowInput(ev) {
|
|||
|
||||
// Option listeners
|
||||
const optionsContent = byId("optionsContent");
|
||||
optionsContent.addEventListener("input", function (event) {
|
||||
const id = event.target.id;
|
||||
const value = event.target.value;
|
||||
|
||||
optionsContent.addEventListener("input", event => {
|
||||
const {id, value} = event.target;
|
||||
if (id === "mapWidthInput" || id === "mapHeightInput") mapSizeInputChange();
|
||||
else if (id === "pointsInput") changeCellsDensity(+value);
|
||||
else if (id === "culturesSet") changeCultureSet();
|
||||
|
|
@ -133,10 +133,8 @@ optionsContent.addEventListener("input", function (event) {
|
|||
else if (id === "transparencyInput") changeDialogsTheme(themeColorInput.value, value);
|
||||
});
|
||||
|
||||
optionsContent.addEventListener("change", function (event) {
|
||||
const id = event.target.id;
|
||||
const value = event.target.value;
|
||||
|
||||
optionsContent.addEventListener("change", event => {
|
||||
const {id, value} = event.target;
|
||||
if (id === "zoomExtentMin" || id === "zoomExtentMax") changeZoomExtent(value);
|
||||
else if (id === "optionsSeed") generateMapWithSeed("seed change");
|
||||
else if (id === "uiSizeInput" || id === "uiSizeOutput") changeUiSize(value);
|
||||
|
|
@ -146,8 +144,8 @@ optionsContent.addEventListener("change", function (event) {
|
|||
else if (id === "stateLabelsModeInput") options.stateLabelsMode = value;
|
||||
});
|
||||
|
||||
optionsContent.addEventListener("click", function (event) {
|
||||
const id = event.target.id;
|
||||
optionsContent.addEventListener("click", event => {
|
||||
const {id} = event.target;
|
||||
if (id === "restoreDefaultCanvasSize") restoreDefaultCanvasSize();
|
||||
else if (id === "optionsMapHistory") showSeedHistoryDialog();
|
||||
else if (id === "optionsCopySeed") copyMapURL();
|
||||
|
|
@ -327,6 +325,7 @@ const cellsDensityMap = {
|
|||
};
|
||||
|
||||
function changeCellsDensity(value) {
|
||||
pointsInput.value = value;
|
||||
const cells = cellsDensityMap[value] || 1000;
|
||||
pointsInput.dataset.cells = cells;
|
||||
pointsOutputFormatted.value = getCellsDensityValue(cells);
|
||||
|
|
@ -536,6 +535,7 @@ function applyStoredOptions() {
|
|||
const key = localStorage.key(i);
|
||||
|
||||
if (key === "speakerVoice") continue;
|
||||
|
||||
const input = byId(key + "Input") || byId(key);
|
||||
const output = byId(key + "Output");
|
||||
|
||||
|
|
@ -544,6 +544,8 @@ function applyStoredOptions() {
|
|||
if (output) output.value = value;
|
||||
lock(key);
|
||||
|
||||
if (key === "points") changeCellsDensity(+value);
|
||||
|
||||
// add saved style presets to options
|
||||
if (key.slice(0, 5) === "style") applyOption(stylePreset, key, key.slice(5));
|
||||
}
|
||||
|
|
@ -581,6 +583,7 @@ function randomizeOptions() {
|
|||
const randomize = new URL(window.location.href).searchParams.get("options") === "default"; // ignore stored options
|
||||
|
||||
// 'Options' settings
|
||||
if (randomize || !locked("points")) changeCellsDensity(4); // reset to default, no need to randomize
|
||||
if (randomize || !locked("template")) randomizeHeightmapTemplate();
|
||||
if (randomize || !locked("regions")) regionsInput.value = regionsOutput.value = gauss(18, 5, 2, 30);
|
||||
if (randomize || !locked("provinces")) provincesInput.value = provincesOutput.value = gauss(20, 10, 20, 100);
|
||||
|
|
@ -774,7 +777,7 @@ function showExportPane() {
|
|||
}
|
||||
|
||||
async function exportToJson(type) {
|
||||
const {exportToJson} = await import("../dynamic/export-json.js?v=1.96.00");
|
||||
const {exportToJson} = await import("../dynamic/export-json.js?v=1.97.08");
|
||||
exportToJson(type);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ function editRegiment(selector) {
|
|||
armies.selectAll(":scope > g > g").call(d3.drag().on("drag", dragRegiment));
|
||||
elSelected = selector ? document.querySelector(selector) : d3.event.target.parentElement; // select g element
|
||||
if (!pack.states[elSelected.dataset.state]) return;
|
||||
if (!regiment()) return;
|
||||
updateRegimentData(regiment());
|
||||
if (!getRegiment()) return;
|
||||
updateRegimentData(getRegiment());
|
||||
drawBase();
|
||||
drawRotationControl();
|
||||
|
||||
$("#regimentEditor").dialog({
|
||||
title: "Edit Regiment",
|
||||
|
|
@ -37,8 +38,8 @@ function editRegiment(selector) {
|
|||
document.getElementById("regimentRemove").addEventListener("click", removeRegiment);
|
||||
|
||||
// get regiment data element
|
||||
function regiment() {
|
||||
return pack.states[elSelected.dataset.state].military.find(r => r.i == elSelected.dataset.id);
|
||||
function getRegiment() {
|
||||
return pack.states[elSelected.dataset.state]?.military.find(r => r.i == elSelected.dataset.id);
|
||||
}
|
||||
|
||||
function updateRegimentData(regiment) {
|
||||
|
|
@ -60,7 +61,7 @@ function editRegiment(selector) {
|
|||
}
|
||||
|
||||
function drawBase() {
|
||||
const reg = regiment();
|
||||
const reg = getRegiment();
|
||||
const clr = pack.states[elSelected.dataset.state].color;
|
||||
const base = viewbox
|
||||
.insert("g", "g#armies")
|
||||
|
|
@ -69,12 +70,8 @@ function editRegiment(selector) {
|
|||
.attr("stroke", "#000")
|
||||
.attr("cursor", "move");
|
||||
base
|
||||
.on("mouseenter", () => {
|
||||
tip("Regiment base. Drag to re-base the regiment", true);
|
||||
})
|
||||
.on("mouseleave", () => {
|
||||
tip("", true);
|
||||
});
|
||||
.on("mouseenter", () => tip("Regiment base. Drag to re-base the regiment", true))
|
||||
.on("mouseleave", () => tip("", true));
|
||||
|
||||
base
|
||||
.append("line")
|
||||
|
|
@ -92,8 +89,42 @@ function editRegiment(selector) {
|
|||
.call(d3.drag().on("drag", dragBase));
|
||||
}
|
||||
|
||||
function drawRotationControl() {
|
||||
const reg = getRegiment();
|
||||
const {x, width, y, height} = elSelected.getBBox();
|
||||
|
||||
debug
|
||||
.append("circle")
|
||||
.attr("id", "rotationControl")
|
||||
.attr("cx", x + width)
|
||||
.attr("cy", y + height / 2)
|
||||
.attr("r", 1)
|
||||
.attr("opacity", 1)
|
||||
.attr("fill", "yellow")
|
||||
.attr("stroke-width", 0.3)
|
||||
.attr("stroke", "black")
|
||||
.attr("cursor", "alias")
|
||||
.attr("transform", `rotate(${reg.angle || 0})`)
|
||||
.attr("transform-origin", `${reg.x}px ${reg.y}px`)
|
||||
.on("mouseenter", () => tip("Drag to rotate the regiment", true))
|
||||
.on("mouseleave", () => tip("", true))
|
||||
.call(d3.drag().on("start", rotateRegiment));
|
||||
}
|
||||
|
||||
function rotateRegiment() {
|
||||
const reg = getRegiment();
|
||||
|
||||
d3.event.on("drag", function () {
|
||||
const {x, y} = d3.event;
|
||||
const angle = rn(Math.atan2(y - reg.y, x - reg.x) * (180 / Math.PI), 2);
|
||||
elSelected.setAttribute("transform", `rotate(${angle})`);
|
||||
this.setAttribute("transform", `rotate(${angle})`);
|
||||
reg.angle = rn(angle, 2);
|
||||
});
|
||||
}
|
||||
|
||||
function changeType() {
|
||||
const reg = regiment();
|
||||
const reg = getRegiment();
|
||||
reg.n = +!reg.n;
|
||||
document.getElementById("regimentType").className = reg.n ? "icon-anchor" : "icon-users";
|
||||
|
||||
|
|
@ -110,11 +141,11 @@ function editRegiment(selector) {
|
|||
}
|
||||
|
||||
function changeName() {
|
||||
elSelected.dataset.name = regiment().name = this.value;
|
||||
elSelected.dataset.name = getRegiment().name = this.value;
|
||||
}
|
||||
|
||||
function restoreName() {
|
||||
const reg = regiment(),
|
||||
const reg = getRegiment(),
|
||||
regs = pack.states[elSelected.dataset.state].military;
|
||||
const name = Military.getName(reg, regs);
|
||||
elSelected.dataset.name = reg.name = document.getElementById("regimentName").value = name;
|
||||
|
|
@ -129,12 +160,12 @@ function editRegiment(selector) {
|
|||
|
||||
function changeEmblem() {
|
||||
const emblem = document.getElementById("regimentEmblem").value;
|
||||
regiment().icon = elSelected.querySelector(".regimentIcon").innerHTML = emblem;
|
||||
getRegiment().icon = elSelected.querySelector(".regimentIcon").innerHTML = emblem;
|
||||
}
|
||||
|
||||
function changeUnit() {
|
||||
const u = this.dataset.u;
|
||||
const reg = regiment();
|
||||
const reg = getRegiment();
|
||||
reg.u[u] = +this.value || 0;
|
||||
reg.a = d3.sum(Object.values(reg.u));
|
||||
elSelected.querySelector("text").innerHTML = Military.getTotal(reg);
|
||||
|
|
@ -143,7 +174,7 @@ function editRegiment(selector) {
|
|||
}
|
||||
|
||||
function splitRegiment() {
|
||||
const reg = regiment(),
|
||||
const reg = getRegiment(),
|
||||
u1 = reg.u;
|
||||
const state = +elSelected.dataset.state,
|
||||
military = pack.states[state].military;
|
||||
|
|
@ -206,8 +237,7 @@ function editRegiment(selector) {
|
|||
function addRegimentOnClick() {
|
||||
const point = d3.mouse(this);
|
||||
const cell = findCell(point[0], point[1]);
|
||||
const x = pack.cells.p[cell][0],
|
||||
y = pack.cells.p[cell][1];
|
||||
const [x, y] = pack.cells.p[cell];
|
||||
const state = +elSelected.dataset.state,
|
||||
military = pack.states[state].military;
|
||||
const i = military.length ? last(military).i + 1 : 0;
|
||||
|
|
@ -254,7 +284,7 @@ function editRegiment(selector) {
|
|||
return;
|
||||
}
|
||||
|
||||
const attacker = regiment();
|
||||
const attacker = getRegiment();
|
||||
const defender = pack.states[regSelected.dataset.state].military.find(r => r.i == regSelected.dataset.id);
|
||||
if (!attacker.a || !defender.a) {
|
||||
tip("Regiment has no troops to battle", false, "error");
|
||||
|
|
@ -322,7 +352,7 @@ function editRegiment(selector) {
|
|||
return;
|
||||
}
|
||||
|
||||
const reg = regiment(); // reg to be attached
|
||||
const reg = getRegiment(); // reg to be attached
|
||||
const sel = pack.states[newState].military.find(r => r.i == regSelected.dataset.id); // reg to attach to
|
||||
|
||||
for (const unit of options.military) {
|
||||
|
|
@ -349,11 +379,11 @@ function editRegiment(selector) {
|
|||
if (index != -1) notes.splice(index, 1);
|
||||
|
||||
const s = pack.states[elSelected.dataset.state];
|
||||
Military.generateNote(regiment(), s);
|
||||
Military.generateNote(getRegiment(), s);
|
||||
}
|
||||
|
||||
function editLegend() {
|
||||
editNotes(elSelected.id, regiment().name);
|
||||
editNotes(elSelected.id, getRegiment().name);
|
||||
}
|
||||
|
||||
function removeRegiment() {
|
||||
|
|
@ -365,7 +395,7 @@ function editRegiment(selector) {
|
|||
Remove: function () {
|
||||
$(this).dialog("close");
|
||||
const military = pack.states[elSelected.dataset.state].military;
|
||||
const regIndex = military.indexOf(regiment());
|
||||
const regIndex = military.indexOf(getRegiment());
|
||||
if (regIndex === -1) return;
|
||||
military.splice(regIndex, 1);
|
||||
|
||||
|
|
@ -392,8 +422,6 @@ function editRegiment(selector) {
|
|||
const size = +armies.attr("box-size");
|
||||
const w = reg.n ? size * 4 : size * 6;
|
||||
const h = size * 2;
|
||||
const x1 = x => rn(x - w / 2, 2);
|
||||
const y1 = y => rn(y - size, 2);
|
||||
|
||||
const baseRect = this.querySelector("rect");
|
||||
const text = this.querySelector("text");
|
||||
|
|
@ -402,26 +430,37 @@ function editRegiment(selector) {
|
|||
|
||||
const self = elSelected === this;
|
||||
const baseLine = viewbox.select("g#regimentBase > line");
|
||||
const rotationControl = debug.select("#rotationControl");
|
||||
|
||||
d3.event.on("drag", function () {
|
||||
const x = (reg.x = d3.event.x),
|
||||
y = (reg.y = d3.event.y);
|
||||
const {x, y} = d3.event;
|
||||
reg.x = x;
|
||||
reg.y = y;
|
||||
const x1 = rn(x - w / 2, 2);
|
||||
const y1 = rn(y - size, 2);
|
||||
|
||||
baseRect.setAttribute("x", x1(x));
|
||||
baseRect.setAttribute("y", y1(y));
|
||||
this.setAttribute("transform-origin", `${x}px ${y}px`);
|
||||
baseRect.setAttribute("x", x1);
|
||||
baseRect.setAttribute("y", y1);
|
||||
text.setAttribute("x", x);
|
||||
text.setAttribute("y", y);
|
||||
iconRect.setAttribute("x", x1(x) - h);
|
||||
iconRect.setAttribute("y", y1(y));
|
||||
icon.setAttribute("x", x1(x) - size);
|
||||
iconRect.setAttribute("x", x1 - h);
|
||||
iconRect.setAttribute("y", y1);
|
||||
icon.setAttribute("x", x1 - size);
|
||||
icon.setAttribute("y", y);
|
||||
if (self) baseLine.attr("x2", x).attr("y2", y);
|
||||
if (self) {
|
||||
baseLine.attr("x2", x).attr("y2", y);
|
||||
rotationControl
|
||||
.attr("cx", x1 + w)
|
||||
.attr("cy", y)
|
||||
.attr("transform-origin", `${x}px ${y}px`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function dragBase() {
|
||||
const baseLine = viewbox.select("g#regimentBase > line");
|
||||
const reg = regiment();
|
||||
const reg = getRegiment();
|
||||
|
||||
d3.event.on("drag", function () {
|
||||
this.setAttribute("cx", d3.event.x);
|
||||
|
|
@ -436,9 +475,10 @@ function editRegiment(selector) {
|
|||
}
|
||||
|
||||
function closeEditor() {
|
||||
debug.selectAll("*").remove();
|
||||
viewbox.selectAll("g#regimentBase").remove();
|
||||
armies.selectAll(":scope > g").classed("draggable", false);
|
||||
armies.selectAll("g>g").call(d3.drag().on("drag", null));
|
||||
viewbox.selectAll("g#regimentBase").remove();
|
||||
document.getElementById("regimentAdd").classList.remove("pressed");
|
||||
document.getElementById("regimentAttack").classList.remove("pressed");
|
||||
document.getElementById("regimentAttach").classList.remove("pressed");
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ async function getStylePreset(desiredPreset) {
|
|||
|
||||
async function fetchSystemPreset(preset) {
|
||||
try {
|
||||
const res = await fetch(`./styles/${preset}.json`);
|
||||
const res = await fetch(`./styles/${preset}.json?v=${version}`);
|
||||
return await res.json();
|
||||
} catch (err) {
|
||||
throw new Error("Cannot fetch style preset", preset);
|
||||
|
|
@ -198,7 +198,7 @@ function addStylePreset() {
|
|||
"mask"
|
||||
],
|
||||
"#compass": ["opacity", "transform", "filter", "mask", "shape-rendering"],
|
||||
"#rose": ["transform"],
|
||||
"#compass > use": ["transform"],
|
||||
"#relig": ["opacity", "stroke", "stroke-width", "filter"],
|
||||
"#cults": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter"],
|
||||
"#landmass": ["opacity", "fill", "filter"],
|
||||
|
|
|
|||
|
|
@ -335,29 +335,44 @@ function regenerateProvinces() {
|
|||
}
|
||||
|
||||
function regenerateBurgs() {
|
||||
const {cells, states} = pack;
|
||||
const lockedburgs = pack.burgs.filter(b => b.i && !b.removed && b.lock);
|
||||
const {cells, features, burgs, states, provinces} = pack;
|
||||
|
||||
rankCells();
|
||||
|
||||
cells.burg = new Uint16Array(cells.i.length);
|
||||
const burgs = (pack.burgs = [0]); // clear burgs array
|
||||
states.filter(s => s.i).forEach(s => (s.capital = 0)); // clear state capitals
|
||||
pack.provinces.filter(p => p.i).forEach(p => (p.burg = 0)); // clear province capitals
|
||||
// remove notes for unlocked burgs
|
||||
notes = notes.filter(note => {
|
||||
if (note.id.startsWith("burg")) {
|
||||
const burgId = +note.id.slice(4);
|
||||
return burgs[burgId]?.lock;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
const newBurgs = [0]; // new burgs array
|
||||
const burgsTree = d3.quadtree();
|
||||
|
||||
// add locked burgs
|
||||
cells.burg = new Uint16Array(cells.i.length); // clear cells burg data
|
||||
states.filter(s => s.i).forEach(s => (s.capital = 0)); // clear state capitals
|
||||
provinces.filter(p => p.i).forEach(p => (p.burg = 0)); // clear province capitals
|
||||
|
||||
// readd locked burgs
|
||||
const lockedburgs = burgs.filter(burg => burg.i && !burg.removed && burg.lock);
|
||||
for (let j = 0; j < lockedburgs.length; j++) {
|
||||
const id = burgs.length;
|
||||
const lockedBurg = lockedburgs[j];
|
||||
lockedBurg.i = id;
|
||||
burgs.push(lockedBurg);
|
||||
const newId = newBurgs.length;
|
||||
|
||||
const noteIndex = notes.findIndex(note => note.id === `burg${lockedBurg.i}`);
|
||||
if (noteIndex !== -1) notes[noteIndex].id = `burg${newId}`;
|
||||
|
||||
lockedBurg.i = newId;
|
||||
newBurgs.push(lockedBurg);
|
||||
|
||||
burgsTree.add([lockedBurg.x, lockedBurg.y]);
|
||||
cells.burg[lockedBurg.cell] = id;
|
||||
cells.burg[lockedBurg.cell] = newId;
|
||||
|
||||
if (lockedBurg.capital) {
|
||||
const stateId = lockedBurg.state;
|
||||
states[stateId].capital = id;
|
||||
states[stateId].capital = newId;
|
||||
states[stateId].center = lockedBurg.cell;
|
||||
}
|
||||
}
|
||||
|
|
@ -370,8 +385,8 @@ function regenerateBurgs() {
|
|||
existingStatesCount;
|
||||
const spacing = (graphWidth + graphHeight) / 150 / (burgsCount ** 0.7 / 66); // base min distance between towns
|
||||
|
||||
for (let i = 0; i < sorted.length && burgs.length < burgsCount; i++) {
|
||||
const id = burgs.length;
|
||||
for (let i = 0; i < sorted.length && newBurgs.length < burgsCount; i++) {
|
||||
const id = newBurgs.length;
|
||||
const cell = sorted[i];
|
||||
const [x, y] = cells.p[cell];
|
||||
|
||||
|
|
@ -387,24 +402,27 @@ function regenerateBurgs() {
|
|||
|
||||
const culture = cells.culture[cell];
|
||||
const name = Names.getCulture(culture);
|
||||
burgs.push({cell, x, y, state: stateId, i: id, culture, name, capital, feature: cells.f[cell]});
|
||||
newBurgs.push({cell, x, y, state: stateId, i: id, culture, name, capital, feature: cells.f[cell]});
|
||||
burgsTree.add([x, y]);
|
||||
cells.burg[cell] = id;
|
||||
}
|
||||
|
||||
pack.burgs = newBurgs; // assign new burgs array
|
||||
|
||||
// add a capital at former place for states without added capitals
|
||||
states
|
||||
.filter(s => s.i && !s.removed && !s.capital)
|
||||
.forEach(s => {
|
||||
const burg = addBurg([cells.p[s.center][0], cells.p[s.center][1]]); // add new burg
|
||||
s.capital = burg;
|
||||
s.center = pack.burgs[burg].cell;
|
||||
pack.burgs[burg].capital = 1;
|
||||
pack.burgs[burg].state = s.i;
|
||||
moveBurgToGroup(burg, "cities");
|
||||
const [x, y] = cells.p[s.center];
|
||||
const burgId = addBurg([x, y]);
|
||||
s.capital = burgId;
|
||||
s.center = pack.burgs[burgId].cell;
|
||||
pack.burgs[burgId].capital = 1;
|
||||
pack.burgs[burgId].state = s.i;
|
||||
moveBurgToGroup(burgId, "cities");
|
||||
});
|
||||
|
||||
pack.features.forEach(f => {
|
||||
features.forEach(f => {
|
||||
if (f.port) f.port = 0; // reset features ports counter
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -5,18 +5,17 @@ function editWorld() {
|
|||
title: "Configure World",
|
||||
resizable: false,
|
||||
width: "minmax(40em, 85vw)",
|
||||
buttons: {
|
||||
"Whole World": () => applyWorldPreset(100, 50),
|
||||
Northern: () => applyWorldPreset(33, 25),
|
||||
Tropical: () => applyWorldPreset(33, 50),
|
||||
Southern: () => applyWorldPreset(33, 75)
|
||||
},
|
||||
buttons: {"Update world": updateWorld},
|
||||
open: function () {
|
||||
const buttons = $(this).dialog("widget").find(".ui-dialog-buttonset > button");
|
||||
buttons[0].addEventListener("mousemove", () => tip("Click to set map size to cover the whole World"));
|
||||
buttons[1].addEventListener("mousemove", () => tip("Click to set map size to cover the Northern latitudes"));
|
||||
buttons[2].addEventListener("mousemove", () => tip("Click to set map size to cover the Tropical latitudes"));
|
||||
buttons[3].addEventListener("mousemove", () => tip("Click to set map size to cover the Southern latitudes"));
|
||||
const checkbox = /* html */ `<div class="dontAsk" data-tip="Automatically update world on input changes and button clicks">
|
||||
<input id="wcAutoChange" class="checkbox" type="checkbox" checked />
|
||||
<label for="wcAutoChange" class="checkbox-label"><i>auto-apply changes</i></label>
|
||||
</div>`;
|
||||
const pane = this.parentElement.querySelector(".ui-dialog-buttonpane");
|
||||
pane.insertAdjacentHTML("afterbegin", checkbox);
|
||||
|
||||
const button = this.parentElement.querySelector(".ui-dialog-buttonset > button");
|
||||
button.on("mousemove", () => tip("Apply curreny settings to the map"));
|
||||
},
|
||||
close: function () {
|
||||
$(this).dialog("destroy");
|
||||
|
|
@ -34,12 +33,16 @@ function editWorld() {
|
|||
if (modules.editWorld) return;
|
||||
modules.editWorld = true;
|
||||
|
||||
byId("worldControls").addEventListener("input", e => updateWorld(e.target));
|
||||
globe.select("#globeWindArrows").on("click", changeWind);
|
||||
globe.select("#globeWindArrows").on("click", handleWindChange);
|
||||
globe.select("#globeGraticule").attr("d", round(path(d3.geoGraticule()()))); // globe graticule
|
||||
updateWindDirections();
|
||||
|
||||
byId("restoreWinds").addEventListener("click", restoreDefaultWinds);
|
||||
byId("worldControls").on("input", handleControlsChange);
|
||||
byId("restoreWinds").on("click", restoreDefaultWinds);
|
||||
byId("wcWholeWorld").on("click", () => applyWorldPreset(100, 50));
|
||||
byId("wcNorthern").on("click", () => applyWorldPreset(33, 25));
|
||||
byId("wcTropical").on("click", () => applyWorldPreset(33, 50));
|
||||
byId("wcSouthern").on("click", () => applyWorldPreset(33, 75));
|
||||
|
||||
function updateInputValues() {
|
||||
byId("temperatureEquatorInput").value = options.temperatureEquator;
|
||||
|
|
@ -55,27 +58,27 @@ function editWorld() {
|
|||
byId("temperatureSouthPoleF").innerText = convertTemperature(options.temperatureSouthPole, "°F");
|
||||
}
|
||||
|
||||
function updateWorld(el) {
|
||||
if (el?.dataset.stored) {
|
||||
const stored = el.dataset.stored;
|
||||
byId(stored + "Input").value = el.value;
|
||||
byId(stored + "Output").value = el.value;
|
||||
lock(el.dataset.stored);
|
||||
function handleControlsChange({target}) {
|
||||
const stored = target.dataset.stored;
|
||||
byId(stored + "Input").value = target.value;
|
||||
byId(stored + "Output").value = target.value;
|
||||
lock(stored);
|
||||
|
||||
if (stored === "temperatureEquator") {
|
||||
options.temperatureEquator = Number(el.value);
|
||||
byId("temperatureEquatorF").innerText = convertTemperature(options.temperatureEquator, "°F");
|
||||
}
|
||||
if (stored === "temperatureNorthPole") {
|
||||
options.temperatureNorthPole = Number(el.value);
|
||||
byId("temperatureNorthPoleF").innerText = convertTemperature(options.temperatureNorthPole, "°F");
|
||||
}
|
||||
if (stored === "temperatureSouthPole") {
|
||||
options.temperatureSouthPole = Number(el.value);
|
||||
byId("temperatureSouthPoleF").innerText = convertTemperature(options.temperatureSouthPole, "°F");
|
||||
}
|
||||
if (stored === "temperatureEquator") {
|
||||
options.temperatureEquator = Number(target.value);
|
||||
byId("temperatureEquatorF").innerText = convertTemperature(options.temperatureEquator, "°F");
|
||||
} else if (stored === "temperatureNorthPole") {
|
||||
options.temperatureNorthPole = Number(target.value);
|
||||
byId("temperatureNorthPoleF").innerText = convertTemperature(options.temperatureNorthPole, "°F");
|
||||
} else if (stored === "temperatureSouthPole") {
|
||||
options.temperatureSouthPole = Number(target.value);
|
||||
byId("temperatureSouthPoleF").innerText = convertTemperature(options.temperatureSouthPole, "°F");
|
||||
}
|
||||
|
||||
if (byId("wcAutoChange").checked) updateWorld();
|
||||
}
|
||||
|
||||
function updateWorld() {
|
||||
updateGlobeTemperature();
|
||||
updateGlobePosition();
|
||||
calculateTemperatures();
|
||||
|
|
@ -113,9 +116,11 @@ function editWorld() {
|
|||
|
||||
function toKilometer(v) {
|
||||
if (unit === "km") return v;
|
||||
else if (unit === "mi") return v * 1.60934;
|
||||
else if (unit === "lg") return v * 5.556;
|
||||
else if (unit === "vr") return v * 1.0668;
|
||||
if (unit === "mi") return v * 1.60934;
|
||||
if (unit === "lg") return v * 4.828;
|
||||
if (unit === "vr") return v * 1.0668;
|
||||
if (unit === "nmi") return v * 1.852;
|
||||
if (unit === "nlg") return v * 5.556;
|
||||
return 0; // 0 if distanceUnitInput is a custom unit
|
||||
}
|
||||
|
||||
|
|
@ -128,6 +133,7 @@ function editWorld() {
|
|||
[mc.lonW, mc.latN],
|
||||
[mc.lonE, mc.latS]
|
||||
]);
|
||||
|
||||
globe.select("#globeArea").attr("d", round(path(area.outline()))); // map area
|
||||
}
|
||||
|
||||
|
|
@ -161,21 +167,22 @@ function editWorld() {
|
|||
});
|
||||
}
|
||||
|
||||
function changeWind() {
|
||||
function handleWindChange() {
|
||||
const arrow = d3.event.target.nextElementSibling;
|
||||
const tier = +arrow.dataset.tier;
|
||||
options.winds[tier] = (options.winds[tier] + 45) % 360;
|
||||
const tr = parseTransform(arrow.getAttribute("transform"));
|
||||
arrow.setAttribute("transform", `rotate(${options.winds[tier]} ${tr[1]} ${tr[2]})`);
|
||||
localStorage.setItem("winds", options.winds);
|
||||
|
||||
const mapTiers = d3.range(mapCoordinates.latN, mapCoordinates.latS, -30).map(c => ((90 - c) / 30) | 0);
|
||||
if (mapTiers.includes(tier)) updateWorld();
|
||||
if (byId("wcAutoChange").checked && mapTiers.includes(tier)) updateWorld();
|
||||
}
|
||||
|
||||
function restoreDefaultWinds() {
|
||||
const defaultWinds = [225, 45, 225, 315, 135, 315];
|
||||
const mapTiers = d3.range(mapCoordinates.latN, mapCoordinates.latS, -30).map(c => ((90 - c) / 30) | 0);
|
||||
const update = mapTiers.some(t => options.winds[t] != defaultWinds[t]);
|
||||
const update = byId("wcAutoChange").checked && mapTiers.some(t => options.winds[t] != defaultWinds[t]);
|
||||
options.winds = defaultWinds;
|
||||
updateWindDirections();
|
||||
if (update) updateWorld();
|
||||
|
|
@ -186,6 +193,6 @@ function editWorld() {
|
|||
byId("latitudeInput").value = byId("latitudeOutput").value = lat;
|
||||
lock("mapSize");
|
||||
lock("latitude");
|
||||
updateWorld();
|
||||
if (byId("wcAutoChange").checked) updateWorld();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
function editZones() {
|
||||
closeDialogs();
|
||||
if (!layerIsOn("toggleZones")) toggleZones();
|
||||
const body = document.getElementById("zonesBodySection");
|
||||
const body = byId("zonesBodySection");
|
||||
|
||||
updateFilters();
|
||||
zonesEditorAddLines();
|
||||
|
|
@ -20,20 +20,20 @@ function editZones() {
|
|||
});
|
||||
|
||||
// add listeners
|
||||
document.getElementById("zonesFilterType").addEventListener("click", updateFilters);
|
||||
document.getElementById("zonesFilterType").addEventListener("change", filterZonesByType);
|
||||
document.getElementById("zonesEditorRefresh").addEventListener("click", zonesEditorAddLines);
|
||||
document.getElementById("zonesEditStyle").addEventListener("click", () => editStyle("zones"));
|
||||
document.getElementById("zonesLegend").addEventListener("click", toggleLegend);
|
||||
document.getElementById("zonesPercentage").addEventListener("click", togglePercentageMode);
|
||||
document.getElementById("zonesManually").addEventListener("click", enterZonesManualAssignent);
|
||||
document.getElementById("zonesManuallyApply").addEventListener("click", applyZonesManualAssignent);
|
||||
document.getElementById("zonesManuallyCancel").addEventListener("click", cancelZonesManualAssignent);
|
||||
document.getElementById("zonesAdd").addEventListener("click", addZonesLayer);
|
||||
document.getElementById("zonesExport").addEventListener("click", downloadZonesData);
|
||||
document.getElementById("zonesRemove").addEventListener("click", toggleEraseMode);
|
||||
byId("zonesFilterType").on("click", updateFilters);
|
||||
byId("zonesFilterType").on("change", filterZonesByType);
|
||||
byId("zonesEditorRefresh").on("click", zonesEditorAddLines);
|
||||
byId("zonesEditStyle").on("click", () => editStyle("zones"));
|
||||
byId("zonesLegend").on("click", toggleLegend);
|
||||
byId("zonesPercentage").on("click", togglePercentageMode);
|
||||
byId("zonesManually").on("click", enterZonesManualAssignent);
|
||||
byId("zonesManuallyApply").on("click", applyZonesManualAssignent);
|
||||
byId("zonesManuallyCancel").on("click", cancelZonesManualAssignent);
|
||||
byId("zonesAdd").on("click", addZonesLayer);
|
||||
byId("zonesExport").on("click", downloadZonesData);
|
||||
byId("zonesRemove").on("click", toggleEraseMode);
|
||||
|
||||
body.addEventListener("click", function (ev) {
|
||||
body.on("click", function (ev) {
|
||||
const el = ev.target,
|
||||
cl = el.classList,
|
||||
zone = el.parentNode.dataset.id;
|
||||
|
|
@ -45,7 +45,7 @@ function editZones() {
|
|||
if (customization) selectZone(el);
|
||||
});
|
||||
|
||||
body.addEventListener("input", function (ev) {
|
||||
body.on("input", function (ev) {
|
||||
const el = ev.target;
|
||||
const zone = zones.select("#" + el.parentNode.dataset.id);
|
||||
|
||||
|
|
@ -58,10 +58,11 @@ function editZones() {
|
|||
const zones = Array.from(document.querySelectorAll("#zones > g"));
|
||||
const types = unique(zones.map(zone => zone.dataset.type));
|
||||
|
||||
const filterSelect = document.getElementById("zonesFilterType");
|
||||
const filterSelect = byId("zonesFilterType");
|
||||
const typeToFilterBy = types.includes(zonesFilterType.value) ? zonesFilterType.value : "all";
|
||||
|
||||
filterSelect.innerHTML = "<option value='all'>all</option>" + types.map(type => `<option value="${type}">${type}</option>`).join("");
|
||||
filterSelect.innerHTML =
|
||||
"<option value='all'>all</option>" + types.map(type => `<option value="${type}">${type}</option>`).join("");
|
||||
filterSelect.value = typeToFilterBy;
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +70,7 @@ function editZones() {
|
|||
function zonesEditorAddLines() {
|
||||
const unit = " " + getAreaUnit();
|
||||
|
||||
const typeToFilterBy = document.getElementById("zonesFilterType").value;
|
||||
const typeToFilterBy = byId("zonesFilterType").value;
|
||||
const zones = Array.from(document.querySelectorAll("#zones > g"));
|
||||
const filteredZones = typeToFilterBy === "all" ? zones : zones.filter(zone => zone.dataset.type === typeToFilterBy);
|
||||
|
||||
|
|
@ -80,9 +81,12 @@ function editZones() {
|
|||
const fill = zoneEl.getAttribute("fill");
|
||||
const area = getArea(d3.sum(c.map(i => pack.cells.area[i])));
|
||||
const rural = d3.sum(c.map(i => pack.cells.pop[i])) * populationRate;
|
||||
const urban = d3.sum(c.map(i => pack.cells.burg[i]).map(b => pack.burgs[b].population)) * populationRate * urbanization;
|
||||
const urban =
|
||||
d3.sum(c.map(i => pack.cells.burg[i]).map(b => pack.burgs[b].population)) * populationRate * urbanization;
|
||||
const population = rural + urban;
|
||||
const populationTip = `Total population: ${si(population)}; Rural population: ${si(rural)}; Urban population: ${si(urban)}. Click to change`;
|
||||
const populationTip = `Total population: ${si(population)}; Rural population: ${si(
|
||||
rural
|
||||
)}; Urban population: ${si(urban)}. Click to change`;
|
||||
const inactive = zoneEl.style.display === "none";
|
||||
const focused = defs.select("#fog #focus" + zoneEl.id).size();
|
||||
|
||||
|
|
@ -98,8 +102,12 @@ function editZones() {
|
|||
<span data-tip="${populationTip}" class="icon-male hide"></span>
|
||||
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
|
||||
<span data-tip="Drag to raise or lower the zone" class="icon-resize-vertical hide"></span>
|
||||
<span data-tip="Toggle zone focus" class="icon-pin ${focused ? "" : " inactive"} hide ${c.length ? "" : " placeholder"}"></span>
|
||||
<span data-tip="Toggle zone visibility" class="icon-eye ${inactive ? " inactive" : ""} hide ${c.length ? "" : " placeholder"}"></span>
|
||||
<span data-tip="Toggle zone focus" class="icon-pin ${focused ? "" : " inactive"} hide ${
|
||||
c.length ? "" : " placeholder"
|
||||
}"></span>
|
||||
<span data-tip="Toggle zone visibility" class="icon-eye ${inactive ? " inactive" : ""} hide ${
|
||||
c.length ? "" : " placeholder"
|
||||
}"></span>
|
||||
<span data-tip="Remove zone" class="icon-trash-empty hide"></span>
|
||||
</div>`;
|
||||
});
|
||||
|
|
@ -109,7 +117,9 @@ function editZones() {
|
|||
// update footer
|
||||
const totalArea = getArea(graphWidth * graphHeight);
|
||||
zonesFooterArea.dataset.area = totalArea;
|
||||
const totalPop = (d3.sum(pack.cells.pop) + d3.sum(pack.burgs.filter(b => !b.removed).map(b => b.population)) * urbanization) * populationRate;
|
||||
const totalPop =
|
||||
(d3.sum(pack.cells.pop) + d3.sum(pack.burgs.filter(b => !b.removed).map(b => b.population)) * urbanization) *
|
||||
populationRate;
|
||||
zonesFooterPopulation.dataset.population = totalPop;
|
||||
zonesFooterNumber.innerHTML = /* html */ `${filteredZones.length} of ${zones.length}`;
|
||||
zonesFooterCells.innerHTML = pack.cells.i.length;
|
||||
|
|
@ -117,8 +127,8 @@ function editZones() {
|
|||
zonesFooterPopulation.innerHTML = si(totalPop);
|
||||
|
||||
// add listeners
|
||||
body.querySelectorAll("div.states").forEach(el => el.addEventListener("mouseenter", ev => zoneHighlightOn(ev)));
|
||||
body.querySelectorAll("div.states").forEach(el => el.addEventListener("mouseleave", ev => zoneHighlightOff(ev)));
|
||||
body.querySelectorAll("div.states").forEach(el => el.on("mouseenter", ev => zoneHighlightOn(ev)));
|
||||
body.querySelectorAll("div.states").forEach(el => el.on("mouseleave", ev => zoneHighlightOff(ev)));
|
||||
|
||||
if (body.dataset.type === "percentage") {
|
||||
body.dataset.type = "absolute";
|
||||
|
|
@ -150,7 +160,13 @@ function editZones() {
|
|||
zonesEditorAddLines();
|
||||
}
|
||||
|
||||
$(body).sortable({items: "div.states", handle: ".icon-resize-vertical", containment: "parent", axis: "y", update: movezone});
|
||||
$(body).sortable({
|
||||
items: "div.states",
|
||||
handle: ".icon-resize-vertical",
|
||||
containment: "parent",
|
||||
axis: "y",
|
||||
update: movezone
|
||||
});
|
||||
function movezone(ev, ui) {
|
||||
const zone = $("#" + ui.item.attr("data-id"));
|
||||
const prev = $("#" + ui.item.prev().attr("data-id"));
|
||||
|
|
@ -166,7 +182,7 @@ function editZones() {
|
|||
if (!layerIsOn("toggleZones")) toggleZones();
|
||||
customization = 10;
|
||||
document.querySelectorAll("#zonesBottom > *").forEach(el => (el.style.display = "none"));
|
||||
document.getElementById("zonesManuallyButtons").style.display = "inline-block";
|
||||
byId("zonesManuallyButtons").style.display = "inline-block";
|
||||
|
||||
zonesEditor.querySelectorAll(".hide").forEach(el => el.classList.add("hidden"));
|
||||
zonesFooter.style.display = "none";
|
||||
|
|
@ -174,7 +190,11 @@ function editZones() {
|
|||
$("#zonesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}});
|
||||
|
||||
tip("Click to select a zone, drag to paint a zone", true);
|
||||
viewbox.style("cursor", "crosshair").on("click", selectZoneOnMapClick).call(d3.drag().on("start", dragZoneBrush)).on("touchmove mousemove", moveZoneBrush);
|
||||
viewbox
|
||||
.style("cursor", "crosshair")
|
||||
.on("click", selectZoneOnMapClick)
|
||||
.call(d3.drag().on("start", dragZoneBrush))
|
||||
.on("touchmove mousemove", moveZoneBrush);
|
||||
|
||||
body.querySelector("div").classList.add("selected");
|
||||
zones.selectAll("g").each(function () {
|
||||
|
|
@ -195,24 +215,27 @@ function editZones() {
|
|||
}
|
||||
|
||||
function dragZoneBrush() {
|
||||
const r = +zonesBrush.value;
|
||||
const radius = +byId("zonesBrush").value;
|
||||
const eraseMode = byId("zonesRemove").classList.contains("pressed");
|
||||
const landOnly = byId("zonesBrushLandOnly").checked;
|
||||
|
||||
const selected = body.querySelector("div.selected");
|
||||
const zone = zones.select("#" + selected.dataset.id);
|
||||
const base = zone.attr("id") + "_"; // id generic part
|
||||
|
||||
d3.event.on("drag", () => {
|
||||
if (!d3.event.dx && !d3.event.dy) return;
|
||||
const p = d3.mouse(this);
|
||||
moveCircle(p[0], p[1], r);
|
||||
const [x, y] = d3.mouse(this);
|
||||
moveCircle(x, y, radius);
|
||||
|
||||
const selection = r > 5 ? findAll(p[0], p[1], r) : [findCell(p[0], p[1], r)];
|
||||
let selection = radius > 5 ? findAll(x, y, radius) : [findCell(x, y, radius)];
|
||||
if (landOnly) selection = selection.filter(i => pack.cells.h[i] >= 20);
|
||||
if (!selection) return;
|
||||
|
||||
const selected = body.querySelector("div.selected");
|
||||
const zone = zones.select("#" + selected.dataset.id);
|
||||
const base = zone.attr("id") + "_"; // id generic part
|
||||
const dataCells = zone.attr("data-cells");
|
||||
let cells = dataCells ? dataCells.split(",").map(i => +i) : [];
|
||||
|
||||
const erase = document.getElementById("zonesRemove").classList.contains("pressed");
|
||||
if (erase) {
|
||||
if (eraseMode) {
|
||||
// remove
|
||||
selection.forEach(i => {
|
||||
const index = cells.indexOf(i);
|
||||
|
|
@ -280,12 +303,13 @@ function editZones() {
|
|||
customization = 0;
|
||||
removeCircle();
|
||||
document.querySelectorAll("#zonesBottom > *").forEach(el => (el.style.display = "inline-block"));
|
||||
document.getElementById("zonesManuallyButtons").style.display = "none";
|
||||
byId("zonesManuallyButtons").style.display = "none";
|
||||
|
||||
zonesEditor.querySelectorAll(".hide:not(.show)").forEach(el => el.classList.remove("hidden"));
|
||||
zonesFooter.style.display = "block";
|
||||
body.querySelectorAll("div > input, select, svg").forEach(e => (e.style.pointerEvents = "all"));
|
||||
if (!close) $("#zonesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}});
|
||||
if (!close)
|
||||
$("#zonesEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}});
|
||||
|
||||
restoreDefaultEvents();
|
||||
clearMainTip();
|
||||
|
|
@ -300,7 +324,7 @@ function editZones() {
|
|||
const fill = el.getAttribute("fill");
|
||||
const callback = newFill => {
|
||||
el.fill = newFill;
|
||||
document.getElementById(el.parentNode.dataset.id).setAttribute("fill", newFill);
|
||||
byId(el.parentNode.dataset.id).setAttribute("fill", newFill);
|
||||
};
|
||||
|
||||
openPicker(fill, callback);
|
||||
|
|
@ -356,7 +380,8 @@ function editZones() {
|
|||
body.querySelectorAll(":scope > div").forEach(function (el) {
|
||||
el.querySelector(".stateCells").innerHTML = rn((+el.dataset.cells / totalCells) * 100, 2) + "%";
|
||||
el.querySelector(".biomeArea").innerHTML = rn((+el.dataset.area / totalArea) * 100, 2) + "%";
|
||||
el.querySelector(".culturePopulation").innerHTML = rn((+el.dataset.population / totalPopulation) * 100, 2) + "%";
|
||||
el.querySelector(".culturePopulation").innerHTML =
|
||||
rn((+el.dataset.population / totalPopulation) * 100, 2) + "%";
|
||||
});
|
||||
} else {
|
||||
body.dataset.type = "absolute";
|
||||
|
|
@ -369,7 +394,13 @@ function editZones() {
|
|||
const description = "Unknown zone";
|
||||
const type = "Unknown";
|
||||
const fill = "url(#hatch" + (id.slice(4) % 42) + ")";
|
||||
zones.append("g").attr("id", id).attr("data-description", description).attr("data-type", type).attr("data-cells", "").attr("fill", fill);
|
||||
zones
|
||||
.append("g")
|
||||
.attr("id", id)
|
||||
.attr("data-description", description)
|
||||
.attr("data-type", type)
|
||||
.attr("data-cells", "")
|
||||
.attr("fill", fill);
|
||||
|
||||
zonesEditorAddLines();
|
||||
}
|
||||
|
|
@ -411,13 +442,19 @@ function editZones() {
|
|||
const burgs = pack.burgs.filter(b => !b.removed && cells.includes(b.cell));
|
||||
|
||||
const rural = rn(d3.sum(cells.map(i => pack.cells.pop[i])) * populationRate);
|
||||
const urban = rn(d3.sum(cells.map(i => pack.cells.burg[i]).map(b => pack.burgs[b].population)) * populationRate * urbanization);
|
||||
const urban = rn(
|
||||
d3.sum(cells.map(i => pack.cells.burg[i]).map(b => pack.burgs[b].population)) * populationRate * urbanization
|
||||
);
|
||||
const total = rural + urban;
|
||||
const l = n => Number(n).toLocaleString();
|
||||
|
||||
alertMessage.innerHTML = /* html */ `Rural: <input type="number" min="0" step="1" id="ruralPop" value=${rural} style="width:6em" /> Urban:
|
||||
<input type="number" min="0" step="1" id="urbanPop" value=${urban} style="width:6em" ${burgs.length ? "" : "disabled"} />
|
||||
<p>Total population: ${l(total)} ⇒ <span id="totalPop">${l(total)}</span> (<span id="totalPopPerc">100</span>%)</p>`;
|
||||
<input type="number" min="0" step="1" id="urbanPop" value=${urban} style="width:6em" ${
|
||||
burgs.length ? "" : "disabled"
|
||||
} />
|
||||
<p>Total population: ${l(total)} ⇒ <span id="totalPop">${l(
|
||||
total
|
||||
)}</span> (<span id="totalPopPerc">100</span>%)</p>`;
|
||||
|
||||
const update = function () {
|
||||
const totalNew = ruralPop.valueAsNumber + urbanPop.valueAsNumber;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue