diff --git a/.gitignore b/.gitignore index eb169d8d..8cd42a0d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .bat -.vscode \ No newline at end of file +.vscode +.idea +.idea/Fantasy-Map-Generator.iml diff --git a/components/fill-box.js b/components/fill-box.js new file mode 100644 index 00000000..02912f3b --- /dev/null +++ b/components/fill-box.js @@ -0,0 +1,74 @@ +// fill-box cannot use Shadow DOM as it needs access to svg hatches +// append stylesheet +{ + const style = ` + fill-box:not([disabled]) { + cursor: pointer; + } + + fill-box > svg { + vertical-align: middle; + pointer-events: none; + } + + fill-box > svg > rect { + stroke: #666666; + stroke-width: 2; + }`; + + const styleElement = document.createElement("style"); + styleElement.setAttribute("type", "text/css"); + styleElement.innerHTML = style; + document.head.appendChild(styleElement); +} + +{ + const template = document.createElement("template"); + template.innerHTML = ` + + + + `; + + class FillBox extends HTMLElement { + constructor() { + super(); + + this.appendChild(template.content.cloneNode(true)); + this.querySelector("rect")?.setAttribute("fill", this.fill); + this.querySelector("svg")?.setAttribute("width", this.size); + this.querySelector("svg")?.setAttribute("height", this.size); + } + + static showTip() { + tip(this.tip); + } + + connectedCallback() { + this.addEventListener("mousemove", this.constructor.showTip); + } + + disconnectedCallback() { + this.removeEventListener("mousemove", this.constructor.showTip); + } + + get fill() { + return this.getAttribute("fill") || "#333"; + } + + set fill(newFill) { + this.setAttribute("fill", newFill); + this.querySelector("rect")?.setAttribute("fill", newFill); + } + + get size() { + return this.getAttribute("size") || "1em"; + } + + get tip() { + return this.dataset.tip || "Fill style. Click to change"; + } + } + + customElements.define("fill-box", FillBox); +} diff --git a/dropbox.html b/dropbox.html index bc7f1945..cd1921da 100644 --- a/dropbox.html +++ b/dropbox.html @@ -7,35 +7,34 @@ + - - - - - - - - - + + + + + @@ -4458,6 +4590,7 @@ + @@ -4467,7 +4600,6 @@ - @@ -4480,14 +4612,23 @@ - + + - + + + + + + + + + diff --git a/libs/pell.min.js b/libs/pell.min.js deleted file mode 100644 index c5be57e5..00000000 --- a/libs/pell.min.js +++ /dev/null @@ -1,2 +0,0 @@ -// https://github.com/jaredreich/pell, MIT License -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Pell=t()}(this,function(){"use strict";const e=(e,t,n)=>e.addEventListener(t,n),t=(e,t)=>e.appendChild(t),n=e=>document.createElement(e),i=e=>document.queryCommandState(e),o=(e,t=null)=>document.execCommand(e,!1,t),l={bold:{icon:"B",title:"Bold",state:()=>i("bold"),result:()=>o("bold")},italic:{icon:"I",title:"Italic",state:()=>i("italic"),result:()=>o("italic")},underline:{icon:"U",title:"Underline",state:()=>i("underline"),result:()=>o("underline")},strikethrough:{icon:"S",title:"Strike-through",state:()=>i("strikeThrough"),result:()=>o("strikeThrough")},heading1:{icon:"H1",title:"Heading 1",result:()=>o("formatBlock","

")},heading2:{icon:"H2",title:"Heading 2",result:()=>o("formatBlock","

")},paragraph:{icon:"¶",title:"Paragraph",result:()=>o("formatBlock","

")},quote:{icon:"“ ”",title:"Quote",result:()=>o("formatBlock","

")},olist:{icon:"#",title:"Ordered List",result:()=>o("insertOrderedList")},ulist:{icon:"•",title:"Unordered List",result:()=>o("insertUnorderedList")},code:{icon:"</>",title:"Code",result:()=>o("formatBlock","
")},line:{icon:"―",title:"Horizontal Line",result:()=>o("insertHorizontalRule")},link:{icon:"🔗",title:"Link",result:()=>navigator.clipboard.readText().then(e=>o("createLink",e))},image:{icon:"📷",title:"Image",result:()=>{navigator.clipboard.readText().then(e=>o("insertImage",e)),o("enableObjectResizing")}}},r={actionbar:"pell-actionbar",button:"pell-button",content:"pell-content",selected:"pell-button-selected"};return{exec:o,init:i=>{const a=i.actions?i.actions.map(e=>"string"==typeof e?l[e]:l[e.name]?{...l[e.name],...e}:e):Object.keys(l).map(e=>l[e]),s={...r,...i.classes},c=i.defaultParagraphSeparator||"div",u=n("div");u.className=s.actionbar,t(i.element,u);const d=i.element.content=n("div");return d.contentEditable=!0,d.className=s.content,d.oninput=(({target:{firstChild:e}})=>{e&&3===e.nodeType?o("formatBlock",`<${c}>`):"
"===d.innerHTML&&(d.innerHTML=""),i.onChange(d.innerHTML)}),d.onkeydown=(e=>{"Enter"===e.key&&"blockquote"===(e=>document.queryCommandValue(e))("formatBlock")&&setTimeout(()=>o("formatBlock",`<${c}>`),0)}),t(i.element,d),a.forEach(i=>{const o=n("button");if(o.className=s.button,o.innerHTML=i.icon,o.title=i.title,o.setAttribute("type","button"),o.onclick=(()=>i.result()&&d.focus()),i.state){const t=()=>o.classList[i.state()?"add":"remove"](s.selected);e(d,"keyup",t),e(d,"mouseup",t),e(o,"click",t)}t(u,o)}),i.styleWithCSS&&o("styleWithCSS"),o("defaultParagraphSeparator",c),i.element}}}); \ No newline at end of file diff --git a/main.js b/main.js index f014a821..580c3d9e 100644 --- a/main.js +++ b/main.js @@ -1,11 +1,11 @@ -// Azgaar (azgaar.fmg@yandex.com). Minsk, 2017-2021. MIT License +// Azgaar (azgaar.fmg@yandex.com). Minsk, 2017-2022. MIT License // https://github.com/Azgaar/Fantasy-Map-Generator "use strict"; -const version = "1.71"; // generator version +const version = "1.732"; // generator version document.title += " v" + version; -// Switches to disable/enable logging features +// switches to disable/enable logging features const PRODUCTION = location.hostname && location.hostname !== "localhost" && location.hostname !== "127.0.0.1"; const DEBUG = localStorage.getItem("debug"); const INFO = DEBUG || !PRODUCTION; @@ -173,14 +173,46 @@ landmass.append("rect").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr oceanPattern.append("rect").attr("fill", "url(#oceanic)").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight); oceanLayers.append("rect").attr("id", "oceanBase").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight); -// remove loading screen -d3.select("#loading").transition().duration(4000).style("opacity", 0).remove(); -d3.select("#initial").transition().duration(4000).attr("opacity", 0).remove(); -d3.select("#optionsContainer").transition().duration(3000).style("opacity", 1); -d3.select("#tooltip").transition().duration(4000).style("opacity", 1); +if (!location.hostname) { + const wiki = "https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Run-FMG-locally"; + alertMessage.innerHTML = `Fantasy Map Generator cannot run serverless. + Follow the instructions on how you can easily run a local web-server`; + + $("#alert").dialog({ + resizable: false, + title: "Loading error", + width: "28em", + position: {my: "center center-4em", at: "center", of: "svg"}, + buttons: { + OK: function () { + $(this).dialog("close"); + } + } + }); + + d3.select("#loading-text").transition().duration(1000).style("opacity", 0); + d3.select("#init-rose").transition().duration(4000).style("opacity", 0); +} else { + hideLoading(); + checkLoadParameters(); +} + +function hideLoading() { + d3.select("#loading").transition().duration(4000).style("opacity", 0); + d3.select("#initial").transition().duration(4000).attr("opacity", 0); + d3.select("#optionsContainer").transition().duration(3000).style("opacity", 1); + d3.select("#tooltip").transition().duration(4000).style("opacity", 1); +} + +function showLoading() { + d3.select("#loading").transition().duration(200).style("opacity", 1); + d3.select("#initial").transition().duration(200).attr("opacity", 1); + d3.select("#optionsContainer").transition().duration(100).style("opacity", 0); + d3.select("#tooltip").transition().duration(200).style("opacity", 0); +} // decide which map should be loaded or generated on page load -void (function checkLoadParameters() { +function checkLoadParameters() { const url = new URL(window.location.href); const params = url.searchParams; @@ -191,7 +223,9 @@ void (function checkLoadParameters() { const pattern = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; const valid = pattern.test(maplink); if (valid) { - loadMapFromURL(maplink, 1); + setTimeout(() => { + loadMapFromURL(maplink, 1); + }, 1000); return; } else showUploadErrorMessage("Map link is not a valid URL", maplink); } @@ -225,11 +259,11 @@ void (function checkLoadParameters() { WARN && console.warn("Generate random map"); generateMapOnLoad(); -})(); +} -function generateMapOnLoad() { - applyStyleOnLoad(); // apply default or previously selected style - generate(); // generate map +async function generateMapOnLoad() { + await applyStyleOnLoad(); // apply previously selected default or custom style + await generate(); // generate map focusOn(); // based on searchParams focus on point, cell or burg from MFCG applyPreset(); // apply saved layers preset } @@ -410,22 +444,22 @@ function showWelcomeMessage() { const discord = link("https://discordapp.com/invite/X7E84HU", "Discord server"); const patreon = link("https://www.patreon.com/azgaar", "Patreon"); - alertMessage.innerHTML = `The Fantasy Map Generator is updated up to version ${version}. + alertMessage.innerHTML = `The Fantasy Map Generator is updated up to version ${version}. This version is compatible with ${changelog}, loaded .map files will be auto-updated. -
    Main changes: -
  • Ability to limit military units by biome, state, culture and religion
  • -
  • New marker types
  • -
  • New markers editor
  • -
  • Markers overview screen
  • -
  • Markers regeneration menu
  • -
  • Burg editor update
  • -
  • Editable theme color
  • -
  • Add font dialog
  • -
  • Save to Dropbox
  • +
      Latest changes: +
    • Pre-defined heightmaps
    • +
    • Advanced notes editor
    • +
    • Zones editor: filter by type
    • +
    • Color picker: new hatchings
    • +
    • New style presets: Cyberpunk and Atlas
    • +
    • Burg temperature graph
    • +
    • 4 new textures
    • +
    • Province capture logic rework
    • +
    • Button to release all provinces

    Join our ${discord} and ${reddit} to ask questions, share maps, discuss the Generator and Worlbuilding, report bugs and propose new features.

    - Thanks for all supporters on Patreon!`; + Thanks for all supporters on ${patreon}!`; $("#alert").dialog({ resizable: false, @@ -448,7 +482,7 @@ function doWorkOnZoom(isScaleChanged, isPositionChanged) { if (isScaleChanged) { invokeActiveZooming(); - drawScaleBar(); + drawScaleBar(scale); } // zoom image converter overlay @@ -609,7 +643,7 @@ void (function addDragToUpload() { }); })(); -function generate() { +async function generate() { try { const timeStart = performance.now(); invokeActiveZooming(); @@ -619,8 +653,8 @@ function generate() { randomizeOptions(); placePoints(); calculateVoronoi(grid, grid.points); - drawScaleBar(); - HeightmapGenerator.generate(); + drawScaleBar(scale); + await HeightmapGenerator.generate(); markFeatures(); markupGridOcean(); addLakesInDeepDepressions(); @@ -907,6 +941,31 @@ function defineMapSize() { function getSizeAndLatitude() { const template = document.getElementById("templateInput").value; // heightmap template + + if (template === "africa-centric") return [45, 53]; + if (template === "arabia") return [20, 35]; + if (template === "atlantics") return [42, 23]; + if (template === "britain") return [7, 20]; + if (template === "caribbean") return [15, 40]; + if (template === "east-asia") return [11, 28]; + if (template === "eurasia") return [38, 19]; + if (template === "europe") return [20, 16]; + if (template === "europe-accented") return [14, 22]; + if (template === "europe-and-central-asia") return [25, 10]; + if (template === "europe-central") return [11, 22]; + if (template === "europe-north") return [7, 18]; + if (template === "greenland") return [22, 7]; + if (template === "hellenica") return [8, 27]; + if (template === "iceland") return [2, 15]; + if (template === "indian-ocean") return [45, 55]; + if (template === "mediterranean-sea") return [10, 29]; + if (template === "middle-east") return [8, 31]; + if (template === "north-america") return [37, 17]; + if (template === "us-centric") return [66, 27]; + if (template === "us-mainland") return [16, 30]; + if (template === "world") return [78, 27]; + if (template === "world-from-pacific") return [75, 32]; + const part = grid.features.some(f => f.land && f.border); // if land goes over map borders const max = part ? 80 : 100; // max size const lat = () => gauss(P(0.5) ? 40 : 60, 15, 25, 75); // latitude shift @@ -1485,14 +1544,12 @@ function rankCells() { TIME && console.timeEnd("rankCells"); } -// regenerate some zones +// generate zones function addZones(number = 1) { TIME && console.time("addZones"); - const data = [], - cells = pack.cells, - states = pack.states, - burgs = pack.burgs; + const {cells, states, burgs} = pack; const used = new Uint8Array(cells.i.length); // to store used cells + const zonesData = []; for (let i = 0; i < rn(Math.random() * 1.8 * number); i++) addInvasion(); // invasion of enemy lands for (let i = 0; i < rn(Math.random() * 1.6 * number); i++) addRebels(); // rebels along a state border @@ -1506,6 +1563,8 @@ function addZones(number = 1) { for (let i = 0; i < rn(Math.random() * 1.4 * number); i++) addFlood(); // flood on river banks for (let i = 0; i < rn(Math.random() * 1.2 * number); i++) addTsunami(); // tsunami starting near coast + drawZones(); + function addInvasion() { const atWar = states.filter(s => s.diplomacy && s.diplomacy.some(d => d === "Enemy")); if (!atWar.length) return; @@ -1546,7 +1605,7 @@ function addZones(number = 1) { Intervention: 1 }); const name = getAdjective(invader.name) + " " + invasion; - data.push({name, type: "Invasion", cells: cellsArray, fill: "url(#hatch1)"}); + zonesData.push({name, type: "Invasion", cells: cellsArray, fill: "url(#hatch1)"}); } function addRebels() { @@ -1582,7 +1641,7 @@ function addZones(number = 1) { const rebels = rw({Rebels: 5, Insurgents: 2, Mutineers: 1, Rioters: 1, Separatists: 1, Secessionists: 1, Insurrection: 2, Rebellion: 1, Conspiracy: 2}); const name = getAdjective(states[neib].name) + " " + rebels; - data.push({name, type: "Rebels", cells: cellsArray, fill: "url(#hatch3)"}); + zonesData.push({name, type: "Rebels", cells: cellsArray, fill: "url(#hatch3)"}); } function addProselytism() { @@ -1612,7 +1671,7 @@ function addZones(number = 1) { } const name = getAdjective(organized.name.split(" ")[0]) + " Proselytism"; - data.push({name, type: "Proselytism", cells: cellsArray, fill: "url(#hatch6)"}); + zonesData.push({name, type: "Proselytism", cells: cellsArray, fill: "url(#hatch6)"}); } function addCrusade() { @@ -1624,7 +1683,7 @@ function addZones(number = 1) { cellsArray.forEach(i => (used[i] = 1)); const name = getAdjective(heresy.name.split(" ")[0]) + " Crusade"; - data.push({name, type: "Crusade", cells: cellsArray, fill: "url(#hatch6)"}); + zonesData.push({name, type: "Crusade", cells: cellsArray, fill: "url(#hatch6)"}); } function addDisease() { @@ -1661,7 +1720,7 @@ function addZones(number = 1) { const type = rw({Fever: 5, Pestilence: 2, Flu: 2, Pox: 2, Smallpox: 2, Plague: 4, Cholera: 2, Dropsy: 1, Leprosy: 2}); const name = rw({[color()]: 4, [animal()]: 2, [adjective()]: 1}) + " " + type; - data.push({name, type: "Disease", cells: cellsArray, fill: "url(#hatch12)"}); + zonesData.push({name, type: "Disease", cells: cellsArray, fill: "url(#hatch12)"}); } function addDisaster() { @@ -1693,7 +1752,7 @@ function addZones(number = 1) { const type = rw({Famine: 5, Dearth: 1, Drought: 3, Earthquake: 3, Tornadoes: 1, Wildfires: 1}); const name = getAdjective(burg.name) + " " + type; - data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch5)"}); + zonesData.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch5)"}); } function addEruption() { @@ -1724,7 +1783,7 @@ function addZones(number = 1) { }); } - data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch7)"}); + zonesData.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch7)"}); } function addAvalanche() { @@ -1749,7 +1808,7 @@ function addZones(number = 1) { const proper = getAdjective(Names.getCultureShort(cells.culture[cell])); const name = proper + " Avalanche"; - data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch5)"}); + zonesData.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch5)"}); } function addFault() { @@ -1774,7 +1833,7 @@ function addZones(number = 1) { const proper = getAdjective(Names.getCultureShort(cells.culture[cell])); const name = proper + " Fault"; - data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch2)"}); + zonesData.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch2)"}); } function addFlood() { @@ -1804,7 +1863,7 @@ function addZones(number = 1) { } const name = getAdjective(burgs[cells.burg[cell]].name) + " Flood"; - data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch13)"}); + zonesData.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch13)"}); } function addTsunami() { @@ -1832,13 +1891,13 @@ function addZones(number = 1) { const proper = getAdjective(Names.getCultureShort(cells.culture[cell])); const name = proper + " Tsunami"; - data.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch13)"}); + zonesData.push({name, type: "Disaster", cells: cellsArray, fill: "url(#hatch13)"}); } - void (function drawZones() { + function drawZones() { zones .selectAll("g") - .data(data) + .data(zonesData) .enter() .append("g") .attr("id", (d, i) => "zone" + i) @@ -1854,7 +1913,7 @@ function addZones(number = 1) { .attr("id", function (d) { return this.parentNode.id + "_" + d; }); - })(); + } TIME && console.timeEnd("addZones"); } @@ -1881,16 +1940,18 @@ function showStatistics() { INFO && console.log(stats); } -const regenerateMap = debounce(function () { +const regenerateMap = debounce(async function () { WARN && console.warn("Generate new random map"); + showLoading(); closeDialogs("#worldConfigurator, #options3d"); customization = 0; - undraw(); resetZoom(1000); - generate(); + undraw(); + await generate(); restoreLayers(); if (ThreeD.options.isOn) ThreeD.redraw(); if ($("#worldConfigurator").is(":visible")) editWorld(); + hideLoading(); }, 1000); // clear the map diff --git a/modules/burgs-and-states.js b/modules/burgs-and-states.js index 865159aa..a9200868 100644 --- a/modules/burgs-and-states.js +++ b/modules/burgs-and-states.js @@ -595,7 +595,7 @@ window.BurgsAndStates = (function () { g.select("#stateLabel" + id).remove(); } - const path = p[1].length > 1 ? lineGen(p[1]) : `M${p[1][0][0] - 50},${p[1][0][1]}h${100}`; + const path = p[1].length > 1 ? round(lineGen(p[1])) : `M${p[1][0][0] - 50},${p[1][0][1]}h${100}`; const textPath = t .append("path") .attr("d", path) @@ -621,7 +621,7 @@ window.BurgsAndStates = (function () { const spans = lines.map((l, d) => { example.text(l); const left = example.node().getBBox().width / -2; // x offset - return `${l}`; + return `${l}`; }); const el = g diff --git a/modules/coa-generator.js b/modules/coa-generator.js index 2856759d..9491cc0d 100644 --- a/modules/coa-generator.js +++ b/modules/coa-generator.js @@ -976,7 +976,7 @@ window.COA = (function () { if (emblemShape.value === "state" && state && pack.states[state].coa) return pack.states[state].coa.shield; if (pack.cultures[culture].shield) return pack.cultures[culture].shield; - console.error("Shield shape is not defined on culture level", pack.cultures[culture]); + ERROR && console.error("Shield shape is not defined on culture level", pack.cultures[culture]); return "heater"; }; diff --git a/modules/coa-renderer.js b/modules/coa-renderer.js index 5cc4ab40..8bb6b777 100644 --- a/modules/coa-renderer.js +++ b/modules/coa-renderer.js @@ -1938,7 +1938,9 @@ window.COArenderer = (function () { g.setAttribute("id", charge + "_" + id); return g.outerHTML; }) - .catch(err => console.error(err)); + .catch(err => { + ERROR && console.error(err); + }); return fetched; } diff --git a/modules/fonts.js b/modules/fonts.js index 6637e0f4..652ee524 100644 --- a/modules/fonts.js +++ b/modules/fonts.js @@ -14,12 +14,14 @@ const fonts = [ { family: "Almendra SC", src: "url(https://fonts.gstatic.com/s/almendrasc/v13/Iure6Yx284eebowr7hbyTaZOrLQ.woff2)", - unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" + unicodeRange: + "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" }, { family: "Amatic SC", src: "url(https://fonts.gstatic.com/s/amaticsc/v11/TUZ3zwprpvBS1izr_vOMscGKfrUC.woff2)", - unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" + unicodeRange: + "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" }, { family: "Architects Daughter", @@ -34,7 +36,8 @@ const fonts = [ { family: "Caesar Dressing", src: "url(https://fonts.gstatic.com/s/caesardressing/v6/yYLx0hLa3vawqtwdswbotmK4vrRHdrz7.woff2)", - unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" + unicodeRange: + "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" }, { family: "Cinzel", @@ -49,7 +52,8 @@ const fonts = [ { family: "Fredericka the Great", src: "url(https://fonts.gstatic.com/s/frederickathegreat/v6/9Bt33CxNwt7aOctW2xjbCstzwVKsIBVV--Sjxbc.woff2)", - unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" + unicodeRange: + "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" }, { family: "Gloria Hallelujah", @@ -74,12 +78,14 @@ const fonts = [ { family: "MedievalSharp", src: "url(https://fonts.gstatic.com/s/medievalsharp/v9/EvOJzAlL3oU5AQl2mP5KdgptMqhwMg.woff2)", - unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" + unicodeRange: + "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" }, { family: "Metamorphous", src: "url(https://fonts.gstatic.com/s/metamorphous/v7/Wnz8HA03aAXcC39ZEX5y133EOyqs.woff2)", - unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" + unicodeRange: + "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" }, { family: "Montez", @@ -89,7 +95,8 @@ const fonts = [ { family: "Nova Script", src: "url(https://fonts.gstatic.com/s/novascript/v10/7Au7p_IpkSWSTWaFWkumvlQKGFw.woff2)", - unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" + unicodeRange: + "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" }, { family: "Orbitron", @@ -109,12 +116,14 @@ const fonts = [ { family: "Uncial Antiqua", src: "url(https://fonts.gstatic.com/s/uncialantiqua/v5/N0bM2S5WOex4OUbESzoESK-i-MfWQZQ.woff2)", - unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" + unicodeRange: + "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" }, { family: "Underdog", src: "url(https://fonts.gstatic.com/s/underdog/v6/CHygV-jCElj7diMroWSlWV8.woff2)", - unicodeRange: "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" + unicodeRange: + "U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD" }, { family: "Yellowtail", @@ -243,7 +252,7 @@ async function addGoogleFont(family) { }) .catch(err => { tip(`Failed to load Google font ${family}`, true, "error", 4000); - console.error(err); + ERROR && console.error(err); }); } diff --git a/modules/heightmap-generator.js b/modules/heightmap-generator.js index a2567bfd..0723a34a 100644 --- a/modules/heightmap-generator.js +++ b/modules/heightmap-generator.js @@ -3,13 +3,44 @@ window.HeightmapGenerator = (function () { let cells, p; - const generate = function () { - TIME && console.time("generateHeightmap"); + const generate = async function () { cells = grid.cells; p = grid.points; cells.h = new Uint8Array(grid.points.length); - const template = document.getElementById("templateInput").value; + const input = document.getElementById("templateInput"); + const selectedId = input.selectedIndex >= 0 ? input.selectedIndex : 0; + const type = input.options[selectedId]?.parentElement?.label; + + if (type === "Specific") { + // pre-defined heightmap + TIME && console.time("defineHeightmap"); + return new Promise(resolve => { + // create canvas where 1px correcponds to a cell + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d"); + const {cellsX, cellsY} = grid; + canvas.width = cellsX; + canvas.height = cellsY; + + // load heightmap into image and render to canvas + const img = new Image(); + img.src = `./heightmaps/${input.value}.png`; + img.onload = function () { + ctx.drawImage(img, 0, 0, cellsX, cellsY); + const imageData = ctx.getImageData(0, 0, cellsX, cellsY); + assignColorsToHeight(imageData.data); + canvas.remove(); + img.remove(); + TIME && console.timeEnd("defineHeightmap"); + resolve(); + }; + }); + } + + // heightmap template + TIME && console.time("generateHeightmap"); + const template = input.value; const templateString = HeightmapTemplates[template]; const steps = templateString.split("\n"); @@ -79,8 +110,8 @@ window.HeightmapGenerator = (function () { function addOneHill() { const change = new Uint8Array(cells.h.length); - let limit = 0, - start; + let limit = 0; + let start; let h = lim(getNumberInRange(height)); do { @@ -410,5 +441,13 @@ window.HeightmapGenerator = (function () { return rand(min * length, max * length); } + function assignColorsToHeight(imageData) { + for (let i = 0; i < cells.i.length; i++) { + const lightness = imageData[i * 4] / 255; + const powered = lightness < 0.2 ? lightness : 0.2 + (lightness - 0.2) ** 0.8; + cells.h[i] = minmax(Math.floor(powered * 100), 0, 100); + } + } + return {generate, addHill, addRange, addTrough, addStrait, addPit, smooth, modify}; })(); diff --git a/modules/io/auto-update.js b/modules/io/auto-update.js new file mode 100644 index 00000000..064af0ad --- /dev/null +++ b/modules/io/auto-update.js @@ -0,0 +1,523 @@ +"use strict"; + +// update old .map version to the current one +export function resolveVersionConflicts(version) { + if (version < 1) { + // v1.0 added a new religions layer + relig = viewbox.insert("g", "#terrain").attr("id", "relig"); + Religions.generate(); + + // v1.0 added a legend box + legend = svg.append("g").attr("id", "legend"); + legend + .attr("font-family", "Almendra SC") + .attr("font-size", 13) + .attr("data-size", 13) + .attr("data-x", 99) + .attr("data-y", 93) + .attr("stroke-width", 2.5) + .attr("stroke", "#812929") + .attr("stroke-dasharray", "0 4 10 4") + .attr("stroke-linecap", "round"); + + // v1.0 separated drawBorders fron drawStates() + stateBorders = borders.append("g").attr("id", "stateBorders"); + provinceBorders = borders.append("g").attr("id", "provinceBorders"); + borders + .attr("opacity", null) + .attr("stroke", null) + .attr("stroke-width", null) + .attr("stroke-dasharray", null) + .attr("stroke-linecap", null) + .attr("filter", null); + stateBorders.attr("opacity", 0.8).attr("stroke", "#56566d").attr("stroke-width", 1).attr("stroke-dasharray", "2").attr("stroke-linecap", "butt"); + provinceBorders.attr("opacity", 0.8).attr("stroke", "#56566d").attr("stroke-width", 0.5).attr("stroke-dasharray", "1").attr("stroke-linecap", "butt"); + + // v1.0 added state relations, provinces, forms and full names + provs = viewbox.insert("g", "#borders").attr("id", "provs").attr("opacity", 0.6); + BurgsAndStates.collectStatistics(); + BurgsAndStates.generateCampaigns(); + BurgsAndStates.generateDiplomacy(); + BurgsAndStates.defineStateForms(); + drawStates(); + BurgsAndStates.generateProvinces(); + drawBorders(); + if (!layerIsOn("toggleBorders")) $("#borders").fadeOut(); + if (!layerIsOn("toggleStates")) regions.attr("display", "none").selectAll("path").remove(); + + // v1.0 added zones layer + zones = viewbox.insert("g", "#borders").attr("id", "zones").attr("display", "none"); + zones.attr("opacity", 0.6).attr("stroke", null).attr("stroke-width", 0).attr("stroke-dasharray", null).attr("stroke-linecap", "butt"); + addZones(); + if (!markers.selectAll("*").size()) { + Markers.generate(); + turnButtonOn("toggleMarkers"); + } + + // v1.0 add fogging layer (state focus) + fogging = viewbox.insert("g", "#ruler").attr("id", "fogging-cont").attr("mask", "url(#fog)").append("g").attr("id", "fogging").style("display", "none"); + fogging.append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%"); + defs.append("mask").attr("id", "fog").append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%").attr("fill", "white"); + + // v1.0 changes states opacity bask to regions level + if (statesBody.attr("opacity")) { + regions.attr("opacity", statesBody.attr("opacity")); + statesBody.attr("opacity", null); + } + + // v1.0 changed labels to multi-lined + labels.selectAll("textPath").each(function () { + const text = this.textContent; + const shift = this.getComputedTextLength() / -1.5; + this.innerHTML = `${text}`; + }); + + // v1.0 added new biome - Wetland + biomesData.name.push("Wetland"); + biomesData.color.push("#0b9131"); + biomesData.habitability.push(12); + } + + if (version < 1.1) { + // v1.0 initial code had a bug with religion layer id + if (!relig.size()) relig = viewbox.insert("g", "#terrain").attr("id", "relig"); + + // v1.0 initially has Sympathy status then relaced with Friendly + for (const s of pack.states) { + if (!s.diplomacy) continue; + s.diplomacy = s.diplomacy.map(r => (r === "Sympathy" ? "Friendly" : r)); + } + + // labels should be toggled via style attribute, so remove display attribute + labels.attr("display", null); + + // v1.0 added religions heirarchy tree + if (pack.religions[1] && !pack.religions[1].code) { + pack.religions + .filter(r => r.i) + .forEach(r => { + r.origin = 0; + r.code = r.name.slice(0, 2); + }); + } + + if (!document.getElementById("freshwater")) { + lakes.append("g").attr("id", "freshwater"); + lakes.select("#freshwater").attr("opacity", 0.5).attr("fill", "#a6c1fd").attr("stroke", "#5f799d").attr("stroke-width", 0.7).attr("filter", null); + } + + if (!document.getElementById("salt")) { + lakes.append("g").attr("id", "salt"); + lakes.select("#salt").attr("opacity", 0.5).attr("fill", "#409b8a").attr("stroke", "#388985").attr("stroke-width", 0.7).attr("filter", null); + } + + // v1.1 added new lake and coast groups + if (!document.getElementById("sinkhole")) { + lakes.append("g").attr("id", "sinkhole"); + lakes.append("g").attr("id", "frozen"); + lakes.append("g").attr("id", "lava"); + lakes.select("#sinkhole").attr("opacity", 1).attr("fill", "#5bc9fd").attr("stroke", "#53a3b0").attr("stroke-width", 0.7).attr("filter", null); + lakes.select("#frozen").attr("opacity", 0.95).attr("fill", "#cdd4e7").attr("stroke", "#cfe0eb").attr("stroke-width", 0).attr("filter", null); + lakes.select("#lava").attr("opacity", 0.7).attr("fill", "#90270d").attr("stroke", "#f93e0c").attr("stroke-width", 2).attr("filter", "url(#crumpled)"); + + coastline.append("g").attr("id", "sea_island"); + coastline.append("g").attr("id", "lake_island"); + coastline.select("#sea_island").attr("opacity", 0.5).attr("stroke", "#1f3846").attr("stroke-width", 0.7).attr("filter", "url(#dropShadow)"); + coastline.select("#lake_island").attr("opacity", 1).attr("stroke", "#7c8eaf").attr("stroke-width", 0.35).attr("filter", null); + } + + // v1.1 features stores more data + defs.select("#land").selectAll("path").remove(); + defs.select("#water").selectAll("path").remove(); + coastline.selectAll("path").remove(); + lakes.selectAll("path").remove(); + drawCoastline(); + } + + if (version < 1.11) { + // v1.11 added new attributes + terrs.attr("scheme", "bright").attr("terracing", 0).attr("skip", 5).attr("relax", 0).attr("curve", 0); + svg.select("#oceanic > *").attr("id", "oceanicPattern"); + oceanLayers.attr("layers", "-6,-3,-1"); + gridOverlay.attr("type", "pointyHex").attr("size", 10); + + // v1.11 added cultures heirarchy tree + if (pack.cultures[1] && !pack.cultures[1].code) { + pack.cultures + .filter(c => c.i) + .forEach(c => { + c.origin = 0; + c.code = c.name.slice(0, 2); + }); + } + + // v1.11 had an issue with fogging being displayed on load + unfog(); + + // v1.2 added new terrain attributes + if (!terrain.attr("set")) terrain.attr("set", "simple"); + if (!terrain.attr("size")) terrain.attr("size", 1); + if (!terrain.attr("density")) terrain.attr("density", 0.4); + } + + if (version < 1.21) { + // v1.11 replaced "display" attribute by "display" style + viewbox.selectAll("g").each(function () { + if (this.hasAttribute("display")) { + this.removeAttribute("display"); + this.style.display = "none"; + } + }); + + // v1.21 added rivers data to pack + pack.rivers = []; // rivers data + rivers.selectAll("path").each(function () { + const i = +this.id.slice(5); + const length = this.getTotalLength() / 2; + const s = this.getPointAtLength(length), + e = this.getPointAtLength(0); + const source = findCell(s.x, s.y), + mouth = findCell(e.x, e.y); + const name = Rivers.getName(mouth); + const type = length < 25 ? rw({Creek: 9, River: 3, Brook: 3, Stream: 1}) : "River"; + pack.rivers.push({i, parent: 0, length, source, mouth, basin: i, name, type}); + }); + } + + if (version < 1.22) { + // v1.22 changed state neighbors from Set object to array + BurgsAndStates.collectStatistics(); + } + + if (version < 1.3) { + // v1.3 added global options object + const winds = options.slice(); // previostly wind was saved in settings[19] + const year = rand(100, 2000); + const era = Names.getBaseShort(P(0.7) ? 1 : rand(nameBases.length)) + " Era"; + const eraShort = era[0] + "E"; + const military = Military.getDefaultOptions(); + options = {winds, year, era, eraShort, military}; + + // v1.3 added campaings data for all states + BurgsAndStates.generateCampaigns(); + + // v1.3 added militry layer + armies = viewbox.insert("g", "#icons").attr("id", "armies"); + armies.attr("opacity", 1).attr("fill-opacity", 1).attr("font-size", 6).attr("box-size", 3).attr("stroke", "#000").attr("stroke-width", 0.3); + turnButtonOn("toggleMilitary"); + Military.generate(); + } + + if (version < 1.4) { + // v1.35 added dry lakes + if (!lakes.select("#dry").size()) { + lakes.append("g").attr("id", "dry"); + lakes.select("#dry").attr("opacity", 1).attr("fill", "#c9bfa7").attr("stroke", "#8e816f").attr("stroke-width", 0.7).attr("filter", null); + } + + // v1.4 added ice layer + ice = viewbox.insert("g", "#coastline").attr("id", "ice").style("display", "none"); + ice.attr("opacity", null).attr("fill", "#e8f0f6").attr("stroke", "#e8f0f6").attr("stroke-width", 1).attr("filter", "url(#dropShadow05)"); + drawIce(); + + // v1.4 added icon and power attributes for units + for (const unit of options.military) { + if (!unit.icon) unit.icon = getUnitIcon(unit.type); + if (!unit.power) unit.power = unit.crew; + } + + function getUnitIcon(type) { + if (type === "naval") return "🌊"; + if (type === "ranged") return "🏹"; + if (type === "mounted") return "🐴"; + if (type === "machinery") return "💣"; + if (type === "armored") return "🐢"; + if (type === "aviation") return "🦅"; + if (type === "magical") return "🔮"; + else return "⚔️"; + } + + // v1.4 added state reference for regiments + pack.states.filter(s => s.military).forEach(s => s.military.forEach(r => (r.state = s.i))); + } + + if (version < 1.5) { + // not need to store default styles from v 1.5 + localStorage.removeItem("styleClean"); + localStorage.removeItem("styleGloom"); + localStorage.removeItem("styleAncient"); + localStorage.removeItem("styleMonochrome"); + + // v1.5 cultures has shield attribute + pack.cultures.forEach(culture => { + if (culture.removed) return; + culture.shield = Cultures.getRandomShield(); + }); + + // v1.5 added burg type value + pack.burgs.forEach(burg => { + if (!burg.i || burg.removed) return; + burg.type = BurgsAndStates.getType(burg.cell, burg.port); + }); + + // v1.5 added emblems + defs.append("g").attr("id", "defs-emblems"); + emblems = viewbox.insert("g", "#population").attr("id", "emblems").style("display", "none"); + emblems.append("g").attr("id", "burgEmblems"); + emblems.append("g").attr("id", "provinceEmblems"); + emblems.append("g").attr("id", "stateEmblems"); + regenerateEmblems(); + toggleEmblems(); + + // v1.5 changed releif icons data + terrain.selectAll("use").each(function () { + const type = this.getAttribute("data-type") || this.getAttribute("xlink:href"); + this.removeAttribute("xlink:href"); + this.removeAttribute("data-type"); + this.removeAttribute("data-size"); + this.setAttribute("href", type); + }); + } + + if (version < 1.6) { + // v1.6 changed rivers data + for (const river of pack.rivers) { + const el = document.getElementById("river" + river.i); + if (el) { + river.widthFactor = +el.getAttribute("data-width"); + el.removeAttribute("data-width"); + el.removeAttribute("data-increment"); + river.discharge = pack.cells.fl[river.mouth] || 1; + river.width = rn(river.length / 100, 2); + river.sourceWidth = 0.1; + } else { + Rivers.remove(river.i); + } + } + + // v1.6 changed lakes data + for (const f of pack.features) { + if (f.type !== "lake") continue; + if (f.evaporation) continue; + + f.flux = f.flux || f.cells * 3; + f.temp = grid.cells.temp[pack.cells.g[f.firstCell]]; + f.height = f.height || d3.min(pack.cells.c[f.firstCell].map(c => pack.cells.h[c]).filter(h => h >= 20)); + const height = (f.height - 18) ** heightExponentInput.value; + const evaporation = ((700 * (f.temp + 0.006 * height)) / 50 + 75) / (80 - f.temp); + f.evaporation = rn(evaporation * f.cells); + f.name = f.name || Lakes.getName(f); + delete f.river; + } + } + + if (version < 1.61) { + // v1.61 changed rulers data + ruler.style("display", null); + rulers = new Rulers(); + + ruler.selectAll(".ruler > .white").each(function () { + const x1 = +this.getAttribute("x1"); + const y1 = +this.getAttribute("y1"); + const x2 = +this.getAttribute("x2"); + const y2 = +this.getAttribute("y2"); + if (isNaN(x1) || isNaN(y1) || isNaN(x2) || isNaN(y2)) return; + const points = [ + [x1, y1], + [x2, y2] + ]; + rulers.create(Ruler, points); + }); + + ruler.selectAll("g.opisometer").each(function () { + const pointsString = this.dataset.points; + if (!pointsString) return; + const points = JSON.parse(pointsString); + rulers.create(Opisometer, points); + }); + + ruler.selectAll("path.planimeter").each(function () { + const length = this.getTotalLength(); + if (length < 30) return; + + const step = length > 1000 ? 40 : length > 400 ? 20 : 10; + const increment = length / Math.ceil(length / step); + const points = []; + for (let i = 0; i <= length; i += increment) { + const point = this.getPointAtLength(i); + points.push([point.x | 0, point.y | 0]); + } + + rulers.create(Planimeter, points); + }); + + ruler.selectAll("*").remove(); + + if (rulers.data.length) { + turnButtonOn("toggleRulers"); + rulers.draw(); + } else turnButtonOff("toggleRulers"); + + // 1.61 changed oceanicPattern from rect to image + const pattern = document.getElementById("oceanic"); + const filter = pattern.firstElementChild.getAttribute("filter"); + const href = filter ? "./images/" + filter.replace("url(#", "").replace(")", "") + ".png" : ""; + pattern.innerHTML = ``; + } + + if (version < 1.62) { + // v1.62 changed grid data + gridOverlay.attr("size", null); + } + + if (version < 1.63) { + // v1.63 changed ocean pattern opacity element + const oceanPattern = document.getElementById("oceanPattern"); + if (oceanPattern) oceanPattern.removeAttribute("opacity"); + const oceanicPattern = document.getElementById("oceanicPattern"); + if (!oceanicPattern.getAttribute("opacity")) oceanicPattern.setAttribute("opacity", 0.2); + + // v 1.63 moved label text-shadow from css to editable inline style + burgLabels.select("#cities").style("text-shadow", "white 0 0 4px"); + burgLabels.select("#towns").style("text-shadow", "white 0 0 4px"); + labels.select("#states").style("text-shadow", "white 0 0 4px"); + labels.select("#addedLabels").style("text-shadow", "white 0 0 4px"); + } + + if (version < 1.64) { + // v1.64 change states style + const opacity = regions.attr("opacity"); + const filter = regions.attr("filter"); + statesBody.attr("opacity", opacity).attr("filter", filter); + statesHalo.attr("opacity", opacity).attr("filter", "blur(5px)"); + regions.attr("opacity", null).attr("filter", null); + } + + if (version < 1.65) { + // v1.65 changed rivers data + d3.select("#rivers").attr("style", null); // remove style to unhide layer + const {cells, rivers} = pack; + const defaultWidthFactor = rn(1 / (pointsInput.dataset.cells / 10000) ** 0.25, 2); + + for (const river of rivers) { + const node = document.getElementById("river" + river.i); + if (node && !river.cells) { + const riverCells = []; + const riverPoints = []; + + const length = node.getTotalLength() / 2; + if (!length) continue; + const segments = Math.ceil(length / 6); + const increment = length / segments; + + for (let i = 0; i <= segments; i++) { + const shift = increment * i; + const {x: x1, y: y1} = node.getPointAtLength(length + shift); + const {x: x2, y: y2} = node.getPointAtLength(length - shift); + const x = rn((x1 + x2) / 2, 1); + const y = rn((y1 + y2) / 2, 1); + + const cell = findCell(x, y); + riverPoints.push([x, y]); + riverCells.push(cell); + } + + river.cells = riverCells; + river.points = riverPoints; + } + + river.widthFactor = defaultWidthFactor; + + cells.i.forEach(i => { + const riverInWater = cells.r[i] && cells.h[i] < 20; + if (riverInWater) cells.r[i] = 0; + }); + } + } + + if (version < 1.652) { + // remove style to unhide layers + rivers.attr("style", null); + borders.attr("style", null); + } + + if (version < 1.7) { + // v1.7 changed markers data + const defs = document.getElementById("defs-markers"); + const markersGroup = document.getElementById("markers"); + + if (defs && markersGroup) { + const markerElements = markersGroup.querySelectorAll("use"); + const rescale = +markersGroup.getAttribute("rescale"); + + pack.markers = Array.from(markerElements).map((el, i) => { + const id = el.getAttribute("id"); + const note = notes.find(note => note.id === id); + if (note) note.id = `marker${i}`; + + let x = +el.dataset.x; + let y = +el.dataset.y; + + const transform = el.getAttribute("transform"); + if (transform) { + const [dx, dy] = parseTransform(transform); + if (dx) x += +dx; + if (dy) y += +dy; + } + const cell = findCell(x, y); + const size = rn(rescale ? el.dataset.size * 30 : el.getAttribute("width"), 1); + + const href = el.href.baseVal; + const type = href.replace("#marker_", ""); + const symbol = defs?.querySelector(`symbol${href}`); + const text = symbol?.querySelector("text"); + const circle = symbol?.querySelector("circle"); + + const icon = text?.innerHTML; + const px = text && Number(text.getAttribute("font-size")?.replace("px", "")); + const dx = text && Number(text.getAttribute("x")?.replace("%", "")); + const dy = text && Number(text.getAttribute("y")?.replace("%", "")); + const fill = circle && circle.getAttribute("fill"); + const stroke = circle && circle.getAttribute("stroke"); + + const marker = {i, icon, type, x, y, size, cell}; + if (size && size !== 30) marker.size = size; + if (!isNaN(px) && px !== 12) marker.px = px; + if (!isNaN(dx) && dx !== 50) marker.dx = dx; + if (!isNaN(dy) && dy !== 50) marker.dy = dy; + if (fill && fill !== "#ffffff") marker.fill = fill; + if (stroke && stroke !== "#000000") marker.stroke = stroke; + if (circle?.getAttribute("opacity") === "0") marker.pin = "no"; + + return marker; + }); + + markersGroup.style.display = null; + defs?.remove(); + markerElements.forEach(el => el.remove()); + if (layerIsOn("markers")) drawMarkers(); + } + } + + if (version < 1.72) { + // v1.72 renamed custom style presets + const storedStyles = Object.keys(localStorage).filter(key => key.startsWith("style")); + storedStyles.forEach(styleName => { + const style = localStorage.getItem(styleName); + const newStyleName = styleName.replace(/^style/, customPresetPrefix); + localStorage.setItem(newStyleName, style); + localStorage.removeItem(styleName); + }); + } + + if (version < 1.73) { + // v1.73 moved the hatching patterns out of the user's SVG + document.getElementById("hatching")?.remove(); + + // v1.73 added zone type to UI, ensure type is populated + const zones = Array.from(document.querySelectorAll("#zones > g")); + zones.forEach(zone => { + if (!zone.dataset.type) zone.dataset.type = "Unknown"; + }); + } +} diff --git a/modules/cloud.js b/modules/io/cloud.js similarity index 58% rename from modules/cloud.js rename to modules/io/cloud.js index cfe5db77..54f42bce 100644 --- a/modules/cloud.js +++ b/modules/io/cloud.js @@ -12,7 +12,6 @@ async load(filename): load filename from provider async list(): list available filenames at provider async getLink(filePath): get shareable link for file restore(): restore access tokens from storage if possible - */ window.Cloud = (function () { @@ -32,38 +31,40 @@ window.Cloud = (function () { token: null, // Access token api: null, - restore() { - this.token = getToken(this.name); - if (this.token) this.connect(this.token); - }, - async call(name, param) { try { + if (!this.api) await this.initialize(); return await this.api[name](param); } catch (e) { if (e.name !== "DropboxResponseError") throw e; - // retry with auth - await this.auth(); + await this.auth(); // retry with auth return await this.api[name](param); } }, - connect(token) { - const clientId = this.clientId; - const auth = new Dropbox.DropboxAuth({clientId}); + initialize() { + const token = getToken(this.name); + if (token) { + return this.connect(token); + } else { + return this.auth(); + } + }, + + async connect(token) { + await import("https://unpkg.com/dropbox@10.8.0/dist/Dropbox-sdk.min.js"); + const auth = new Dropbox.DropboxAuth({clientId: this.clientId}); auth.setAccessToken(token); this.api = new Dropbox.Dropbox({auth}); }, async save(fileName, contents) { - if (!this.api) await this.auth(); - const resp = this.call("filesUpload", {path: "/" + fileName, contents}); + const resp = await this.call("filesUpload", {path: "/" + fileName, contents}); DEBUG && console.log("Dropbox response:", resp); return true; }, async load(path) { - if (!this.api) await this.auth(); const resp = await this.call("filesDownload", {path}); const blob = resp.result.fileBlob; if (!blob) throw new Error("Invalid response from dropbox."); @@ -71,22 +72,23 @@ window.Cloud = (function () { }, async list() { - if (!this.api) return null; const resp = await this.call("filesListFolder", {path: ""}); return resp.result.entries.map(e => ({name: e.name, path: e.path_lower})); }, auth() { - const url = window.location.origin + window.location.pathname + "dropbox.html"; - this.authWindow = window.open(url, "auth", "width=640,height=480"); - // child window expected to call - // window.opener.Cloud.providers.dropbox.setDropBoxToken (see below) + const width = 640; + const height = 480; + const left = window.innerWidth / 2 - width / 2; + const top = window.innerHeight / 2 - height / 2.5; + this.authWindow = window.open("./dropbox.html", "auth", `width=640, height=${height}, top=${top}, left=${left}}`); + return new Promise((resolve, reject) => { - const watchDog = () => { + const watchDog = setTimeout(() => { this.authWindow.close(); - reject(new Error("Timeout. No auth for dropbox.")); - }; - setTimeout(watchDog, 120 * 1000); + reject(new Error("Timeout. No auth for Dropbox")); + }, 120 * 1000); + window.addEventListener("dropboxauth", e => { clearTimeout(watchDog); resolve(); @@ -94,46 +96,34 @@ window.Cloud = (function () { }); }, - // Callback function for auth window. - setDropBoxToken(token) { + // Callback function for auth window + async setDropBoxToken(token) { DEBUG && console.log("Access token:", token); setToken(this.name, token); - this.connect(token); + await this.connect(token); this.authWindow.close(); window.dispatchEvent(new Event("dropboxauth")); }, + returnError(errorDescription) { + console.error(errorDescription); + tip(errorDescription.replaceAll("+", " "), true, "error", 4000); + this.authWindow.close(); + }, + async getLink(path) { - if (!this.api) await this.auth(); - let resp; + // return existitng shared link + const sharedLinks = await this.call("sharingListSharedLinks", {path}); + if (sharedLinks.result.links.length) return resp.result.links[0].url; - // already exists? - resp = await this.call("sharingListSharedLinks", {path}); - if (resp.result.links.length) return resp.result.links[0].url; - - // create new - resp = await this.call("sharingCreateSharedLinkWithSettings", { - path, - settings: { - require_password: false, - audience: "public", - access: "viewer", - requested_visibility: "public", - allow_download: true - } - }); + // create new shared link + const settings = {require_password: false, audience: "public", access: "viewer", requested_visibility: "public", allow_download: true}; + const resp = await this.call("sharingCreateSharedLinkWithSettings", {path, settings}); DEBUG && console.log("Dropbox link object:", resp.result); return resp.result.url; } }; - // register providers here: - const providers = { - dropbox: DBP - }; - - // restore all providers at startup - for (const p of Object.values(providers)) p.restore(); - + const providers = {dropbox: DBP}; return {providers}; })(); diff --git a/modules/io/export-json.js b/modules/io/export-json.js new file mode 100644 index 00000000..28d87a09 --- /dev/null +++ b/modules/io/export-json.js @@ -0,0 +1,209 @@ +function exportToJson(type) { + if (customization) return tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error"); + closeDialogs("#alert"); + + const typeMap = { + Full: getFullDataJson, + Minimal: getMinimalDataJson, + PackCells: getPackCellsDataJson, + GridCells: getGridCellsDataJson, + }; + + const mapData = typeMap[type](); + const blob = new Blob([mapData], {type: "application/json"}); + const URL = window.URL.createObjectURL(blob); + const link = document.createElement("a"); + link.download = getFileName(type) + ".json"; + link.href = URL; + link.click(); + tip(`${link.download} is saved. Open "Downloads" screen (CTRL + J) to check`, true, "success", 7000); + window.URL.revokeObjectURL(URL); +} + +function getMapInfo() { + const info = { + version, + description: "Azgaar's Fantasy Map Generator output: azgaar.github.io/Fantasy-map-generator", + exportedAt: new Date().toISOString(), + mapName: mapName.value, + seed, + mapId + }; + + return info; +} + +function getSettings() { + const settings = { + distanceUnit: distanceUnitInput.value, + distanceScale: distanceScaleInput.value, + areaUnit: areaUnit.value, + heightUnit: heightUnit.value, + heightExponent: heightExponentInput.value, + temperatureScale: temperatureScale.value, + barSize: barSizeInput.value, + barLabel: barLabel.value, + barBackOpacity: barBackOpacity.value, + barBackColor: barBackColor.value, + barPosX: barPosX.value, + barPosY: barPosY.value, + populationRate: populationRate, + urbanization: urbanization, + mapSize: mapSizeOutput.value, + latitudeO: latitudeOutput.value, + temperatureEquator: temperatureEquatorOutput.value, + temperaturePole: temperaturePoleOutput.value, + prec: precOutput.value, + options: options, + mapName: mapName.value, + hideLabels: hideLabels.checked, + stylePreset: stylePreset.value, + rescaleLabels: rescaleLabels.checked, + urbanDensity: urbanDensity + }; + + return settings; +} + +function getPackCellsData() { + const cellConverted = { + i: Array.from(pack.cells.i), + v: pack.cells.v, + c: pack.cells.c, + p: pack.cells.p, + g: Array.from(pack.cells.g), + h: Array.from(pack.cells.h), + area: Array.from(pack.cells.area), + f: Array.from(pack.cells.f), + t: Array.from(pack.cells.t), + haven: Array.from(pack.cells.haven), + harbor: Array.from(pack.cells.harbor), + fl: Array.from(pack.cells.fl), + r: Array.from(pack.cells.r), + conf: Array.from(pack.cells.conf), + biome: Array.from(pack.cells.biome), + s: Array.from(pack.cells.s), + pop: Array.from(pack.cells.pop), + culture: Array.from(pack.cells.culture), + burg: Array.from(pack.cells.burg), + road: Array.from(pack.cells.road), + crossroad: Array.from(pack.cells.crossroad), + state: Array.from(pack.cells.state), + religion: Array.from(pack.cells.religion), + province: Array.from(pack.cells.province) + }; + const cellObjArr = []; + { + cellConverted.i.forEach(value => { + const cellobj = { + i: value, + v: cellConverted.v[value], + c: cellConverted.c[value], + p: cellConverted.p[value], + g: cellConverted.g[value], + h: cellConverted.h[value], + area: cellConverted.area[value], + f: cellConverted.f[value], + t: cellConverted.t[value], + haven: cellConverted.haven[value], + harbor: cellConverted.harbor[value], + fl: cellConverted.fl[value], + r: cellConverted.r[value], + conf: cellConverted.conf[value], + biome: cellConverted.biome[value], + s: cellConverted.s[value], + pop: cellConverted.pop[value], + culture: cellConverted.culture[value], + burg: cellConverted.burg[value], + road: cellConverted.road[value], + crossroad: cellConverted.crossroad[value], + state: cellConverted.state[value], + religion: cellConverted.religion[value], + province: cellConverted.province[value] + }; + cellObjArr.push(cellobj); + }); + } + + const cellsData = { + cells: cellObjArr, + features: pack.features, + cultures: pack.cultures, + burgs: pack.burgs, + states: pack.states, + provinces: pack.provinces, + religions: pack.religions, + rivers: pack.rivers, + markers: pack.markers + }; + + return cellsData; +} + +//data only containing graphical appearance +function getGridCellsData(){ + const gridData = { + spacing: grid.spacing, + cellsY: grid.cellsY, + cellsX: grid.cellsX, + points: grid.points, + boundary: grid.boundary + } + return gridData +} + +function getFullDataJson() { + TIME && console.time("getFullDataJson"); + + const info = getMapInfo(); + const settings = getSettings(); + const cells = getPackCellsData(); + const exportData = {info, settings, coords: mapCoordinates, cells, biomes: biomesData, notes, nameBases}; + + TIME && console.timeEnd("getFullDataJson"); + return JSON.stringify(exportData); +} + +// data excluding cells +function getMinimalDataJson() { + TIME && console.time("getMinimalDataJson"); + + const info = getMapInfo(); + const settings = getSettings(); + const packData = { + features: pack.features, + cultures: pack.cultures, + burgs: pack.burgs, + states: pack.states, + provinces: pack.provinces, + religions: pack.religions, + rivers: pack.rivers, + markers: pack.markers + }; + const exportData = {info, settings, coords: mapCoordinates, pack: packData, biomes: biomesData, notes, nameBases}; + + TIME && console.timeEnd("getMinimalDataJson"); + return JSON.stringify(exportData); +} + +function getPackCellsDataJson() { + TIME && console.time("getCellsDataJson"); + + const info = getMapInfo(); + const cells = getPackCellsData(); + const exportData = {info, cells}; + + TIME && console.timeEnd("getCellsDataJson"); + return JSON.stringify(exportData); +} + +function getGridCellsDataJson() { + TIME && console.time("getGridCellsDataJson"); + + const info = getMapInfo(); + const gridCells = getGridCellsData() + const exportData = {info,gridCells}; + + TIME && console.log("getGridCellsDataJson"); + return JSON.stringify(exportData); +} \ No newline at end of file diff --git a/modules/export.js b/modules/io/export.js similarity index 96% rename from modules/export.js rename to modules/io/export.js index 7b88a7e6..5d30d013 100644 --- a/modules/export.js +++ b/modules/io/export.js @@ -262,19 +262,19 @@ async function getMapURL(type, options = {}) { if (pattern) cloneDefs.appendChild(pattern.cloneNode(true)); } - if (!cloneEl.getElementById("hatching").children.length) cloneEl.getElementById("hatching")?.remove(); // remove unused hatching group if (!cloneEl.getElementById("fogging-cont")) cloneEl.getElementById("fog")?.remove(); // remove unused fog if (!cloneEl.getElementById("regions")) cloneEl.getElementById("statePaths")?.remove(); // removed unused statePaths if (!cloneEl.getElementById("labels")) cloneEl.getElementById("textPaths")?.remove(); // removed unused textPaths // add armies style - if (cloneEl.getElementById("armies")) + if (cloneEl.getElementById("armies")) { cloneEl.insertAdjacentHTML( "afterbegin", "" ); + } - // add xlink: for href to support svg1.1 + // add xlink: for href to support svg 1.1 if (type === "svg") { cloneEl.querySelectorAll("[href]").forEach(el => { const href = el.getAttribute("href"); @@ -283,6 +283,16 @@ async function getMapURL(type, options = {}) { }); } + // add hatchings + const hatchingUsers = cloneEl.querySelectorAll(`[fill^='url(#hatch']`); + const hatchingFills = unique(Array.from(hatchingUsers).map(el => el.getAttribute("fill"))); + const hatchingIds = hatchingFills.map(fill => fill.slice(5, -1)); + for (const hatchingId of hatchingIds) { + const hatching = svgDefs.getElementById(hatchingId); + if (hatching) cloneDefs.appendChild(hatching.cloneNode(true)); + } + + // load fonts const usedFonts = getUsedFonts(cloneEl); const fontsToLoad = usedFonts.filter(font => font.src); if (fontsToLoad.length) { diff --git a/modules/load.js b/modules/io/load.js similarity index 52% rename from modules/load.js rename to modules/io/load.js index c6102d37..5d35afb8 100644 --- a/modules/load.js +++ b/modules/io/load.js @@ -145,7 +145,7 @@ function parseLoadedResult(result) { const mapVersion = parseFloat(mapData[0].split("|")[0] || mapData[0]); return [mapData, mapVersion]; } catch (error) { - console.error(error); + ERROR && console.error(error); return [null, null]; } } @@ -182,18 +182,15 @@ function showUploadMessage(type, mapData, mapVersion) { $("#alert").dialog({title, buttons}); } -function parseLoadedData(data) { +async function parseLoadedData(data) { try { // exit customization if (window.closeDialogs) closeDialogs(); customization = 0; if (customizationMenu.offsetParent) styleTab.click(); - const reliefIcons = document.getElementById("defs-relief").innerHTML; // save relief icons - const hatching = document.getElementById("hatching").cloneNode(true); // save hatching - + const params = data[0].split("|"); void (function parseParameters() { - const params = data[0].split("|"); if (params[3]) { seed = params[3]; optionsSeed.value = seed; @@ -423,513 +420,12 @@ function parseLoadedData(data) { legend.on("mousemove", () => tip("Drag to change the position. Click to hide the legend")).on("click", () => clearLegend()); })(); - void (function resolveVersionConflicts() { - const version = parseFloat(data[0].split("|")[0]); - if (version < 0.9) { - // 0.9 has additional relief icons to be included into older maps - document.getElementById("defs-relief").innerHTML = reliefIcons; - } - - if (version < 1) { - // 1.0 adds a new religions layer - relig = viewbox.insert("g", "#terrain").attr("id", "relig"); - Religions.generate(); - - // 1.0 adds a legend box - legend = svg.append("g").attr("id", "legend"); - legend - .attr("font-family", "Almendra SC") - .attr("font-size", 13) - .attr("data-size", 13) - .attr("data-x", 99) - .attr("data-y", 93) - .attr("stroke-width", 2.5) - .attr("stroke", "#812929") - .attr("stroke-dasharray", "0 4 10 4") - .attr("stroke-linecap", "round"); - - // 1.0 separated drawBorders fron drawStates() - stateBorders = borders.append("g").attr("id", "stateBorders"); - provinceBorders = borders.append("g").attr("id", "provinceBorders"); - borders - .attr("opacity", null) - .attr("stroke", null) - .attr("stroke-width", null) - .attr("stroke-dasharray", null) - .attr("stroke-linecap", null) - .attr("filter", null); - stateBorders.attr("opacity", 0.8).attr("stroke", "#56566d").attr("stroke-width", 1).attr("stroke-dasharray", "2").attr("stroke-linecap", "butt"); - provinceBorders.attr("opacity", 0.8).attr("stroke", "#56566d").attr("stroke-width", 0.5).attr("stroke-dasharray", "1").attr("stroke-linecap", "butt"); - - // 1.0 adds state relations, provinces, forms and full names - provs = viewbox.insert("g", "#borders").attr("id", "provs").attr("opacity", 0.6); - BurgsAndStates.collectStatistics(); - BurgsAndStates.generateCampaigns(); - BurgsAndStates.generateDiplomacy(); - BurgsAndStates.defineStateForms(); - drawStates(); - BurgsAndStates.generateProvinces(); - drawBorders(); - if (!layerIsOn("toggleBorders")) $("#borders").fadeOut(); - if (!layerIsOn("toggleStates")) regions.attr("display", "none").selectAll("path").remove(); - - // 1.0 adds hatching - document.getElementsByTagName("defs")[0].appendChild(hatching); - - // 1.0 adds zones layer - zones = viewbox.insert("g", "#borders").attr("id", "zones").attr("display", "none"); - zones.attr("opacity", 0.6).attr("stroke", null).attr("stroke-width", 0).attr("stroke-dasharray", null).attr("stroke-linecap", "butt"); - addZones(); - if (!markers.selectAll("*").size()) { - Markers.generate(); - turnButtonOn("toggleMarkers"); - } - - // 1.0 add fogging layer (state focus) - fogging = viewbox.insert("g", "#ruler").attr("id", "fogging-cont").attr("mask", "url(#fog)").append("g").attr("id", "fogging").style("display", "none"); - fogging.append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%"); - defs.append("mask").attr("id", "fog").append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%").attr("fill", "white"); - - // 1.0 changes states opacity bask to regions level - if (statesBody.attr("opacity")) { - regions.attr("opacity", statesBody.attr("opacity")); - statesBody.attr("opacity", null); - } - - // 1.0 changed labels to multi-lined - labels.selectAll("textPath").each(function () { - const text = this.textContent; - const shift = this.getComputedTextLength() / -1.5; - this.innerHTML = `${text}`; - }); - - // 1.0 added new biome - Wetland - biomesData.name.push("Wetland"); - biomesData.color.push("#0b9131"); - biomesData.habitability.push(12); - } - - if (version < 1.1) { - // v 1.0 initial code had a bug with religion layer id - if (!relig.size()) relig = viewbox.insert("g", "#terrain").attr("id", "relig"); - - // v 1.0 initially has Sympathy status then relaced with Friendly - for (const s of pack.states) { - if (!s.diplomacy) continue; - s.diplomacy = s.diplomacy.map(r => (r === "Sympathy" ? "Friendly" : r)); - } - - // labels should be toggled via style attribute, so remove display attribute - labels.attr("display", null); - - // v 1.0 added religions heirarchy tree - if (pack.religions[1] && !pack.religions[1].code) { - pack.religions - .filter(r => r.i) - .forEach(r => { - r.origin = 0; - r.code = r.name.slice(0, 2); - }); - } - - if (!document.getElementById("freshwater")) { - lakes.append("g").attr("id", "freshwater"); - lakes.select("#freshwater").attr("opacity", 0.5).attr("fill", "#a6c1fd").attr("stroke", "#5f799d").attr("stroke-width", 0.7).attr("filter", null); - } - - if (!document.getElementById("salt")) { - lakes.append("g").attr("id", "salt"); - lakes.select("#salt").attr("opacity", 0.5).attr("fill", "#409b8a").attr("stroke", "#388985").attr("stroke-width", 0.7).attr("filter", null); - } - - // v 1.1 added new lake and coast groups - if (!document.getElementById("sinkhole")) { - lakes.append("g").attr("id", "sinkhole"); - lakes.append("g").attr("id", "frozen"); - lakes.append("g").attr("id", "lava"); - lakes.select("#sinkhole").attr("opacity", 1).attr("fill", "#5bc9fd").attr("stroke", "#53a3b0").attr("stroke-width", 0.7).attr("filter", null); - lakes.select("#frozen").attr("opacity", 0.95).attr("fill", "#cdd4e7").attr("stroke", "#cfe0eb").attr("stroke-width", 0).attr("filter", null); - lakes.select("#lava").attr("opacity", 0.7).attr("fill", "#90270d").attr("stroke", "#f93e0c").attr("stroke-width", 2).attr("filter", "url(#crumpled)"); - - coastline.append("g").attr("id", "sea_island"); - coastline.append("g").attr("id", "lake_island"); - coastline.select("#sea_island").attr("opacity", 0.5).attr("stroke", "#1f3846").attr("stroke-width", 0.7).attr("filter", "url(#dropShadow)"); - coastline.select("#lake_island").attr("opacity", 1).attr("stroke", "#7c8eaf").attr("stroke-width", 0.35).attr("filter", null); - } - - // v 1.1 features stores more data - defs.select("#land").selectAll("path").remove(); - defs.select("#water").selectAll("path").remove(); - coastline.selectAll("path").remove(); - lakes.selectAll("path").remove(); - drawCoastline(); - } - - if (version < 1.11) { - // v 1.11 added new attributes - terrs.attr("scheme", "bright").attr("terracing", 0).attr("skip", 5).attr("relax", 0).attr("curve", 0); - svg.select("#oceanic > *").attr("id", "oceanicPattern"); - oceanLayers.attr("layers", "-6,-3,-1"); - gridOverlay.attr("type", "pointyHex").attr("size", 10); - - // v 1.11 added cultures heirarchy tree - if (pack.cultures[1] && !pack.cultures[1].code) { - pack.cultures - .filter(c => c.i) - .forEach(c => { - c.origin = 0; - c.code = c.name.slice(0, 2); - }); - } - - // v 1.11 had an issue with fogging being displayed on load - unfog(); - - // v 1.2 added new terrain attributes - if (!terrain.attr("set")) terrain.attr("set", "simple"); - if (!terrain.attr("size")) terrain.attr("size", 1); - if (!terrain.attr("density")) terrain.attr("density", 0.4); - } - - if (version < 1.21) { - // v 1.11 replaced "display" attribute by "display" style - viewbox.selectAll("g").each(function () { - if (this.hasAttribute("display")) { - this.removeAttribute("display"); - this.style.display = "none"; - } - }); - - // v 1.21 added rivers data to pack - pack.rivers = []; // rivers data - rivers.selectAll("path").each(function () { - const i = +this.id.slice(5); - const length = this.getTotalLength() / 2; - const s = this.getPointAtLength(length), - e = this.getPointAtLength(0); - const source = findCell(s.x, s.y), - mouth = findCell(e.x, e.y); - const name = Rivers.getName(mouth); - const type = length < 25 ? rw({Creek: 9, River: 3, Brook: 3, Stream: 1}) : "River"; - pack.rivers.push({i, parent: 0, length, source, mouth, basin: i, name, type}); - }); - } - - if (version < 1.22) { - // v 1.22 changed state neighbors from Set object to array - BurgsAndStates.collectStatistics(); - } - - if (version < 1.3) { - // v 1.3 added global options object - const winds = options.slice(); // previostly wind was saved in settings[19] - const year = rand(100, 2000); - const era = Names.getBaseShort(P(0.7) ? 1 : rand(nameBases.length)) + " Era"; - const eraShort = era[0] + "E"; - const military = Military.getDefaultOptions(); - options = {winds, year, era, eraShort, military}; - - // v 1.3 added campaings data for all states - BurgsAndStates.generateCampaigns(); - - // v 1.3 added militry layer - armies = viewbox.insert("g", "#icons").attr("id", "armies"); - armies.attr("opacity", 1).attr("fill-opacity", 1).attr("font-size", 6).attr("box-size", 3).attr("stroke", "#000").attr("stroke-width", 0.3); - turnButtonOn("toggleMilitary"); - Military.generate(); - } - - if (version < 1.4) { - // v 1.35 added dry lakes - if (!lakes.select("#dry").size()) { - lakes.append("g").attr("id", "dry"); - lakes.select("#dry").attr("opacity", 1).attr("fill", "#c9bfa7").attr("stroke", "#8e816f").attr("stroke-width", 0.7).attr("filter", null); - } - - // v 1.4 added ice layer - ice = viewbox.insert("g", "#coastline").attr("id", "ice").style("display", "none"); - ice.attr("opacity", null).attr("fill", "#e8f0f6").attr("stroke", "#e8f0f6").attr("stroke-width", 1).attr("filter", "url(#dropShadow05)"); - drawIce(); - - // v 1.4 added icon and power attributes for units - for (const unit of options.military) { - if (!unit.icon) unit.icon = getUnitIcon(unit.type); - if (!unit.power) unit.power = unit.crew; - } - - function getUnitIcon(type) { - if (type === "naval") return "🌊"; - if (type === "ranged") return "🏹"; - if (type === "mounted") return "🐴"; - if (type === "machinery") return "💣"; - if (type === "armored") return "🐢"; - if (type === "aviation") return "🦅"; - if (type === "magical") return "🔮"; - else return "⚔️"; - } - - // 1.4 added state reference for regiments - pack.states.filter(s => s.military).forEach(s => s.military.forEach(r => (r.state = s.i))); - } - - if (version < 1.5) { - // not need to store default styles from v 1.5 - localStorage.removeItem("styleClean"); - localStorage.removeItem("styleGloom"); - localStorage.removeItem("styleAncient"); - localStorage.removeItem("styleMonochrome"); - - // v 1.5 cultures has shield attribute - pack.cultures.forEach(culture => { - if (culture.removed) return; - culture.shield = Cultures.getRandomShield(); - }); - - // v 1.5 added burg type value - pack.burgs.forEach(burg => { - if (!burg.i || burg.removed) return; - burg.type = BurgsAndStates.getType(burg.cell, burg.port); - }); - - // v 1.5 added emblems - defs.append("g").attr("id", "defs-emblems"); - emblems = viewbox.insert("g", "#population").attr("id", "emblems").style("display", "none"); - emblems.append("g").attr("id", "burgEmblems"); - emblems.append("g").attr("id", "provinceEmblems"); - emblems.append("g").attr("id", "stateEmblems"); - regenerateEmblems(); - toggleEmblems(); - - // v 1.5 changed releif icons data - terrain.selectAll("use").each(function () { - const type = this.getAttribute("data-type") || this.getAttribute("xlink:href"); - this.removeAttribute("xlink:href"); - this.removeAttribute("data-type"); - this.removeAttribute("data-size"); - this.setAttribute("href", type); - }); - } - - if (version < 1.6) { - // v 1.6 changed rivers data - for (const river of pack.rivers) { - const el = document.getElementById("river" + river.i); - if (el) { - river.widthFactor = +el.getAttribute("data-width"); - el.removeAttribute("data-width"); - el.removeAttribute("data-increment"); - river.discharge = pack.cells.fl[river.mouth] || 1; - river.width = rn(river.length / 100, 2); - river.sourceWidth = 0.1; - } else { - Rivers.remove(river.i); - } - } - - // v 1.6 changed lakes data - for (const f of pack.features) { - if (f.type !== "lake") continue; - if (f.evaporation) continue; - - f.flux = f.flux || f.cells * 3; - f.temp = grid.cells.temp[pack.cells.g[f.firstCell]]; - f.height = f.height || d3.min(pack.cells.c[f.firstCell].map(c => pack.cells.h[c]).filter(h => h >= 20)); - const height = (f.height - 18) ** heightExponentInput.value; - const evaporation = ((700 * (f.temp + 0.006 * height)) / 50 + 75) / (80 - f.temp); - f.evaporation = rn(evaporation * f.cells); - f.name = f.name || Lakes.getName(f); - delete f.river; - } - } - - if (version < 1.61) { - // v 1.61 changed rulers data - ruler.style("display", null); - rulers = new Rulers(); - - ruler.selectAll(".ruler > .white").each(function () { - const x1 = +this.getAttribute("x1"); - const y1 = +this.getAttribute("y1"); - const x2 = +this.getAttribute("x2"); - const y2 = +this.getAttribute("y2"); - if (isNaN(x1) || isNaN(y1) || isNaN(x2) || isNaN(y2)) return; - const points = [ - [x1, y1], - [x2, y2] - ]; - rulers.create(Ruler, points); - }); - - ruler.selectAll("g.opisometer").each(function () { - const pointsString = this.dataset.points; - if (!pointsString) return; - const points = JSON.parse(pointsString); - rulers.create(Opisometer, points); - }); - - ruler.selectAll("path.planimeter").each(function () { - const length = this.getTotalLength(); - if (length < 30) return; - - const step = length > 1000 ? 40 : length > 400 ? 20 : 10; - const increment = length / Math.ceil(length / step); - const points = []; - for (let i = 0; i <= length; i += increment) { - const point = this.getPointAtLength(i); - points.push([point.x | 0, point.y | 0]); - } - - rulers.create(Planimeter, points); - }); - - ruler.selectAll("*").remove(); - - if (rulers.data.length) { - turnButtonOn("toggleRulers"); - rulers.draw(); - } else turnButtonOff("toggleRulers"); - - // 1.61 changed oceanicPattern from rect to image - const pattern = document.getElementById("oceanic"); - const filter = pattern.firstElementChild.getAttribute("filter"); - const href = filter ? "./images/" + filter.replace("url(#", "").replace(")", "") + ".png" : ""; - pattern.innerHTML = ``; - } - - if (version < 1.62) { - // v 1.62 changed grid data - gridOverlay.attr("size", null); - } - - if (version < 1.63) { - // v.1.63 changed ocean pattern opacity element - const oceanPattern = document.getElementById("oceanPattern"); - if (oceanPattern) oceanPattern.removeAttribute("opacity"); - const oceanicPattern = document.getElementById("oceanicPattern"); - if (!oceanicPattern.getAttribute("opacity")) oceanicPattern.setAttribute("opacity", 0.2); - - // v 1.63 moved label text-shadow from css to editable inline style - burgLabels.select("#cities").style("text-shadow", "white 0 0 4px"); - burgLabels.select("#towns").style("text-shadow", "white 0 0 4px"); - labels.select("#states").style("text-shadow", "white 0 0 4px"); - labels.select("#addedLabels").style("text-shadow", "white 0 0 4px"); - } - - if (version < 1.64) { - // v.1.64 change states style - const opacity = regions.attr("opacity"); - const filter = regions.attr("filter"); - statesBody.attr("opacity", opacity).attr("filter", filter); - statesHalo.attr("opacity", opacity).attr("filter", "blur(5px)"); - regions.attr("opacity", null).attr("filter", null); - } - - if (version < 1.65) { - // v 1.65 changed rivers data - d3.select("#rivers").attr("style", null); // remove style to unhide layer - const {cells, rivers} = pack; - const defaultWidthFactor = rn(1 / (pointsInput.dataset.cells / 10000) ** 0.25, 2); - - for (const river of rivers) { - const node = document.getElementById("river" + river.i); - if (node && !river.cells) { - const riverCells = []; - const riverPoints = []; - - const length = node.getTotalLength() / 2; - if (!length) continue; - const segments = Math.ceil(length / 6); - const increment = length / segments; - - for (let i = 0; i <= segments; i++) { - const shift = increment * i; - const {x: x1, y: y1} = node.getPointAtLength(length + shift); - const {x: x2, y: y2} = node.getPointAtLength(length - shift); - const x = rn((x1 + x2) / 2, 1); - const y = rn((y1 + y2) / 2, 1); - - const cell = findCell(x, y); - riverPoints.push([x, y]); - riverCells.push(cell); - } - - river.cells = riverCells; - river.points = riverPoints; - } - - river.widthFactor = defaultWidthFactor; - - cells.i.forEach(i => { - const riverInWater = cells.r[i] && cells.h[i] < 20; - if (riverInWater) cells.r[i] = 0; - }); - } - } - - if (version < 1.652) { - // remove style to unhide layers - rivers.attr("style", null); - borders.attr("style", null); - } - - if (version < 1.7) { - // v 1.7 changed markers data - const defs = document.getElementById("defs-markers"); - const markersGroup = document.getElementById("markers"); - - if (defs && markersGroup) { - const markerElements = markersGroup.querySelectorAll("use"); - const rescale = +markersGroup.getAttribute("rescale"); - - pack.markers = Array.from(markerElements).map((el, i) => { - const id = el.getAttribute("id"); - const note = notes.find(note => note.id === id); - if (note) note.id = `marker${i}`; - - let x = +el.dataset.x; - let y = +el.dataset.y; - - const transform = el.getAttribute("transform"); - if (transform) { - const [dx, dy] = parseTransform(transform); - if (dx) x += +dx; - if (dy) y += +dy; - } - const cell = findCell(x, y); - const size = rn(rescale ? el.dataset.size * 30 : el.getAttribute("width"), 1); - - const href = el.href.baseVal; - const type = href.replace("#marker_", ""); - const symbol = defs?.querySelector(`symbol${href}`); - const text = symbol?.querySelector("text"); - const circle = symbol?.querySelector("circle"); - - const icon = text?.innerHTML; - const px = text && Number(text.getAttribute("font-size")?.replace("px", "")); - const dx = text && Number(text.getAttribute("x")?.replace("%", "")); - const dy = text && Number(text.getAttribute("y")?.replace("%", "")); - const fill = circle && circle.getAttribute("fill"); - const stroke = circle && circle.getAttribute("stroke"); - - const marker = {i, icon, type, x, y, size, cell}; - if (size && size !== 30) marker.size = size; - if (!isNaN(px) && px !== 12) marker.px = px; - if (!isNaN(dx) && dx !== 50) marker.dx = dx; - if (!isNaN(dy) && dy !== 50) marker.dy = dy; - if (fill && fill !== "#ffffff") marker.fill = fill; - if (stroke && stroke !== "#000000") marker.stroke = stroke; - if (circle?.getAttribute("opacity") === "0") marker.pin = "no"; - - return marker; - }); - - markersGroup.style.display = null; - defs?.remove(); - markerElements.forEach(el => el.remove()); - if (layerIsOn("markers")) drawMarkers(); - } - } - })(); + { + // dynamically import and run auto-udpdate script + const version = parseFloat(params[0]); + const {resolveVersionConflicts} = await import("./auto-update.js"); + resolveVersionConflicts(version); + } void (function checkDataIntegrity() { const cells = pack.cells; @@ -1070,6 +566,7 @@ function parseLoadedData(data) { alertMessage.innerHTML = `An error is occured on map loading. Select a different file to load,
    generate a new random map or cancel the loading

    ${parseError(error)}

    `; + $("#alert").dialog({ resizable: false, title: "Loading error", diff --git a/modules/save.js b/modules/io/save.js similarity index 99% rename from modules/save.js rename to modules/io/save.js index 04f3e665..8e0a74e8 100644 --- a/modules/save.js +++ b/modules/io/save.js @@ -145,7 +145,7 @@ async function saveToDropbox() { await Cloud.providers.dropbox.save(filename, mapData); tip("Map is saved to your Dropbox", true, "success", 8000); } catch (msg) { - console.error(msg); + ERROR && console.error(msg); tip("Cannot save .map to your Dropbox", true, "error", 8000); } } diff --git a/modules/markers-generator.js b/modules/markers-generator.js index 1aefca5e..50acf34d 100644 --- a/modules/markers-generator.js +++ b/modules/markers-generator.js @@ -519,7 +519,7 @@ window.Markers = (function () { const dungeonSeed = `${seed}${cell}`; const name = "Dungeon"; - const legend = `
    Undiscovered dungeon. See One page dungeon
    `; + const legend = `
    Undiscovered dungeon. See One page dungeon
    `; notes.push({id, name, legend}); quantity--; } diff --git a/modules/ui/battle-screen.js b/modules/ui/battle-screen.js index 37a1bd51..2936549c 100644 --- a/modules/ui/battle-screen.js +++ b/modules/ui/battle-screen.js @@ -141,8 +141,8 @@ class Battle { const state = pack.states[regiment.state]; const distance = (Math.hypot(this.y - regiment.by, this.x - regiment.bx) * distanceScaleInput.value) | 0; // distance between regiment and its base const color = state.color[0] === "#" ? state.color : "#999"; - const icon = ` - + const icon = ` + ${regiment.icon}`; const body = ``; @@ -183,7 +183,7 @@ class Battle { dist = added ? "0 " + distanceUnitInput.value : distance(r); return `
    - +
    ${s.name.slice(0, 11)}
    ${r.icon}
    ${r.name.slice(0, 24)}
    diff --git a/modules/ui/biomes-editor.js b/modules/ui/biomes-editor.js index ca5bb41d..527e0b08 100644 --- a/modules/ui/biomes-editor.js +++ b/modules/ui/biomes-editor.js @@ -37,9 +37,9 @@ function editBiomes() { document.getElementById("biomesExport").addEventListener("click", downloadBiomesData); body.addEventListener("click", function (ev) { - const el = ev.target, - cl = el.classList; - if (cl.contains("fillRect")) biomeChangeColor(el); + const el = ev.target; + const cl = el.classList; + if (el.tagName === "FILL-BOX") biomeChangeColor(el); else if (cl.contains("icon-info-circled")) openWiki(el); else if (cl.contains("icon-trash-empty")) removeCustomBiome(el); if (customization === 6) selectBiomeOnLineClick(el); @@ -94,9 +94,7 @@ function editBiomes() { lines += `
    - + % { + el.fill = newFill; + biomesData.color[biome] = newFill; biomes .select("#biome" + biome) - .attr("fill", fill) - .attr("stroke", fill); + .attr("fill", newFill) + .attr("stroke", newFill); }; openPicker(currentFill, callback); @@ -270,7 +268,7 @@ function editBiomes() { const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value; const line = `
    - + % diff --git a/modules/ui/burg-editor.js b/modules/ui/burg-editor.js index 1a2bef17..8ec8b61a 100644 --- a/modules/ui/burg-editor.js +++ b/modules/ui/burg-editor.js @@ -52,6 +52,7 @@ function editBurg(id) { document.getElementById("burglLegend").addEventListener("click", editBurgLegend); document.getElementById("burgLock").addEventListener("click", toggleBurgLockButton); document.getElementById("burgRemove").addEventListener("click", removeSelectedBurg); + document.getElementById("burgTemperatureGraph").addEventListener("click", showTemperatureGraph); function updateBurgValues() { const id = +elSelected.attr("data-id"); @@ -543,6 +544,11 @@ function editBurg(id) { editNotes("burg" + id, name); } + function showTemperatureGraph() { + const id = elSelected.attr("data-id"); + showBurgTemperatureGraph(id); + } + function removeSelectedBurg() { const id = +elSelected.attr("data-id"); if (pack.burgs[id].capital) { diff --git a/modules/ui/cultures-editor.js b/modules/ui/cultures-editor.js index 74c73535..50b5bc63 100644 --- a/modules/ui/cultures-editor.js +++ b/modules/ui/cultures-editor.js @@ -108,9 +108,7 @@ function editCultures() { lines += `
    - - - + @@ -148,7 +146,7 @@ function editCultures() { body.querySelectorAll("div.cultures").forEach(el => el.addEventListener("mouseenter", ev => cultureHighlightOn(ev))); body.querySelectorAll("div.cultures").forEach(el => el.addEventListener("mouseleave", ev => cultureHighlightOff(ev))); body.querySelectorAll("div.states").forEach(el => el.addEventListener("click", selectCultureOnLineClick)); - body.querySelectorAll("rect.fillRect").forEach(el => el.addEventListener("click", cultureChangeColor)); + body.querySelectorAll("fill-box").forEach(el => el.addEventListener("click", cultureChangeColor)); body.querySelectorAll("div > input.cultureName").forEach(el => el.addEventListener("input", cultureChangeName)); body.querySelectorAll("div > span.icon-cw").forEach(el => el.addEventListener("click", cultureRegenerateName)); body.querySelectorAll("div > input.statePower").forEach(el => el.addEventListener("input", cultureChangeExpansionism)); @@ -248,16 +246,16 @@ function editCultures() { function cultureChangeColor() { const el = this; const currentFill = el.getAttribute("fill"); - const culture = +el.parentNode.parentNode.dataset.id; + const culture = +el.parentNode.dataset.id; - const callback = function (fill) { - el.setAttribute("fill", fill); - pack.cultures[culture].color = fill; + const callback = newFill => { + el.fill = newFill; + pack.cultures[culture].color = newFill; cults .select("#culture" + culture) - .attr("fill", fill) - .attr("stroke", fill); - debug.select("#cultureCenter" + culture).attr("fill", fill); + .attr("fill", newFill) + .attr("stroke", newFill); + debug.select("#cultureCenter" + culture).attr("fill", newFill); }; openPicker(currentFill, callback); diff --git a/modules/ui/diplomacy-editor.js b/modules/ui/diplomacy-editor.js index 657f6b73..bed60a3b 100644 --- a/modules/ui/diplomacy-editor.js +++ b/modules/ui/diplomacy-editor.js @@ -101,10 +101,8 @@ function editDiplomacy() { lines += `
    ${name}
    -
    - - - +
    + ${relation}
    `; @@ -195,9 +193,7 @@ function editDiplomacy() { ([relation, {color, inText, tip}]) => `
    ` ) diff --git a/modules/ui/editors.js b/modules/ui/editors.js index 3c14c149..be97102c 100644 --- a/modules/ui/editors.js +++ b/modules/ui/editors.js @@ -425,10 +425,10 @@ function clearLegend() { function createPicker() { const pos = () => tip("Drag to change the picker position"); const cl = () => tip("Click to close the picker"); - const closePicker = () => contaiter.style("display", "none"); + const closePicker = () => container.style("display", "none"); - const contaiter = d3.select("body").append("svg").attr("id", "pickerContainer").attr("width", "100%").attr("height", "100%"); - contaiter + const container = d3.select("body").append("svg").attr("id", "pickerContainer").attr("width", "100%").attr("height", "100%"); + container .append("rect") .attr("x", 0) .attr("y", 0) @@ -437,7 +437,7 @@ function createPicker() { .attr("opacity", 0.2) .on("mousemove", cl) .on("click", closePicker); - const picker = contaiter + const picker = container .append("g") .attr("id", "picker") .call( @@ -494,7 +494,7 @@ function createPicker() { const colors = picker.append("g").attr("id", "pickerColors").attr("stroke", "#333333"); const hatches = picker.append("g").attr("id", "pickerHatches").attr("stroke", "#333333"); - const hatching = d3.selectAll("g#hatching > pattern"); + const hatching = d3.selectAll("g#defs-hatching > pattern"); const number = hatching.size(); const clr = d3.range(number).map(i => d3.hsl((i / number) * 360, 0.7, 0.7).hex()); @@ -504,8 +504,8 @@ function createPicker() { .attr("id", "picker_" + d) .attr("fill", d) .attr("class", i ? "" : "selected") - .attr("x", i * 22 + 4) - .attr("y", 40) + .attr("x", (i % 14) * 22 + 4) + .attr("y", 40 + Math.floor(i / 14)*20) .attr("width", 16) .attr("height", 16); }); @@ -515,20 +515,20 @@ function createPicker() { .append("rect") .attr("id", "picker_" + this.id) .attr("fill", "url(#" + this.id + ")") - .attr("x", i * 22 + 4) - .attr("y", 61) + .attr("x", (i % 14) * 22 + 4) + .attr("y", Math.floor(i / 14)*20 + 20 + (number * 2)) .attr("width", 16) - .attr("height", 16); + .attr("height", 16) }); colors .selectAll("rect") .on("click", pickerFillClicked) - .on("mousemove", () => tip("Click to fill with the color")); + .on("mouseover", () => tip("Click to fill with the color")); hatches .selectAll("rect") .on("click", pickerFillClicked) - .on("mousemove", () => tip("Click to fill with the hatching")); + .on("mouseover", function() { tip("Click to fill with the hatching " + this.id) }); // append box const bbox = picker.node().getBBox(); @@ -544,10 +544,10 @@ function createPicker() { .attr("fill", "#ffffff") .attr("stroke", "#5d4651") .on("mousemove", pos); - picker.insert("text", ":first-child").attr("x", 291).attr("y", -10).attr("id", "pickerCloseText").text("✕"); + picker.insert("text", ":first-child").attr("x", width-20).attr("y", -10).attr("id", "pickerCloseText").text("✕"); picker .insert("rect", ":first-child") - .attr("x", 288) + .attr("x", width-23) .attr("y", -21) .attr("id", "pickerCloseRect") .attr("width", 14) diff --git a/modules/ui/general.js b/modules/ui/general.js index 5823afec..b7a6255d 100644 --- a/modules/ui/general.js +++ b/modules/ui/general.js @@ -70,7 +70,8 @@ function mouseMove() { const point = d3.mouse(this); const i = findCell(point[0], point[1]); // pack cell id if (i === undefined) return; - showNotes(d3.event, i); + + showNotes(d3.event); const g = findGridCell(point[0], point[1]); // grid cell id if (tooltip.dataset.main) showMainTip(); else showMapTooltip(point, d3.event, i, g); @@ -78,7 +79,7 @@ function mouseMove() { } // show note box on hover (if any) -function showNotes(e, i) { +function showNotes(e) { if (notesEditor.offsetParent) return; let id = e.target.id || e.target.parentNode.id || e.target.parentNode.parentNode.id; if (e.target.parentNode.parentNode.id === "burgLabels") id = "burg" + e.target.dataset.id; diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js index b4ebde9f..effb81c7 100644 --- a/modules/ui/heightmap-editor.js +++ b/modules/ui/heightmap-editor.js @@ -913,11 +913,9 @@ function editHeightmap() { function uploadTemplate(dataLoaded) { const steps = dataLoaded.split("\r\n"); - if (!steps.length) { - tip("Cannot parse the template, please check the file", false, "error"); - return; - } + if (!steps.length) return tip("Cannot parse the template, please check the file", false, "error"); templateBody.innerHTML = ""; + for (const s of steps) { const step = s.split(" "); if (step.length !== 5) { @@ -1318,10 +1316,10 @@ function editHeightmap() { img.onload = function () { const canvas = document.createElement("canvas"); const ctx = canvas.getContext("2d"); - canvas.width = svgWidth; - canvas.height = svgHeight; + canvas.width = graphWidth; + canvas.height = graphHeight; document.body.insertBefore(canvas, optionsContainer); - ctx.drawImage(img, 0, 0, svgWidth, svgHeight); + ctx.drawImage(img, 0, 0, graphWidth, graphHeight); const imgBig = canvas.toDataURL("image/png"); const link = document.createElement("a"); link.download = getFileName("Heightmap") + ".png"; diff --git a/modules/ui/measurers.js b/modules/ui/measurers.js index 3fe8fe5b..488aafe4 100644 --- a/modules/ui/measurers.js +++ b/modules/ui/measurers.js @@ -536,12 +536,11 @@ class Planimeter extends Measurer { } // Scale bar -function drawScaleBar(requestedScale) { +function drawScaleBar(scaleLevel) { if (scaleBar.style("display") === "none") return; // no need to re-draw hidden element scaleBar.selectAll("*").remove(); // fully redraw every time - const scaleLevel = requestedScale || scale; - const distanceScale = distanceScaleInput.value; + const distanceScale = +distanceScaleInput.value; const unit = distanceUnitInput.value; const size = +barSizeInput.value; diff --git a/modules/ui/military-overview.js b/modules/ui/military-overview.js index 38b25a41..0d244314 100644 --- a/modules/ui/military-overview.js +++ b/modules/ui/military-overview.js @@ -75,12 +75,9 @@ function overviewMilitary() { const sortData = options.military.map(u => `data-${u.name}="${getForces(u)}"`).join(" "); const lineData = options.military.map(u => `
    ${getForces(u)}
    `).join(" "); - lines += `
    - + lines += `
    + ${lineData}
    ${si(total)}
    diff --git a/modules/ui/notes-editor.js b/modules/ui/notes-editor.js index 3ad4b979..872437fa 100644 --- a/modules/ui/notes-editor.js +++ b/modules/ui/notes-editor.js @@ -1,25 +1,22 @@ "use strict"; function editNotes(id, name) { + // elements + const notesLegend = document.getElementById("notesLegend"); + const notesName = document.getElementById("notesName"); + const notesSelect = document.getElementById("notesSelect"); + const notesPin = document.getElementById("notesPin"); + // update list of objects - const select = document.getElementById("notesSelect"); - select.options.length = 0; + notesSelect.options.length = 0; for (const note of notes) { - select.options.add(new Option(note.id, note.id)); + notesSelect.options.add(new Option(note.id, note.id)); } - // initiate pell (html editor) - const notesText = document.getElementById("notesText"); - notesText.innerHTML = ""; - const editor = Pell.init({ - element: notesText, - onChange: html => { - const note = notes.find(note => note.id === select.value); - if (!note) return; - note.legend = html; - showNote(note); - } - }); + // update pin notes icon + const notesArePinned = options.pinNotes; + if (notesArePinned) notesPin.classList.add("pressed"); + else notesPin.classList.remove("pressed"); // select an object if (notes.length || id) { @@ -29,136 +26,161 @@ function editNotes(id, name) { if (!name) name = id; note = {id, name, legend: ""}; notes.push(note); - select.options.add(new Option(id, id)); + notesSelect.options.add(new Option(id, id)); } - select.value = id; + + notesSelect.value = id; notesName.value = note.name; - editor.content.innerHTML = note.legend; - showNote(note); + notesLegend.innerHTML = note.legend; + initEditor(); + updateNotesBox(note); } else { - editor.content.innerHTML = "There are no added notes. Click on element (e.g. label) and add a free text note"; - document.getElementById("notesName").value = ""; + // if notes array is empty + notesName.value = ""; + notesLegend.innerHTML = "No notes added. Click on an element (e.g. label or marker) and add a free text note"; } - // open a dialog $("#notesEditor").dialog({ title: "Notes Editor", - minWidth: "40em", - width: "50vw", - position: {my: "center", at: "center", of: "svg"} + width: "70vw", + height: window.innerHeight * 0.75, + position: {my: "center", at: "center", of: "svg"}, + close: removeEditor }); + $("[aria-describedby='notesEditor']").css("top", "10vh"); if (modules.editNotes) return; modules.editNotes = true; // add listeners - document.getElementById("notesSelect").addEventListener("change", changeObject); + document.getElementById("notesSelect").addEventListener("change", changeElement); document.getElementById("notesName").addEventListener("input", changeName); - document.getElementById("notesPin").addEventListener("click", () => (options.pinNotes = !options.pinNotes)); - document.getElementById("notesSpeak").addEventListener("click", () => speak(editor.content.innerHTML)); + document.getElementById("notesLegend").addEventListener("blur", updateLegend); + document.getElementById("notesPin").addEventListener("click", toggleNotesPin); document.getElementById("notesFocus").addEventListener("click", validateHighlightElement); document.getElementById("notesDownload").addEventListener("click", downloadLegends); document.getElementById("notesUpload").addEventListener("click", () => legendsToLoad.click()); document.getElementById("legendsToLoad").addEventListener("change", function () { uploadFile(this, uploadLegends); }); - document.getElementById("notesClearStyle").addEventListener("click", clearStyle); document.getElementById("notesRemove").addEventListener("click", triggerNotesRemove); - function showNote(note) { - document.getElementById("notes").style.display = "block"; + async function initEditor() { + if (!window.tinymce) { + const url = "https://cdn.tiny.cloud/1/4i6a79ymt2y0cagke174jp3meoi28vyecrch12e5puyw3p9a/tinymce/5/tinymce.min.js"; + try { + await import(url); + } catch (error) { + // error may be caused by failed request being cached, try again with random hash + try { + const hash = Math.random().toString(36).substring(2, 15); + await import(`${url}#${hash}`); + } catch (error) { + console.error(error); + } + } + } + + if (window.tinymce) { + tinymce.init({ + selector: "#notesLegend", + height: "90%", + menubar: false, + plugins: `autolink lists link charmap print formatpainter casechange code fullscreen image link media table paste hr checklist wordcount`, + toolbar: `code | undo redo | bold italic strikethrough | forecolor backcolor | formatpainter removeformat | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image media table | fontselect fontsizeselect | blockquote hr casechange checklist charmap | print fullscreen`, + media_alt_source: false, + media_poster: false, + setup: editor => { + editor.on("Change", updateLegend); + } + }); + } + } + + function updateLegend() { + const note = notes.find(note => note.id === notesSelect.value); + if (!note) return tip("Note element is not found", true, "error", 4000); + + const isTinyEditorActive = window.tinymce?.activeEditor; + note.legend = isTinyEditorActive ? tinymce.activeEditor.getContent() : notesLegend.innerHTML; + updateNotesBox(note); + } + + function updateNotesBox(note) { document.getElementById("notesHeader").innerHTML = note.name; document.getElementById("notesBody").innerHTML = note.legend; } - function changeObject() { + function changeElement() { const note = notes.find(note => note.id === this.value); - if (!note) return; + if (!note) return tip("Note element is not found", true, "error", 4000); + notesName.value = note.name; - editor.content.innerHTML = note.legend; + notesLegend.innerHTML = note.legend; + updateNotesBox(note); + + if (window.tinymce) tinymce.activeEditor.setContent(note.legend); } function changeName() { - const id = document.getElementById("notesSelect").value; - const note = notes.find(note => note.id === id); - if (!note) return; + const note = notes.find(note => note.id === notesSelect.value); + if (!note) return tip("Note element is not found", true, "error", 4000); + note.name = this.value; - showNote(note); } function validateHighlightElement() { - const select = document.getElementById("notesSelect"); - const element = document.getElementById(select.value); + const element = document.getElementById(notesSelect.value); + if (element) return highlightElement(element, 3); - // if element is not found - if (element === null) { - alertMessage.innerHTML = "Related element is not found. Would you like to remove the note?"; - $("#alert").dialog({ - resizable: false, - title: "Element not found", - buttons: { - Remove: function () { - $(this).dialog("close"); - removeLegend(); - }, - Keep: function () { - $(this).dialog("close"); - } - } - }); - return; - } - - highlightElement(element, 3); // if element is found + confirmationDialog({ + title: "Element not found", + message: "Note element is not found. Would you like to remove the note?", + confirm: "Remove", + cancel: "Keep", + onConfirm: removeLegend + }); } function downloadLegends() { - const data = JSON.stringify(notes); + const notesData = JSON.stringify(notes); const name = getFileName("Notes") + ".txt"; - downloadFile(data, name); + downloadFile(notesData, name); } function uploadLegends(dataLoaded) { - if (!dataLoaded) { - tip("Cannot load the file. Please check the data format", false, "error"); - return; - } + if (!dataLoaded) return tip("Cannot load the file. Please check the data format", false, "error"); notes = JSON.parse(dataLoaded); - document.getElementById("notesSelect").options.length = 0; + notesSelect.options.length = 0; editNotes(notes[0].id, notes[0].name); } - function clearStyle() { - editor.content.innerHTML = editor.content.textContent; - } - function triggerNotesRemove() { - alertMessage.innerHTML = "Are you sure you want to remove the selected note?"; - $("#alert").dialog({ - resizable: false, + confirmationDialog({ title: "Remove note", - buttons: { - Remove: function () { - $(this).dialog("close"); - removeLegend(); - }, - Keep: function () { - $(this).dialog("close"); - } - } + message: "Are you sure you want to remove the selected note? There is no way to undo this action", + confirm: "Remove", + onConfirm: removeLegend }); } function removeLegend() { - const select = document.getElementById("notesSelect"); - const index = notes.findIndex(n => n.id === select.value); + const index = notes.findIndex(n => n.id === notesSelect.value); notes.splice(index, 1); - select.options.length = 0; + notesSelect.options.length = 0; if (!notes.length) { $("#notesEditor").dialog("close"); return; } - notesText.innerHTML = ""; editNotes(notes[0].id, notes[0].name); } + + function toggleNotesPin() { + options.pinNotes = !options.pinNotes; + this.classList.toggle("pressed"); + } + + function removeEditor() { + if (window.tinymce) tinymce.remove(); + } } diff --git a/modules/ui/options.js b/modules/ui/options.js index 35645d14..b6658490 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -103,7 +103,9 @@ function showSupporters() { Mike Conley,Xavier privé,Hope You're Well,Mark Sprietsma,Robert Landry,Nick Mowry,steve hall,Markell,Josh Wren,Neutrix,BLRageQuit,Rocky, Dario Spadavecchia,Bas Kroot,John Patrick Callahan Jr,Alexandra Vesey,D,Exp1nt,james,Braxton Istace,w,Rurikid,AntiBlock,Redsauz,BigE0021, Jonathan Williams,ojacid .,Brian Wilson,A Patreon of the Ahts,Shubham Jakhotiya,www15o,Jan Bundesmann,Angelique Badger,Joshua Xiong,Moist mongol, - Frank Fewkes,jason baldrick,Game Master Pro,Andrew Kircher,Preston Mitchell,Chris Kohut`; + Frank Fewkes,jason baldrick,Game Master Pro,Andrew Kircher,Preston Mitchell,Chris Kohut,Emarandzeb,Trentin Bergeron,Damon Gallaty,Pleaseworkforonce, + Jordan,William Markus,Sidr Dim,Alexander Whittaker,The Next Level,Patrick Valverde,Markus Peham,Daniel Cooper,the Beagles of Neorbus,Marley Moule, + Maximilian Schielke,Johnathan Xavier Hutchinson,Ele,Rita`; const array = supporters .replace(/(?:\r\n|\r|\n)/g, "") @@ -304,10 +306,8 @@ function showSeedHistoryDialog() { // generate map with historical seed function restoreSeed(id) { - if (mapHistory[id].seed == seed) { - tip("The current map is already generated with this seed", null, "error"); - return; - } + if (mapHistory[id].seed == seed) return tip("The current map is already generated with this seed", null, "error"); + optionsSeed.value = mapHistory[id].seed; mapWidthInput.value = mapHistory[id].width; mapHeightInput.value = mapHistory[id].height; @@ -545,7 +545,7 @@ function randomizeOptions() { // 'Options' settings if (randomize || !locked("template")) randomizeHeightmapTemplate(); - if (randomize || !locked("regions")) regionsInput.value = regionsOutput.value = gauss(15, 3, 2, 30); + 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); if (randomize || !locked("manors")) { manorsInput.value = 1000; @@ -736,24 +736,43 @@ async function showLoadPane() { } }); - const loadFromDropboxButtons = document.getElementById("loadFromDropboxButtons"); - const fileSelect = document.getElementById("loadFromDropboxSelect"); - const files = await Cloud.providers.dropbox.list(); + // already connected to Dropbox: list saved maps + if (Cloud.providers.dropbox.api) { + document.getElementById("dropboxConnectButton").style.display = "none"; + document.getElementById("loadFromDropboxSelect").style.display = "block"; + const loadFromDropboxButtons = document.getElementById("loadFromDropboxButtons"); + const fileSelect = document.getElementById("loadFromDropboxSelect"); + fileSelect.innerHTML = ``; + + const files = await Cloud.providers.dropbox.list(); + + if (!files) { + loadFromDropboxButtons.style.display = "none"; + fileSelect.innerHTML = ``; + return; + } + + loadFromDropboxButtons.style.display = "block"; + fileSelect.innerHTML = ""; + files.forEach(file => { + const opt = document.createElement("option"); + opt.innerText = file.name; + opt.value = file.path; + fileSelect.appendChild(opt); + }); - if (!files) { - loadFromDropboxButtons.style.display = "none"; - fileSelect.innerHTML = ``; return; } - loadFromDropboxButtons.style.display = "block"; - fileSelect.innerHTML = ""; - files.forEach(file => { - const opt = document.createElement("option"); - opt.innerText = file.name; - opt.value = file.path; - fileSelect.appendChild(opt); - }); + // not connected to Dropbox: show connect button + document.getElementById("dropboxConnectButton").style.display = "inline-block"; + document.getElementById("loadFromDropboxButtons").style.display = "none"; + document.getElementById("loadFromDropboxSelect").style.display = "none"; +} + +async function connectToDropbox() { + await Cloud.providers.dropbox.initialize(); + if (Cloud.providers.dropbox.api) showLoadPane(); } function loadURL() { diff --git a/modules/ui/provinces-editor.js b/modules/ui/provinces-editor.js index 7983d430..045505ee 100644 --- a/modules/ui/provinces-editor.js +++ b/modules/ui/provinces-editor.js @@ -44,7 +44,8 @@ function editProvinces() { cl = el.classList, line = el.parentNode, p = +line.dataset.id; - if (cl.contains("fillRect")) changeFill(el); + + if (el.tagName === "FILL-BOX") changeFill(el); else if (cl.contains("name")) editProvinceName(p); else if (cl.contains("coaIcon")) editEmblem("province", "provinceCOA" + p, pack.provinces[p]); else if (cl.contains("icon-star-empty")) capitalZoomIn(p); @@ -133,9 +134,7 @@ function editProvinces() { lines += `
    - + @@ -215,14 +214,14 @@ function editProvinces() { function changeFill(el) { const currentFill = el.getAttribute("fill"); - const p = +el.parentNode.parentNode.dataset.id; + const p = +el.parentNode.dataset.id; - const callback = function (fill) { - el.setAttribute("fill", fill); - pack.provinces[p].color = fill; + const callback = newFill => { + el.fill = newFill; + pack.provinces[p].color = newFill; const g = provs.select("#provincesBody"); - g.select("#province" + p).attr("fill", fill); - g.select("#province-gap" + p).attr("stroke", fill); + g.select("#province" + p).attr("fill", newFill); + g.select("#province-gap" + p).attr("stroke", newFill); }; openPicker(currentFill, callback); diff --git a/modules/ui/regiments-overview.js b/modules/ui/regiments-overview.js index 67099d35..42a9f4e0 100644 --- a/modules/ui/regiments-overview.js +++ b/modules/ui/regiments-overview.js @@ -14,7 +14,9 @@ function overviewRegiments(state) { updateHeaders(); $("#regimentsOverview").dialog({ - title: "Regiments Overview", resizable: false, width: fitContent(), + title: "Regiments Overview", + resizable: false, + width: fitContent(), position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"} }); @@ -31,11 +33,13 @@ function overviewRegiments(state) { header.querySelectorAll(".removable").forEach(el => el.remove()); const insert = html => document.getElementById("regimentsTotal").insertAdjacentHTML("beforebegin", html); for (const u of options.military) { - const label = capitalize(u.name.replace(/_/g, ' ')); + const label = capitalize(u.name.replace(/_/g, " ")); insert(`
    ${label} 
    `); } - header.querySelectorAll(".removable").forEach(function(e) { - e.addEventListener("click", function() {sortLines(this);}); + header.querySelectorAll(".removable").forEach(function (e) { + e.addEventListener("click", function () { + sortLines(this); + }); }); } @@ -51,11 +55,13 @@ function overviewRegiments(state) { if (state !== -1 && s.i !== state) continue; // specific state is selected for (const r of s.military) { - const sortData = options.military.map(u => `data-${u.name}=${r.u[u.name]||0}`).join(" "); - const lineData = options.military.map(u => `
    ${r.u[u.name]||0}
    `).join(" "); + const sortData = options.military.map(u => `data-${u.name}=${r.u[u.name] || 0}`).join(" "); + const lineData = options.military + .map(u => `
    ${r.u[u.name] || 0}
    `) + .join(" "); lines += `
    - + ${r.icon} @@ -70,12 +76,15 @@ function overviewRegiments(state) { lines += `
    Regiments: ${regiments.length}
    - ${options.military.map(u => `
    ${si(d3.sum(regiments.map(r => r.u[u.name]||0)))}
    `).join(" ")} + ${options.military.map(u => `
    ${si(d3.sum(regiments.map(r => r.u[u.name] || 0)))}
    `).join(" ")}
    ${si(d3.sum(regiments.map(r => r.a)))}
    `; body.insertAdjacentHTML("beforeend", lines); - if (body.dataset.type === "percentage") {body.dataset.type = "absolute"; togglePercentageMode();} + if (body.dataset.type === "percentage") { + body.dataset.type = "absolute"; + togglePercentageMode(); + } applySorting(regimentsHeader); // add listeners @@ -87,7 +96,7 @@ function overviewRegiments(state) { const filter = document.getElementById("regimentsFilter"); filter.options.length = 0; // remove all options filter.options.add(new Option(`all`, -1, false, state === -1)); - const statesSorted = pack.states.filter(s => s.i && !s.removed).sort((a, b) => (a.name > b.name) ? 1 : -1); + const statesSorted = pack.states.filter(s => s.i && !s.removed).sort((a, b) => (a.name > b.name ? 1 : -1)); statesSorted.forEach(s => filter.options.add(new Option(s.name, s.i, false, s.i == state))); } @@ -108,19 +117,20 @@ function overviewRegiments(state) { if (body.dataset.type === "absolute") { body.dataset.type = "percentage"; const lines = body.querySelectorAll(":scope > div:not(.totalLine)"); - const array = Array.from(lines), cache = []; + const array = Array.from(lines), + cache = []; - const total = function(type) { + const total = function (type) { if (cache[type]) cache[type]; cache[type] = d3.sum(array.map(el => +el.dataset[type])); return cache[type]; - } + }; - lines.forEach(function(el) { - el.querySelectorAll("div").forEach(function(div) { + lines.forEach(function (el) { + el.querySelectorAll("div").forEach(function (div) { const type = div.dataset.type; if (type === "rate") return; - div.textContent = total(type) ? rn(+el.dataset[type] / total(type) * 100) + "%" : "0%"; + div.textContent = total(type) ? rn((+el.dataset[type] / total(type)) * 100) + "%" : "0%"; }); }); } else { @@ -145,15 +155,19 @@ function overviewRegiments(state) { function addRegimentOnClick() { const state = +regimentsFilter.value; - if (state === -1) {tip("Please select state from the list", false, "error"); return;} + if (state === -1) { + tip("Please select state from the list", false, "error"); + return; + } 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 = pack.cells.p[cell][0], + y = pack.cells.p[cell][1]; const military = pack.states[state].military; const i = military.length ? last(military).i + 1 : 0; const n = +(pack.cells.h[cell] < 20); // naval or land - const reg = {a:0, cell, i, n, u:{}, x, y, bx:x, by:y, state, icon:"🛡️"}; + const reg = {a: 0, cell, i, n, u: {}, x, y, bx: x, by: y, state, icon: "🛡️"}; reg.name = Military.getName(reg, military); military.push(reg); Military.generateNote(reg, pack.states[state]); // add legend @@ -163,9 +177,9 @@ function overviewRegiments(state) { function downloadRegimentsData() { const units = options.military.map(u => u.name); - let data = "State,Id,Name,"+units.map(u => capitalize(u)).join(",")+",Total\n"; // headers + let data = "State,Id,Name," + units.map(u => capitalize(u)).join(",") + ",Total\n"; // headers - body.querySelectorAll(":scope > div:not(.totalLine)").forEach(function(el) { + body.querySelectorAll(":scope > div:not(.totalLine)").forEach(function (el) { data += el.dataset.state + ","; data += el.dataset.id + ","; data += el.dataset.name + ","; @@ -176,5 +190,4 @@ function overviewRegiments(state) { const name = getFileName("Regiments") + ".csv"; downloadFile(data, name); } - -} \ No newline at end of file +} diff --git a/modules/ui/religions-editor.js b/modules/ui/religions-editor.js index f635dd40..98a4d40d 100644 --- a/modules/ui/religions-editor.js +++ b/modules/ui/religions-editor.js @@ -79,7 +79,7 @@ function editReligions() { if (r.i) { lines += `
    - + @@ -93,7 +93,9 @@ function editReligions() {
    `; } else { // No religion (neutral) line - lines += `
    + lines += `
    @@ -124,7 +126,7 @@ function editReligions() { body.querySelectorAll("div.religions").forEach(el => el.addEventListener("mouseenter", ev => religionHighlightOn(ev))); body.querySelectorAll("div.religions").forEach(el => el.addEventListener("mouseleave", ev => religionHighlightOff(ev))); body.querySelectorAll("div.states").forEach(el => el.addEventListener("click", selectReligionOnLineClick)); - body.querySelectorAll("rect.fillRect").forEach(el => el.addEventListener("click", religionChangeColor)); + body.querySelectorAll("fill-box").forEach(el => el.addEventListener("click", religionChangeColor)); body.querySelectorAll("div > input.religionName").forEach(el => el.addEventListener("input", religionChangeName)); body.querySelectorAll("div > select.religionType").forEach(el => el.addEventListener("change", religionChangeType)); body.querySelectorAll("div > input.religionForm").forEach(el => el.addEventListener("input", religionChangeForm)); @@ -215,13 +217,13 @@ function editReligions() { function religionChangeColor() { const el = this; const currentFill = el.getAttribute("fill"); - const religion = +el.parentNode.parentNode.dataset.id; + const religion = +el.parentNode.dataset.id; - const callback = function (fill) { - el.setAttribute("fill", fill); - pack.religions[religion].color = fill; - relig.select("#religion" + religion).attr("fill", fill); - debug.select("#religionsCenter" + religion).attr("fill", fill); + const callback = newFill => { + el.fill = newFill; + pack.religions[religion].color = newFill; + relig.select("#religion" + religion).attr("fill", newFill); + debug.select("#religionsCenter" + religion).attr("fill", newFill); }; openPicker(currentFill, callback); @@ -459,7 +461,13 @@ function editReligions() { // prepare svg alertMessage.innerHTML = "
    "; - const svg = d3.select("#alertMessage").insert("svg", "#religionInfo").attr("id", "hierarchy").attr("width", width).attr("height", height).style("text-anchor", "middle"); + const svg = d3 + .select("#alertMessage") + .insert("svg", "#religionInfo") + .attr("id", "hierarchy") + .attr("width", width) + .attr("height", height) + .style("text-anchor", "middle"); const graph = svg.append("g").attr("transform", `translate(10, -45)`); const links = graph.append("g").attr("fill", "none").attr("stroke", "#aaaaaa"); const nodes = graph.append("g"); @@ -473,7 +481,24 @@ function editReligions() { .enter() .append("path") .attr("d", d => { - return "M" + d.source.x + "," + d.source.y + "C" + d.source.x + "," + (d.source.y * 3 + d.target.y) / 4 + " " + d.target.x + "," + (d.source.y * 2 + d.target.y) / 3 + " " + d.target.x + "," + d.target.y; + return ( + "M" + + d.source.x + + "," + + d.source.y + + "C" + + d.source.x + + "," + + (d.source.y * 3 + d.target.y) / 4 + + " " + + d.target.x + + "," + + (d.source.y * 2 + d.target.y) / 3 + + " " + + d.target.x + + "," + + d.target.y + ); }); const node = nodes @@ -578,7 +603,11 @@ function editReligions() { $("#religionsEditor").dialog({position: {my: "right top", at: "right-10 top+10", of: "svg"}}); tip("Click on religion to select, drag the circle to change religion", true); - viewbox.style("cursor", "crosshair").on("click", selectReligionOnMapClick).call(d3.drag().on("start", dragReligionBrush)).on("touchmove mousemove", moveReligionBrush); + viewbox + .style("cursor", "crosshair") + .on("click", selectReligionOnMapClick) + .call(d3.drag().on("start", dragReligionBrush)) + .on("touchmove mousemove", moveReligionBrush); body.querySelector("div").classList.add("selected"); } diff --git a/modules/ui/states-editor.js b/modules/ui/states-editor.js index c1d8e978..d7909614 100644 --- a/modules/ui/states-editor.js +++ b/modules/ui/states-editor.js @@ -45,7 +45,7 @@ function editStates() { cl = el.classList, line = el.parentNode, state = +line.dataset.id; - if (cl.contains("fillRect")) stateChangeFill(el); + if (el.tagName === "FILL-BOX") stateChangeFill(el); else if (cl.contains("name")) editStateName(state); else if (cl.contains("coaIcon")) editEmblem("state", "stateCOA" + state, pack.states[state]); else if (cl.contains("icon-star-empty")) stateCapitalZoomIn(state); @@ -102,7 +102,7 @@ function editStates() { // Neutral line lines += `
    - + @@ -126,15 +126,10 @@ function editStates() { const capital = pack.burgs[s.capital].name; COArenderer.trigger("stateCOA" + s.i, s.coa); - lines += `
    - + lines += `
    + @@ -149,9 +144,8 @@ function editStates() {
    ${si(population)}
    - +
    ${s.cells}
    @@ -237,18 +231,18 @@ function editStates() { function stateChangeFill(el) { const currentFill = el.getAttribute("fill"); - const state = +el.parentNode.parentNode.dataset.id; + const state = +el.parentNode.dataset.id; - const callback = function (fill) { - el.setAttribute("fill", fill); - pack.states[state].color = fill; - statesBody.select("#state" + state).attr("fill", fill); - statesBody.select("#state-gap" + state).attr("stroke", fill); - const halo = d3.color(fill) ? d3.color(fill).darker().hex() : "#666666"; + const callback = function (newFill) { + el.fill = newFill; + pack.states[state].color = newFill; + statesBody.select("#state" + state).attr("fill", newFill); + statesBody.select("#state-gap" + state).attr("stroke", newFill); + const halo = d3.color(newFill) ? d3.color(newFill).darker().hex() : "#666666"; statesHalo.select("#state-border" + state).attr("stroke", halo); // recolor regiments - const solidColor = fill[0] === "#" ? fill : "#999"; + const solidColor = newFill[0] === "#" ? newFill : "#999"; const darkerColor = d3.color(solidColor).darker().hex(); armies.select("#army" + state).attr("fill", solidColor); armies diff --git a/modules/ui/style.js b/modules/ui/style.js index 8fc85844..b4179fea 100644 --- a/modules/ui/style.js +++ b/modules/ui/style.js @@ -2,7 +2,7 @@ "use strict"; // add available filters to lists -void (function addFilters() { +{ const filters = Array.from(document.getElementById("filters").querySelectorAll("filter")); const emptyOption = ''; const options = filters.map(filter => { @@ -14,7 +14,7 @@ void (function addFilters() { document.getElementById("styleFilterInput").innerHTML = allOptions; document.getElementById("styleStatesBodyFilter").innerHTML = allOptions; -})(); +} // store some style inputs as options styleElements.addEventListener("change", function (ev) { @@ -754,333 +754,9 @@ function fetchTextureURL(url) { img.src = url; } -const defaultStyles = { - styleAncient: `{"#map":{"background-color":"#000000","filter":null,"data-filter":null},"#armies":{"font-size":8,"box-size":4,"stroke":"#000","stroke-width":0.2,"fill-opacity":1,"filter":null},"#biomes":{"opacity":null,"filter":null,"mask":"url(#land)"},"#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,"scale":1,"dx":0,"dy":0,"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.5,"transform":null,"filter":"url(#filter-sepia)","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":"#e3dfce","filter":null},"#markers":{"opacity":null,"rescale":1,"filter":""},"#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.6,"fill":"#c8d6e0","stroke":"#968d6e","stroke-width":0.7,"filter":null},"#salt":{"opacity":0.5,"fill":"#339482","stroke":"#836a34","stroke-width":0.7,"filter":null},"#sinkhole":{"opacity":1,"fill":"#c3d6df","stroke":"#b29062","stroke-width":0.7,"filter":null},"#frozen":{"opacity":0.95,"fill":"#cdd4e7","stroke":"#cfe0eb","stroke-width":0,"filter":null},"#lava":{"opacity":0.7,"fill":"#a04e18","stroke":"#835520","stroke-width":2,"filter":"url(#paper)"},"#dry":{"opacity":0.7,"fill":"#c6b795","stroke":"#8e816f","stroke-width":0.7,"filter":null},"#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":1,"set":"simple","size":1,"density":0.4,"filter":null,"mask":null},"#rivers":{"opacity":null,"filter":"","fill":"#a69b7d"},"#ruler":{"opacity":null,"filter":null},"#roads":{"opacity":0.7,"stroke":"#8d502a","stroke-width":1,"stroke-dasharray":3,"stroke-linecap":"inherit","filter":"","mask":null},"#trails":{"opacity":0.7,"stroke":"#924217","stroke-width":0.5,"stroke-dasharray":"1 2","stroke-linecap":"butt","filter":null,"mask":null},"#searoutes":{"opacity":0.8,"stroke":"#b16925","stroke-width":0.8,"stroke-dasharray":"1 2","stroke-linecap":"round","filter":null,"mask":null},"#statesBody":{"opacity":0.2,"filter":"url(#filter-sepia)"},"#statesHalo":{"opacity":0.4,"data-width":10,"stroke-width":10,"filter":"blur(6px)"},"#provs":{"opacity":0.7,"fill":"#000000","font-size":10,"font-family":"Georgia","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},"#ice":{"opacity":0.35,"fill":"#e8f0f6","stroke":"#e8f0f6","stroke-width":3,"filter":"url(#dropShadow05)"},"#emblems":{"opacity":0.8,"stroke-width":0.8,"filter":"url(#dropShadow05)"},"#texture":{"opacity":0.6,"filter":"","mask":""},"#textureImage":{"x":0,"y":0},"#zones":{"opacity":0.6,"stroke":"#333333","stroke-width":0,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null,"mask":null},"#oceanLayers":{"filter":"","layers":"-6,-4,-2"},"#oceanBase":{"fill":"#c99f64"},"#oceanicPattern":{"href":"./images/kiwiroo.png","opacity":0.4},"#terrs":{"opacity":null,"scheme":"bright","terracing":0,"skip":2,"relax":1,"curve":0,"filter":"url(#blur3)","mask":"url(#land)"},"#legend":{"data-size":13,"font-size":13,"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},"#burgLabels > #cities":{"opacity":1,"fill":"#3e3e4b","text-shadow":"white 0px 0px 4px","data-size":12,"font-size":12,"font-family":"Great Vibes"},"#burgIcons > #cities":{"opacity":1,"fill":"#fdfab9","fill-opacity":0.7,"size":1,"stroke":"#6f4e1f","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","text-shadow":"white 0px 0px 4px","data-size":5,"font-size":5,"font-family":"Great Vibes"},"#burgIcons > #towns":{"opacity":1,"fill":"#fef4d8","fill-opacity":0.7,"size":0.5,"stroke":"#72472c","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,"text-shadow":"white 0px 0px 4px","data-size":22,"font-size":22,"font-family":"Great Vibes","filter":"url(#filter-sepia)"},"#labels > #addedLabels":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"text-shadow":"white 0px 0px 4px","data-size":18,"font-size":18,"font-family":"Times New Roman","filter":"url(#filter-sepia)"},"#fogging":{"opacity":0.98,"fill":"#30426f","filter":null}}`, - styleGloom: `{"#map":{"background-color":"#000000","filter":null,"data-filter":null},"#armies":{"font-size":6,"box-size":3,"stroke":"#000","stroke-width":0.3,"opacity":1,"fill-opacity":1,"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":null},"#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,"scale":1,"dx":0,"dy":"0","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":null,"mask":null},"#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)"},"#dry":{"opacity":0.7,"fill":"#c9bfa7","stroke":"#8e816f","stroke-width":0.7,"filter":null},"#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":null,"fill":"#779582"},"#ruler":{"opacity":null,"filter":null},"#roads":{"opacity":1,"stroke":"#8b4418","stroke-width":0.9,"stroke-dasharray":"2 3","stroke-linecap":"round","filter":null,"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},"#statesBody":{"opacity":0.4,"filter":null},"#statesHalo":{"opacity":0.5,"data-width":12,"stroke-width":12,"filter":"blur(10px)"},"#provs":{"opacity":0.7,"fill":"#000000","data-size":10,"font-size":10,"font-family":"Georgia","filter":null},"#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},"#ice":{"opacity":0.9,"fill":"#e8f0f6","stroke":"#e8f0f6","stroke-width":1,"filter":"url(#dropShadow05)"},"#emblems": {"opacity":0.6,"stroke-width":0.5,"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},"#oceanLayers":{"filter":null,"layers":"-6,-4,-2"},"#oceanBase":{"fill":"#4e6964"},"#oceanicPattern":{"href":"./images/pattern3.png", "opacity":0.2},"#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,"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","text-shadow":"white 0 0 4px","data-size":7,"font-size":7,"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,"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,"text-shadow":"white 0 0 4px","data-size":22,"font-size":22,"font-family":"Almendra SC","filter":null},"#labels > #addedLabels":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"text-shadow":"white 0 0 4px","data-size":18,"font-size":18,"font-family":"Almendra SC","filter":null},"#fogging":{"opacity":0.98,"fill":"#1b1423","filter":null}}`, - styleClean: `{"#map":{"background-color":"#000000","filter":null,"data-filter":null},"#armies":{"font-size":6,"box-size":3,"stroke":"#000","stroke-width":0,"opacity":1,"fill-opacity":1,"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":null},"#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,"scale":1,"dx":0,"dy":"0","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)"},"#dry":{"opacity":0.7,"fill":"#c9bfa7","stroke":"#8e816f","stroke-width":0.7,"filter":null},"#sea_island":{"opacity":0.6,"stroke":"#595959","stroke-width":0.4,"filter":null,"auto-filter":0},"#lake_island":{"opacity":0,"stroke":"#7c8eaf","stroke-width":0,"filter":null},"#terrain":{"opacity":1,"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)"},"#statesBody":{"opacity":0.3,"filter":null},"#statesHalo":{"opacity":0.5,"data-width":1,"stroke-width":1,"filter":null},"#provs":{"opacity":0.7,"fill":"#000000","data-size":10,"font-size":10,"font-family":"Georgia","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},"#ice":{"opacity":0.9,"fill":"#e8f0f6","stroke":"#e8f0f6","stroke-width":1,"filter":"url(#dropShadow01)"},"#emblems":{"opacity":1,"stroke-width":1,"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},"#oceanLayers":{"filter":null,"layers":"none"},"#oceanBase":{"fill":"#aadaff"},"#oceanicPattern":{"href":"", "opacity":0.2},"#terrs":{"opacity":0.5,"scheme":"bright","terracing":0,"skip":5,"relax":0,"curve":0,"filter":null,"mask":"url(#land)"},"#legend":{"data-size":12.74,"font-size":12.74,"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","text-shadow":"white 0 0 4px","data-size":7,"font-size":7,"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,"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,"text-shadow":"white 0 0 2px","data-size":10,"font-size":10,"font-family":"Arial","filter":null},"#labels > #addedLabels":{"opacity":1,"fill":"#414141","stroke":"#3a3a3a","stroke-width":0,"text-shadow":"white 0 0 4px","data-size":18,"font-size":18,"font-family":"Arial","filter":null},"#fogging":{"opacity":1,"fill":"#ffffff","filter":null}}`, - styleLight: `{"#map":{"background-color":"#000000","filter":null,"data-filter":null},"#armies":{"font-size":8,"box-size":4,"stroke":"#000","stroke-width":0.02,"fill-opacity":0.8,"filter":null},"#biomes":{"opacity":0.5,"filter":null,"mask":"url(#land)"},"#stateBorders":{"opacity":0.8,"stroke":"#4c483e","stroke-width":1,"stroke-dasharray":2,"stroke-linecap":"square","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.5,"scale":1,"dx":0,"dy":0,"type":"pointyHex","stroke":"#808080","stroke-width":1,"stroke-dasharray":null,"stroke-linecap":null,"transform":null,"filter":null,"mask":null},"#coordinates":{"opacity":0.7,"data-size":15,"font-size":15,"stroke":"#734d37","stroke-width":1.5,"stroke-dasharray":5,"stroke-linecap":"square","filter":null,"mask":""},"#compass":{"opacity":0.6,"transform":null,"filter":null,"mask":"url(#water)","shape-rendering":"optimizespeed"},"#rose":{"transform":null},"#relig":{"opacity":0.5,"stroke":null,"stroke-width":0,"filter":null},"#cults":{"opacity":0.5,"stroke":"#777777","stroke-width":0,"stroke-dasharray":null,"stroke-linecap":null,"filter":null},"#landmass":{"opacity":1,"fill":"#f9f2ea","filter":null},"#markers":{"opacity":null,"rescale":1,"filter":null},"#prec":{"opacity":null,"stroke":"#000000","stroke-width":0.1,"fill":"#2554ef","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":"#98cdc4","stroke":"#719892","stroke-width":0.46,"filter":"url(#dropShadow05)"},"#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)"},"#dry":{"opacity":1,"fill":"#c9bfa7","stroke":"#8e816f","stroke-width":0.7,"filter":null},"#sea_island":{"opacity":1,"stroke":"#5e5e5e","stroke-width":0.4,"filter":"url(#dropShadow)","auto-filter":1},"#lake_island":{"opacity":1,"stroke":"#7c8eaf","stroke-width":0.35,"filter":null},"#terrain":{"opacity":0.6,"set":"colored","size":1,"density":0.3,"filter":null,"mask":""},"#rivers":{"opacity":null,"filter":null,"fill":"#6d94ba"},"#ruler":{"opacity":null,"filter":null},"#roads":{"opacity":0.9,"stroke":"#3c1d0b","stroke-width":1.37,"stroke-dasharray":2,"stroke-linecap":"inherit","filter":null,"mask":null},"#trails":{"opacity":0.9,"stroke":"#95481a","stroke-width":0.88,"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},"#statesBody":{"opacity":0.2,"filter":null},"#statesHalo":{"opacity":0.3,"data-width":25,"stroke-width":25,"filter":"blur(5px)"},"#provs":{"opacity":0.4,"fill":"#000000","font-size":5,"font-family":"IM Fell English","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},"#ice":{"opacity":0.5,"fill":"#e8f0f6","stroke":"#e8f0f6","stroke-width":1.5,"filter":"url(#dropShadow05)"},"#emblems":{"opacity":0.9,"stroke-width":1,"filter":null},"#texture":{"opacity":0.39,"filter":null,"mask":""},"#zones":{"opacity":0.6,"stroke":"#333333","stroke-width":0,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null,"mask":null},"#oceanLayers":{"filter":"url(#dropShadow05)","layers":"-6,-3,-1"},"#oceanBase":{"fill":"#8dc1c8"},"#oceanicPattern":{"href":"./images/pattern1.png","opacity":0.2},"#terrs":{"opacity":0.4,"scheme":"light","terracing":10,"skip":5,"relax":0,"curve":0,"filter":"url(#turbulence)","mask":"url(#land)"},"#legend":{"data-size":13,"font-size":13,"font-family":"Almendra SC","stroke":"#812929","stroke-width":2.5,"stroke-dasharray":"0 4 10 4","stroke-linecap":"round","data-x":54.73,"data-y":62.98,"data-columns":8},"#burgLabels > #cities":{"opacity":1,"fill":"#3a3a3a","text-shadow":"white 0px 0px 4px","data-size":8,"font-size":8,"font-family":"IM Fell English"},"#burgIcons > #cities":{"opacity":1,"fill":"#ffffff","fill-opacity":0.7,"size":3,"stroke":"#3e3e4b","stroke-width":0.4,"stroke-dasharray":"0.5 0.25","stroke-linecap":"butt"},"#anchors > #cities":{"opacity":1,"fill":"#ffffff","size":5.5,"stroke":"#3e3e4b","stroke-width":1.2},"#burgLabels > #towns":{"opacity":1,"fill":"#3e3e4b","text-shadow":"white 0px 0px 4px","data-size":4,"font-size":4,"font-family":"IM Fell English"},"#burgIcons > #towns":{"opacity":1,"fill":"#ffffff","fill-opacity":0.7,"size":1.2,"stroke":"#3e3e4b","stroke-width":0.2,"stroke-dasharray":"","stroke-linecap":"butt"},"#anchors > #towns":{"opacity":1,"fill":"#ffffff","size":2.2,"stroke":"#3e3e4b","stroke-width":1.2},"#labels > #states":{"opacity":1,"fill":"#3e3e3e","stroke":"#000000","stroke-width":0.3,"text-shadow":"white 0px 0px 6px","data-size":14,"font-size":14,"font-family":"IM Fell English","filter":null},"#labels > #addedLabels":{"opacity":1,"fill":"#f24706","stroke":"#701b05","stroke-width":0.1,"text-shadow":"white 0px 0px 4px","data-size":6,"font-size":6,"font-family":"IM Fell English","filter":null},"#fogging":{"opacity":1,"fill":"#30426f","filter":null}}`, - styleWatercolor: `{"#map":{"background-color":"#000000","filter":null,"data-filter":null},"#armies":{"font-size":8,"box-size":4,"stroke":"#000","stroke-width":0.2,"fill-opacity":1,"filter":null},"#biomes":{"opacity":0.6,"filter":null,"mask":"url(#land)"},"#stateBorders":{"opacity":0.6,"stroke":"#56566d","stroke-width":1,"stroke-dasharray":3,"stroke-linecap":"butt","filter":null},"#provinceBorders":{"opacity":0.5,"stroke":"#56566d","stroke-width":0.5,"stroke-dasharray":"0 2","stroke-linecap":"round","filter":null},"#cells":{"opacity":null,"stroke":"#808080","stroke-width":0.1,"filter":null,"mask":null},"#gridOverlay":{"opacity":0.8,"scale":1,"dx":0,"dy":0,"type":"pointyHex","stroke":"#777777","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":"#777777","stroke-width":0,"filter":"url(#bluredSplotch)"},"#cults":{"opacity":0.6,"stroke":"#777777","stroke-width":0.5,"stroke-dasharray":null,"stroke-linecap":null,"filter":"url(#splotch)"},"#landmass":{"opacity":1,"fill":"#eef6fb","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)"},"#dry":{"opacity":1,"fill":"#c9bfa7","stroke":"#8e816f","stroke-width":0.7,"filter":null},"#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":1,"set":"gray","size":1,"density":0.4,"filter":null,"mask":null},"#rivers":{"opacity":null,"filter":null,"fill":"#2e89c2"},"#ruler":{"opacity":null,"filter":null},"#roads":{"opacity":0.9,"stroke":"#969696","stroke-width":0.7,"stroke-dasharray":"","stroke-linecap":"butt","filter":null,"mask":null},"#trails":{"opacity":0.9,"stroke":"#969696","stroke-width":0.4,"stroke-dasharray":"","stroke-linecap":"butt","filter":null,"mask":null},"#searoutes":{"opacity":0.9,"stroke":"#969696","stroke-width":0.7,"stroke-dasharray":"","stroke-linecap":"round","filter":null,"mask":null},"#statesBody":{"opacity":0.05,"filter":null},"#statesHalo":{"opacity":0.4,"data-width":8,"stroke-width":8,"filter":"blur(2px)"},"#provs":{"opacity":0.7,"fill":"#000000","font-size":4,"font-family":"Comfortaa","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},"#ice":{"opacity":0.7,"fill":"#dfe8ec","stroke":"#000000","stroke-width":0,"filter":"url(#dropShadow05)"},"#emblems":{"opacity":0.95,"stroke-width":1,"filter":null},"#texture":{"opacity":0.2,"filter":null,"mask":"url(#land)"},"#zones":{"opacity":0.6,"stroke":"#333333","stroke-width":0,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null,"mask":null},"#oceanLayers":{"filter":null,"layers":"-6,-4,-2"},"#oceanBase":{"fill":"#2d788b"},"#oceanicPattern":{"href":"./images/kiwiroo.png","opacity":0.5},"#terrs":{"opacity":0.5,"scheme":"light","terracing":0,"skip":5,"relax":1,"curve":0,"filter":null,"mask":"url(#land)"},"#legend":{"data-size":13,"font-size":13,"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},"#burgLabels > #cities":{"opacity":1,"fill":"#043449","text-shadow":"white 0px 0px 2px","data-size":5,"font-size":5,"font-family":"Comfortaa"},"#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","text-shadow":"white 0px 0px 4px","data-size":3,"font-size":3,"font-family":"Comfortaa"},"#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":"#ffffff","stroke":"#000000","stroke-width":0.15,"text-shadow":"black 1px 1px 2px","data-size":20,"font-size":20,"font-family":"Gloria Hallelujah","filter":null},"#labels > #addedLabels":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"text-shadow":"white 0px 0px 4px","data-size":18,"font-size":18,"font-family":"Comfortaa","filter":null},"#fogging":{"opacity":0.97,"fill":"#8398ce","filter":null}}`, - styleMonochrome: `{"#map":{"background-color":"#000000","filter":"url(#filter-grayscale)","data-filter":"grayscale"},"#armies":{"font-size":6,"box-size":3,"stroke":"#000","stroke-width":0.3,"opacity":1,"fill-opacity":1,"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":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,"scale":1,"dx":0,"dy":"0","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":null},"#sea_island":{"opacity":1,"stroke":"#1f3846","stroke-width":0,"filter":null,"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},"#statesBody":{"opacity":0.4,"filter":null},"#statesHalo":{"opacity":0.4,"data-width":10,"stroke-width":10,"filter":"blur(5px)"},"#provs":{"opacity":0.7,"fill":"#000000","data-size":10,"font-size":10,"font-family":"Georgia","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},"#ice":{"opacity":0.9,"fill":"#e8f0f6","stroke":"#e8f0f6","stroke-width":1,"filter":"url(#dropShadow05)"},"#texture":{"opacity":1,"filter":null,"mask":"url(#land)"},"#emblems": {"opacity": 0.5,"stroke-width": 0.5,"filter": null},"#textureImage":{},"#zones":{"opacity":0.6,"stroke":"#333333","stroke-width":0,"stroke-dasharray":null,"stroke-linecap":"butt","filter":null,"mask":null},"#oceanLayers":{"filter":null,"layers":"none"},"#oceanBase":{"fill":"#000000"},"#oceanicPattern":{"href":"", "opacity":0.2},"#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,"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","text-shadow":"white 0 0 4px","data-size":7,"font-size":7,"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,"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,"text-shadow":"white 0 0 4px","data-size":22,"font-size":22,"font-family":"Almendra SC","filter":null},"#labels > #addedLabels":{"opacity":1,"fill":"#3e3e4b","stroke":"#3a3a3a","stroke-width":0,"text-shadow":"white 0 0 4px","data-size":18,"font-size":18,"font-family":"Almendra SC","filter":null},"#fogging":{"opacity":0.98,"fill":"#30426f","filter":null}}` -}; - -// apply default or custom style settings on load -function applyStyleOnLoad() { - const preset = localStorage.getItem("presetStyle"); - const style = preset && (defaultStyles[preset] || localStorage.getItem(preset)); - - if (preset && style && JSON.isValid(style)) { - applyStyle(JSON.parse(style)); - updateMapFilter(); - stylePreset.value = preset; - stylePreset.dataset.old = preset; - } else { - if (preset && preset !== "styleDefault" && ERROR) console.error(`Style preset ${preset} is not available in localStorage, applying default style`); - stylePreset.value = "styleDefault"; - stylePreset.dataset.old = preset; - applyDefaultStyle(); - } -} - -// set default style -function applyDefaultStyle() { - armies.attr("opacity", 1).attr("fill-opacity", 1).attr("font-size", 6).attr("box-size", 3).attr("stroke", "#000").attr("stroke-width", 0.3); - - biomes.attr("opacity", null).attr("filter", null).attr("mask", "url(#land)"); - ice.attr("opacity", 0.9).attr("fill", "#e8f0f6").attr("stroke", "#e8f0f6").attr("stroke-width", 1).attr("filter", "url(#dropShadow05)"); - stateBorders - .attr("opacity", 0.8) - .attr("stroke", "#56566d") - .attr("stroke-width", 1) - .attr("stroke-dasharray", "2") - .attr("stroke-linecap", "butt") - .attr("filter", null); - provinceBorders - .attr("opacity", 0.8) - .attr("stroke", "#56566d") - .attr("stroke-width", 0.5) - .attr("stroke-dasharray", "0 2") - .attr("stroke-linecap", "round") - .attr("filter", null); - cells.attr("opacity", null).attr("stroke", "#808080").attr("stroke-width", 0.1).attr("filter", null).attr("mask", null); - - gridOverlay - .attr("opacity", 0.8) - .attr("type", "pointyHex") - .attr("scale", 1) - .attr("dx", 0) - .attr("dy", 0) - .attr("stroke", "#777777") - .attr("stroke-width", 0.5) - .attr("stroke-dasharray", null) - .attr("filter", null) - .attr("mask", null); - coordinates - .attr("opacity", 1) - .attr("data-size", 12) - .attr("font-size", 12) - .attr("stroke", "#d4d4d4") - .attr("stroke-width", 1) - .attr("stroke-dasharray", 5) - .attr("filter", null) - .attr("mask", null); - compass.attr("opacity", 0.8).attr("transform", null).attr("filter", null).attr("mask", "url(#water)").attr("shape-rendering", "optimizespeed"); - if (!d3.select("#initial").size()) d3.select("#rose").attr("transform", "translate(80 80) scale(.25)"); - - relig.attr("opacity", 0.7).attr("stroke", "#777777").attr("stroke-width", 0).attr("filter", null); - cults.attr("opacity", 0.6).attr("stroke", "#777777").attr("stroke-width", 0.5).attr("filter", null); - landmass.attr("opacity", 1).attr("fill", "#eef6fb").attr("filter", null); - markers.attr("opacity", null).attr("rescale", 1).attr("filter", "url(#dropShadow01)"); - - prec.attr("opacity", null).attr("stroke", "#000000").attr("stroke-width", 0).attr("fill", "#003dff").attr("filter", null); - population.attr("opacity", null).attr("stroke-width", 1.6).attr("stroke-dasharray", null).attr("stroke-linecap", "butt").attr("filter", null); - population.select("#rural").attr("stroke", "#0000ff"); - population.select("#urban").attr("stroke", "#ff0000"); - - lakes.select("#freshwater").attr("opacity", 0.5).attr("fill", "#a6c1fd").attr("stroke", "#5f799d").attr("stroke-width", 0.7).attr("filter", null); - lakes.select("#salt").attr("opacity", 0.5).attr("fill", "#409b8a").attr("stroke", "#388985").attr("stroke-width", 0.7).attr("filter", null); - lakes.select("#sinkhole").attr("opacity", 1).attr("fill", "#5bc9fd").attr("stroke", "#53a3b0").attr("stroke-width", 0.7).attr("filter", null); - lakes.select("#frozen").attr("opacity", 0.95).attr("fill", "#cdd4e7").attr("stroke", "#cfe0eb").attr("stroke-width", 0).attr("filter", null); - lakes.select("#lava").attr("opacity", 0.7).attr("fill", "#90270d").attr("stroke", "#f93e0c").attr("stroke-width", 2).attr("filter", "url(#crumpled)"); - lakes.select("#dry").attr("opacity", 1).attr("fill", "#c9bfa7").attr("stroke", "#8e816f").attr("stroke-width", 0.7).attr("filter", null); - - coastline - .select("#sea_island") - .attr("opacity", 0.5) - .attr("stroke", "#1f3846") - .attr("stroke-width", 0.7) - .attr("auto-filter", 1) - .attr("filter", "url(#dropShadow)"); - coastline.select("#lake_island").attr("opacity", 1).attr("stroke", "#7c8eaf").attr("stroke-width", 0.35).attr("filter", null); - - terrain.attr("opacity", null).attr("set", "simple").attr("size", 1).attr("density", 0.4).attr("filter", null).attr("mask", null); - rivers.attr("opacity", null).attr("fill", "#5d97bb").attr("filter", null); - ruler.attr("opacity", null).attr("filter", null); - - roads - .attr("opacity", 0.9) - .attr("stroke", "#d06324") - .attr("stroke-width", 0.7) - .attr("stroke-dasharray", "2") - .attr("stroke-linecap", "butt") - .attr("filter", null) - .attr("mask", null); - trails - .attr("opacity", 0.9) - .attr("stroke", "#d06324") - .attr("stroke-width", 0.25) - .attr("stroke-dasharray", ".8 1.6") - .attr("stroke-linecap", "butt") - .attr("filter", null) - .attr("mask", null); - searoutes - .attr("opacity", 0.8) - .attr("stroke", "#ffffff") - .attr("stroke-width", 0.45) - .attr("stroke-dasharray", "1 2") - .attr("stroke-linecap", "round") - .attr("filter", null) - .attr("mask", null); - - statesBody.attr("opacity", 0.4).attr("filter", null); - statesHalo.attr("data-width", 10).attr("stroke-width", 10).attr("opacity", 0.4).attr("filter", "blur(5px)"); - - provs.attr("opacity", 0.7).attr("fill", "#000000").attr("font-family", "Georgia").attr("data-size", 10).attr("font-size", 10).attr("filter", null); - - temperature - .attr("opacity", null) - .attr("fill", "#000000") - .attr("stroke-width", 1.8) - .attr("fill-opacity", 0.3) - .attr("font-size", "8px") - .attr("stroke-dasharray", null) - .attr("filter", null) - .attr("mask", null); - texture.attr("opacity", null).attr("filter", null).attr("mask", "url(#land)"); - texture.select("#textureImage").attr("x", 0).attr("y", 0); - zones - .attr("opacity", 0.6) - .attr("stroke", "#333333") - .attr("stroke-width", 0) - .attr("stroke-dasharray", null) - .attr("stroke-linecap", "butt") - .attr("filter", null) - .attr("mask", null); - - // ocean and svg default style - svg.attr("background-color", "#000000").attr("data-filter", null).attr("filter", null); - oceanLayers.select("rect").attr("fill", "#466eab"); // old color #53679f - oceanLayers.attr("filter", null).attr("layers", "-6,-3,-1"); - svg.select("#oceanicPattern").attr("href", "./images/pattern1.png").attr("opacity", 0.2); - - // heightmap style - terrs - .attr("opacity", null) - .attr("filter", null) - .attr("mask", "url(#land)") - .attr("stroke", "none") - .attr("scheme", "bright") - .attr("terracing", 0) - .attr("skip", 5) - .attr("relax", 0) - .attr("curve", 0); - - // legend - legend - .attr("font-family", "Almendra SC") - .attr("font-size", 13) - .attr("data-size", 13) - .attr("data-x", 99) - .attr("data-y", 93) - .attr("data-columns", 8) - .attr("stroke-width", 2.5) - .attr("stroke", "#812929") - .attr("stroke-dasharray", "0 4 10 4") - .attr("stroke-linecap", "round"); - legend.select("#legendBox").attr("fill", "#ffffff").attr("fill-opacity", 0.8); - - const citiesSize = Math.max(rn(8 - regionsOutput.value / 20), 3); - burgLabels - .select("#cities") - .attr("fill", "#3e3e4b") - .attr("opacity", 1) - .style("text-shadow", "white 0 0 4px") - .attr("font-family", "Almendra SC") - .attr("font-size", citiesSize) - .attr("data-size", citiesSize); - burgIcons - .select("#cities") - .attr("opacity", 1) - .attr("size", 1) - .attr("stroke-width", 0.24) - .attr("fill", "#ffffff") - .attr("stroke", "#3e3e4b") - .attr("fill-opacity", 0.7) - .attr("stroke-dasharray", "") - .attr("stroke-linecap", "butt"); - anchors.select("#cities").attr("opacity", 1).attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("stroke-width", 1.2).attr("size", 2); - - burgLabels - .select("#towns") - .attr("fill", "#3e3e4b") - .attr("opacity", 1) - .style("text-shadow", "white 0 0 4px") - .attr("font-family", "Almendra SC") - .attr("font-size", 3) - .attr("data-size", 4); - burgIcons - .select("#towns") - .attr("opacity", 1) - .attr("size", 0.5) - .attr("stroke-width", 0.12) - .attr("fill", "#ffffff") - .attr("stroke", "#3e3e4b") - .attr("fill-opacity", 0.7) - .attr("stroke-dasharray", "") - .attr("stroke-linecap", "butt"); - anchors.select("#towns").attr("opacity", 1).attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("stroke-width", 1.2).attr("size", 1); - - const stateLabelSize = Math.max(rn(24 - regionsOutput.value / 6), 6); - labels - .select("#states") - .attr("fill", "#3e3e4b") - .attr("opacity", 1) - .attr("stroke", "#3a3a3a") - .attr("stroke-width", 0) - .style("text-shadow", "white 0 0 4px") - .attr("font-family", "Almendra SC") - .attr("font-size", stateLabelSize) - .attr("data-size", stateLabelSize) - .attr("filter", null); - labels - .select("#addedLabels") - .attr("fill", "#3e3e4b") - .attr("opacity", 1) - .attr("stroke", "#3a3a3a") - .attr("stroke-width", 0) - .style("text-shadow", "white 0 0 4px") - .attr("font-family", "Almendra SC") - .attr("font-size", 18) - .attr("data-size", 18) - .attr("filter", null); - - fogging.attr("opacity", 0.98).attr("fill", "#30426f"); - emblems.attr("opacity", 0.9).attr("stroke-width", 1).attr("filter", null); -} - -// apply style settings in JSON -function applyStyle(style) { - for (const selector in style) { - const el = document.querySelector(selector); - if (!el) continue; - for (const attribute in style[selector]) { - const value = style[selector][attribute]; - - if (value === "null" || value === null) { - el.removeAttribute(attribute); - continue; - } - - if (attribute === "text-shadow") { - el.style[attribute] = value; - } else { - el.setAttribute(attribute, value); - } - } - } -} - -// change current style preset to another saved one -function changeStylePreset(preset) { - if (customization) return tip("Please exit the customization mode first", false, "error"); - - if (sessionStorage.getItem("styleChangeWarningShown")) { - changeStyle(); - } else { - sessionStorage.setItem("styleChangeWarningShown", true); - alertMessage.innerHTML = "Are you sure you want to change the style preset? All unsaved style changes will be lost"; - $("#alert").dialog({ - resizable: false, - title: "Change style preset", - width: "23em", - buttons: { - Change: function () { - changeStyle(); - $(this).dialog("close"); - }, - Cancel: function () { - stylePreset.value = stylePreset.dataset.old; - $(this).dialog("close"); - } - } - }); - } - - function changeStyle() { - const customPreset = localStorage.getItem(preset); - if (customPreset) { - if (JSON.isValid(customPreset)) applyStyle(JSON.parse(customPreset)); - else { - tip("Cannot parse stored style JSON. Default style applied", false, "error", 5000); - applyDefaultStyle(); - } - } else if (defaultStyles[preset]) { - const style = defaultStyles[preset]; - if (JSON.isValid(style)) applyStyle(JSON.parse(style)); - else tip("Cannot parse style JSON", false, "error", 5000); - } else applyDefaultStyle(); - - removeStyleButton.style.display = stylePreset.selectedOptions[0].dataset.system ? "none" : "inline-block"; - updateElements(); // change elements - selectStyleElement(); // re-select element to trigger values update - updateMapFilter(); - localStorage.setItem("presetStyle", preset); // save preset to use it onload - stylePreset.dataset.old = stylePreset.value; // save current value - } -} - function updateElements() { // burgIcons to desired size - burgIcons.selectAll("g").each(function (d) { + burgIcons.selectAll("g").each(function () { const size = +this.getAttribute("size"); d3.select(this) .selectAll("circle") @@ -1119,175 +795,6 @@ function updateElements() { invokeActiveZooming(); } -function addStylePreset() { - $("#styleSaver").dialog({ - title: "Style Saver", - width: "26em", - position: {my: "center", at: "center", of: "svg"} - }); - - const currentPreset = document.getElementById("stylePreset").selectedOptions[0]; - const styleName = currentPreset ? currentPreset.text : "custom"; - document.getElementById("styleSaverName").value = styleName; - styleSaverJSON.value = JSON.stringify(getStyle(), null, 2); - checkName(); - - if (modules.saveStyle) return; - modules.saveStyle = true; - - // add listeners - document.getElementById("styleSaverName").addEventListener("input", checkName); - document.getElementById("styleSaverSave").addEventListener("click", saveStyle); - document.getElementById("styleSaverDownload").addEventListener("click", styleDownload); - document.getElementById("styleSaverLoad").addEventListener("click", () => styleToLoad.click()); - document.getElementById("styleToLoad").addEventListener("change", function () { - uploadFile(this, styleUpload); - }); - - function getStyle() { - const style = {}; - const attributes = { - "#map": ["background-color", "filter", "data-filter"], - "#armies": ["font-size", "box-size", "stroke", "stroke-width", "fill-opacity", "filter"], - "#biomes": ["opacity", "filter", "mask"], - "#stateBorders": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter"], - "#provinceBorders": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter"], - "#cells": ["opacity", "stroke", "stroke-width", "filter", "mask"], - "#gridOverlay": ["opacity", "scale", "dx", "dy", "type", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "transform", "filter", "mask"], - "#coordinates": ["opacity", "data-size", "font-size", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"], - "#compass": ["opacity", "transform", "filter", "mask", "shape-rendering"], - "#rose": ["transform"], - "#relig": ["opacity", "stroke", "stroke-width", "filter"], - "#cults": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter"], - "#landmass": ["opacity", "fill", "filter"], - "#markers": ["opacity", "rescale", "filter"], - "#prec": ["opacity", "stroke", "stroke-width", "fill", "filter"], - "#population": ["opacity", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter"], - "#rural": ["stroke"], - "#urban": ["stroke"], - "#freshwater": ["opacity", "fill", "stroke", "stroke-width", "filter"], - "#salt": ["opacity", "fill", "stroke", "stroke-width", "filter"], - "#sinkhole": ["opacity", "fill", "stroke", "stroke-width", "filter"], - "#frozen": ["opacity", "fill", "stroke", "stroke-width", "filter"], - "#lava": ["opacity", "fill", "stroke", "stroke-width", "filter"], - "#dry": ["opacity", "fill", "stroke", "stroke-width", "filter"], - "#sea_island": ["opacity", "stroke", "stroke-width", "filter", "auto-filter"], - "#lake_island": ["opacity", "stroke", "stroke-width", "filter"], - "#terrain": ["opacity", "set", "size", "density", "filter", "mask"], - "#rivers": ["opacity", "filter", "fill"], - "#ruler": ["opacity", "filter"], - "#roads": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"], - "#trails": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"], - "#searoutes": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"], - "#statesBody": ["opacity", "filter"], - "#statesHalo": ["opacity", "data-width", "stroke-width", "filter"], - "#provs": ["opacity", "fill", "font-size", "font-family", "filter"], - "#temperature": ["opacity", "font-size", "fill", "fill-opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter"], - "#ice": ["opacity", "fill", "stroke", "stroke-width", "filter"], - "#emblems": ["opacity", "stroke-width", "filter"], - "#texture": ["opacity", "filter", "mask"], - "#textureImage": ["x", "y"], - "#zones": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"], - "#oceanLayers": ["filter", "layers"], - "#oceanBase": ["fill"], - "#oceanicPattern": ["href", "opacity"], - "#terrs": ["opacity", "scheme", "terracing", "skip", "relax", "curve", "filter", "mask"], - "#legend": ["data-size", "font-size", "font-family", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "data-x", "data-y", "data-columns"], - "#legendBox": ["fill", "fill-opacity"], - "#burgLabels > #cities": ["opacity", "fill", "text-shadow", "data-size", "font-size", "font-family"], - "#burgIcons > #cities": ["opacity", "fill", "fill-opacity", "size", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap"], - "#anchors > #cities": ["opacity", "fill", "size", "stroke", "stroke-width"], - "#burgLabels > #towns": ["opacity", "fill", "text-shadow", "data-size", "font-size", "font-family"], - "#burgIcons > #towns": ["opacity", "fill", "fill-opacity", "size", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap"], - "#anchors > #towns": ["opacity", "fill", "size", "stroke", "stroke-width"], - "#labels > #states": ["opacity", "fill", "stroke", "stroke-width", "text-shadow", "data-size", "font-size", "font-family", "filter"], - "#labels > #addedLabels": ["opacity", "fill", "stroke", "stroke-width", "text-shadow", "data-size", "font-size", "font-family", "filter"], - "#fogging": ["opacity", "fill", "filter"] - }; - - for (const selector in attributes) { - const el = document.querySelector(selector); - if (!el) continue; - - style[selector] = {}; - for (const attr of attributes[selector]) { - let value = el.style[attr] || el.getAttribute(attr); - if (attr === "font-size" && el.hasAttribute("data-size")) value = el.getAttribute("data-size"); - style[selector][attr] = parseValue(value); - } - } - - function parseValue(value) { - if (value === "null" || value === null) return null; - if (value === "") return ""; - if (!isNaN(+value)) return +value; - return value; - } - - return style; - } - - function checkName() { - let tip = ""; - const v = "style" + styleSaverName.value; - const listed = Array.from(stylePreset.options).some(o => o.value == v); - const stored = localStorage.getItem(v); - if (!stored && listed) tip = "default"; - else if (stored) tip = "existing"; - else if (styleSaverName.value) tip = "new"; - styleSaverTip.innerHTML = tip; - } - - function saveStyle() { - if (!styleSaverJSON.value) return tip("Please provide a style JSON", false, "error"); - if (!JSON.isValid(styleSaverJSON.value)) return tip("JSON string is not valid, please check the format", false, "error"); - if (!styleSaverName.value) return tip("Please provide a preset name", false, "error"); - if (styleSaverTip.innerHTML === "default") return tip("You cannot overwrite default preset, please change the name", false, "error"); - - const preset = "style" + styleSaverName.value; - applyOption(stylePreset, preset, styleSaverName.value); // add option - localStorage.setItem("presetStyle", preset); // mark preset as default - localStorage.setItem(preset, styleSaverJSON.value); // save preset - - applyStyle(JSON.parse(styleSaverJSON.value)); - updateMapFilter(); - invokeActiveZooming(); - - $("#styleSaver").dialog("close"); - removeStyleButton.style.display = "inline-block"; - tip("Style preset is saved", false, "success", 4000); - } - - function styleDownload() { - if (!styleSaverJSON.value) return tip("Please provide a style JSON", false, "error"); - if (!JSON.isValid(styleSaverJSON.value)) return tip("JSON string is not valid, please check the format", false, "error"); - if (!styleSaverName.value) return tip("Please provide a preset name", false, "error"); - - const data = styleSaverJSON.value; - if (!data) return tip("Please provide a style JSON", false, "error"); - downloadFile(data, "style" + styleSaverName.value + ".json", "application/json"); - } - - function styleUpload(dataLoaded) { - if (!dataLoaded) return tip("Cannot load the file. Please check the data format", false, "error"); - const data = JSON.stringify(JSON.parse(dataLoaded), null, 2); - styleSaverJSON.value = data; - } -} - -function removeStylePreset() { - if (stylePreset.selectedOptions[0].dataset.system) return tip("Cannot remove system preset", false, "error"); - - localStorage.removeItem("presetStyle"); - localStorage.removeItem(stylePreset.value); - stylePreset.selectedOptions[0].remove(); - removeStyleButton.style.display = "none"; - - applyDefaultStyle(); - updateMapFilter(); - invokeActiveZooming(); -} - // GLOBAL FILTERS mapFilters.addEventListener("click", applyMapFilter); function applyMapFilter(event) { @@ -1300,10 +807,3 @@ function applyMapFilter(event) { button.classList.add("pressed"); svg.attr("data-filter", button.id).attr("filter", "url(#filter-" + button.id + ")"); } - -function updateMapFilter() { - const filter = svg.attr("data-filter"); - mapFilters.querySelectorAll(".pressed").forEach(button => button.classList.remove("pressed")); - if (!filter) return; - mapFilters.querySelector("#" + filter).classList.add("pressed"); -} diff --git a/modules/ui/stylePresets.js b/modules/ui/stylePresets.js new file mode 100644 index 00000000..7353b067 --- /dev/null +++ b/modules/ui/stylePresets.js @@ -0,0 +1,311 @@ +// UI module to control the style presets +"use strict"; + +const systemPresets = ["default", "ancient", "gloom", "light", "watercolor", "clean", "atlas", "cyberpunk", "monochrome"]; +const customPresetPrefix = "fmgStyle_"; + +// add style presets to list +{ + const systemOptions = systemPresets.map(styleName => ``); + const storedStyles = Object.keys(localStorage).filter(key => key.startsWith(customPresetPrefix)); + const customOptions = storedStyles.map(styleName => ``); + const options = systemOptions.join("") + customOptions.join(""); + document.getElementById("stylePreset").innerHTML = options; +} + +async function applyStyleOnLoad() { + const desiredPreset = localStorage.getItem("presetStyle") || "default"; + const styleData = await getStylePreset(desiredPreset); + const [appliedPreset, style] = styleData; + + applyStyle(style); + updateMapFilter(); + stylePreset.value = stylePreset.dataset.old = appliedPreset; + setPresetRemoveButtonVisibiliy(); +} + +async function getStylePreset(desiredPreset) { + let presetToLoad = desiredPreset; + + const isCustom = !systemPresets.includes(desiredPreset); + if (isCustom) { + const storedStyleJSON = localStorage.getItem(desiredPreset); + if (!storedStyleJSON) { + ERROR && console.error(`Custom style ${desiredPreset} in not found in localStorage. Applying default style`); + presetToLoad = "default"; + } else { + const isValid = JSON.isValid(storedStyleJSON); + if (isValid) return [desiredPreset, JSON.parse(storedStyleJSON)]; + + ERROR && console.error(`Custom style ${desiredPreset} stored in localStorage is not valid. Applying default style`); + presetToLoad = "default"; + } + } + + const style = await fetchSystemPreset(presetToLoad); + return [presetToLoad, style]; +} + +async function fetchSystemPreset(preset) { + const style = await fetch(`./styles/${preset}.json`) + .then(res => res.json()) + .catch(err => { + ERROR && console.error("Error on loading style preset", preset, err); + return null; + }); + + if (!style) throw new Error("Cannot fetch style preset", preset); + return style; +} + +function applyStyle(style) { + for (const selector in style) { + const el = document.querySelector(selector); + if (!el) continue; + for (const attribute in style[selector]) { + const value = style[selector][attribute]; + + if (value === "null" || value === null) { + el.removeAttribute(attribute); + continue; + } + + if (attribute === "text-shadow") { + el.style[attribute] = value; + } else { + el.setAttribute(attribute, value); + } + } + } +} + +function requestStylePresetChange(preset) { + const isConfirmed = sessionStorage.getItem("styleChangeConfirmed"); + if (isConfirmed) { + changeStyle(preset); + return; + } + + confirmationDialog({ + title: "Change style preset", + message: "Are you sure you want to change the style preset? All unsaved style changes will be lost", + confirm: "Change", + onConfirm: () => { + sessionStorage.setItem("styleChangeConfirmed", true); + changeStyle(preset); + }, + onCancel: () => { + stylePreset.value = stylePreset.dataset.old; + } + }); +} + +async function changeStyle(desiredPreset) { + const styleData = await getStylePreset(desiredPreset); + const [appliedPreset, style] = styleData; + localStorage.setItem("presetStyle", appliedPreset); + applyStyleWithUiRefresh(style); +} + +function applyStyleWithUiRefresh(style) { + applyStyle(style); + updateElements(); + selectStyleElement(); // re-select element to trigger values update + updateMapFilter(); + stylePreset.dataset.old = stylePreset.value; + + invokeActiveZooming(); + setPresetRemoveButtonVisibiliy(); +} + +function addStylePreset() { + $("#styleSaver").dialog({title: "Style Saver", width: "26em", position: {my: "center", at: "center", of: "svg"}}); + + const styleName = stylePreset.value.replace(customPresetPrefix, ""); + document.getElementById("styleSaverName").value = styleName; + styleSaverJSON.value = JSON.stringify(collectStyleData(), null, 2); + checkName(); + + if (modules.saveStyle) return; + modules.saveStyle = true; + + // add listeners + document.getElementById("styleSaverName").addEventListener("input", checkName); + document.getElementById("styleSaverSave").addEventListener("click", saveStyle); + document.getElementById("styleSaverDownload").addEventListener("click", styleDownload); + document.getElementById("styleSaverLoad").addEventListener("click", () => styleToLoad.click()); + document.getElementById("styleToLoad").addEventListener("change", loadStyleFile); + + function collectStyleData() { + const style = {}; + const attributes = { + "#map": ["background-color", "filter", "data-filter"], + "#armies": ["font-size", "box-size", "stroke", "stroke-width", "fill-opacity", "filter"], + "#biomes": ["opacity", "filter", "mask"], + "#stateBorders": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter"], + "#provinceBorders": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter"], + "#cells": ["opacity", "stroke", "stroke-width", "filter", "mask"], + "#gridOverlay": ["opacity", "scale", "dx", "dy", "type", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "transform", "filter", "mask"], + "#coordinates": ["opacity", "data-size", "font-size", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"], + "#compass": ["opacity", "transform", "filter", "mask", "shape-rendering"], + "#rose": ["transform"], + "#relig": ["opacity", "stroke", "stroke-width", "filter"], + "#cults": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter"], + "#landmass": ["opacity", "fill", "filter"], + "#markers": ["opacity", "rescale", "filter"], + "#prec": ["opacity", "stroke", "stroke-width", "fill", "filter"], + "#population": ["opacity", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter"], + "#rural": ["stroke"], + "#urban": ["stroke"], + "#freshwater": ["opacity", "fill", "stroke", "stroke-width", "filter"], + "#salt": ["opacity", "fill", "stroke", "stroke-width", "filter"], + "#sinkhole": ["opacity", "fill", "stroke", "stroke-width", "filter"], + "#frozen": ["opacity", "fill", "stroke", "stroke-width", "filter"], + "#lava": ["opacity", "fill", "stroke", "stroke-width", "filter"], + "#dry": ["opacity", "fill", "stroke", "stroke-width", "filter"], + "#sea_island": ["opacity", "stroke", "stroke-width", "filter", "auto-filter"], + "#lake_island": ["opacity", "stroke", "stroke-width", "filter"], + "#terrain": ["opacity", "set", "size", "density", "filter", "mask"], + "#rivers": ["opacity", "filter", "fill"], + "#ruler": ["opacity", "filter"], + "#roads": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"], + "#trails": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"], + "#searoutes": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"], + "#statesBody": ["opacity", "filter"], + "#statesHalo": ["opacity", "data-width", "stroke-width", "filter"], + "#provs": ["opacity", "fill", "font-size", "font-family", "filter"], + "#temperature": ["opacity", "font-size", "fill", "fill-opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter"], + "#ice": ["opacity", "fill", "stroke", "stroke-width", "filter"], + "#emblems": ["opacity", "stroke-width", "filter"], + "#texture": ["opacity", "filter", "mask"], + "#textureImage": ["x", "y"], + "#zones": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"], + "#oceanLayers": ["filter", "layers"], + "#oceanBase": ["fill"], + "#oceanicPattern": ["href", "opacity"], + "#terrs": ["opacity", "scheme", "terracing", "skip", "relax", "curve", "filter", "mask"], + "#legend": ["data-size", "font-size", "font-family", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "data-x", "data-y", "data-columns"], + "#legendBox": ["fill", "fill-opacity"], + "#burgLabels > #cities": ["opacity", "fill", "text-shadow", "data-size", "font-size", "font-family"], + "#burgIcons > #cities": ["opacity", "fill", "fill-opacity", "size", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap"], + "#anchors > #cities": ["opacity", "fill", "size", "stroke", "stroke-width"], + "#burgLabels > #towns": ["opacity", "fill", "text-shadow", "data-size", "font-size", "font-family"], + "#burgIcons > #towns": ["opacity", "fill", "fill-opacity", "size", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap"], + "#anchors > #towns": ["opacity", "fill", "size", "stroke", "stroke-width"], + "#labels > #states": ["opacity", "fill", "stroke", "stroke-width", "text-shadow", "data-size", "font-size", "font-family", "filter"], + "#labels > #addedLabels": ["opacity", "fill", "stroke", "stroke-width", "text-shadow", "data-size", "font-size", "font-family", "filter"], + "#fogging": ["opacity", "fill", "filter"] + }; + + for (const selector in attributes) { + const el = document.querySelector(selector); + if (!el) continue; + + style[selector] = {}; + for (const attr of attributes[selector]) { + let value = el.style[attr] || el.getAttribute(attr); + if (attr === "font-size" && el.hasAttribute("data-size")) value = el.getAttribute("data-size"); + style[selector][attr] = parseValue(value); + } + } + + function parseValue(value) { + if (value === "null" || value === null) return null; + if (value === "") return ""; + if (!isNaN(+value)) return +value; + return value; + } + + return style; + } + + function checkName() { + const styleName = customPresetPrefix + styleSaverName.value; + + const isSystem = systemPresets.includes(styleName) || systemPresets.includes(styleSaverName.value); + if (isSystem) return (styleSaverTip.innerHTML = "default"); + + const isExisting = Array.from(stylePreset.options).some(option => option.value == styleName); + if (isExisting) return (styleSaverTip.innerHTML = "existing"); + + styleSaverTip.innerHTML = "new"; + } + + function saveStyle() { + const styleJSON = styleSaverJSON.value; + const desiredName = styleSaverName.value; + + if (!styleJSON) return tip("Please provide a style JSON", false, "error"); + if (!JSON.isValid(styleJSON)) return tip("JSON string is not valid, please check the format", false, "error"); + if (!desiredName) return tip("Please provide a preset name", false, "error"); + if (styleSaverTip.innerHTML === "default") return tip("You cannot overwrite default preset, please change the name", false, "error"); + + const presetName = customPresetPrefix + desiredName; + applyOption(stylePreset, presetName, desiredName + " [custom]"); + localStorage.setItem("presetStyle", presetName); + localStorage.setItem(presetName, styleJSON); + + applyStyleWithUiRefresh(JSON.parse(styleJSON)); + tip("Style preset is saved and applied", false, "success", 4000); + $("#styleSaver").dialog("close"); + } + + function styleDownload() { + const styleJSON = styleSaverJSON.value; + const styleName = styleSaverName.value; + + if (!styleJSON) return tip("Please provide a style JSON", false, "error"); + if (!JSON.isValid(styleJSON)) return tip("JSON string is not valid, please check the format", false, "error"); + if (!styleName) return tip("Please provide a preset name", false, "error"); + + downloadFile(styleJSON, styleName + ".json", "application/json"); + } + + function loadStyleFile() { + const fileName = this.files[0]?.name.replace(/\.[^.]*$/, ""); + uploadFile(this, styleUpload); + + function styleUpload(dataLoaded) { + if (!dataLoaded) return tip("Cannot load the file. Please check the data format", false, "error"); + const isValid = JSON.isValid(dataLoaded); + if (!isValid) return tip("Loaded data is not a valid JSON, please check the format", false, "error"); + + styleSaverJSON.value = JSON.stringify(JSON.parse(dataLoaded), null, 2); + styleSaverName.value = fileName; + checkName(); + tip("Style preset is uploaded", false, "success", 4000); + } + } +} + +function requestRemoveStylePreset() { + const isDefault = systemPresets.includes(stylePreset.value); + if (isDefault) return tip("Cannot remove system preset", false, "error"); + + confirmationDialog({ + title: "Remove style preset", + message: "Are you sure you want to remove the style preset? This action cannot be undone.", + confirm: "Remove", + onConfirm: removeStylePreset + }); +} + +function removeStylePreset() { + localStorage.removeItem("presetStyle"); + localStorage.removeItem(stylePreset.value); + stylePreset.selectedOptions[0].remove(); + + changeStyle("default"); +} + +function updateMapFilter() { + const filter = svg.attr("data-filter"); + mapFilters.querySelectorAll(".pressed").forEach(button => button.classList.remove("pressed")); + if (!filter) return; + mapFilters.querySelector("#" + filter).classList.add("pressed"); +} + +function setPresetRemoveButtonVisibiliy() { + const isDefault = systemPresets.includes(stylePreset.value); + removeStyleButton.style.display = isDefault ? "none" : "inline-block"; +} diff --git a/modules/ui/temperature-graph.js b/modules/ui/temperature-graph.js new file mode 100644 index 00000000..0b3ea567 --- /dev/null +++ b/modules/ui/temperature-graph.js @@ -0,0 +1,161 @@ +"use strict"; + +function showBurgTemperatureGraph(id) { + const b = pack.burgs[id]; + const lat = mapCoordinates.latN - (b.y / graphHeight) * mapCoordinates.latT; + const burgTemp = grid.cells.temp[pack.cells.g[b.cell]]; + const prec = grid.cells.prec[pack.cells.g[b.cell]]; + + // prettier-ignore + const weights = [ + [ + [10.782752257744338, 2.7100404240962126], [-2.8226802110591462, 51.62920138583541], [-6.6250956268643835, 4.427939197315455], [-59.64690518541339, 41.89084162654791], [-1.3302059550553835, -3.6964487738450913], + [-2.5844898544535497, 0.09879268612455298], [-5.58528252533573, -0.23426224364501905], [26.94531337690372, 20.898158905988907], [3.816397481634785, -0.19045424064580757], [-4.835697931609101, -10.748232783636434] + ], + [ + [-2.478952081870123, 0.6405800134306895, -7.136785640930911, -0.2186529024764509, 3.6568435212735424, 31.446026153530838, -19.91005187482281, 0.2543395274783306, -7.036924569659988, -0.7721371621651565], + [-197.10583739743538, 6.889921141533474, 0.5058941504631129, 7.7667203434606416, -53.74180550086929, -15.717331715167001, -61.32068414155791, -2.259728220978728, 35.84049189540032, 94.6157364730977], + [-5.312011591880851, -0.09923148954215096, -1.7132477487917586, -22.55559652066422, 0.4806107280554336, -26.5583974109492, 2.0558257347014863, 25.815645234787432, -18.569029876991156, -2.6792003366730035], + [20.706518520569514, 18.344297403881875, 99.52244671131733, -58.53124969563653, -60.74384321042212, -80.57540534651835, 7.884792406540866, -144.33871131678563, 80.134199744324, 20.50745285622448], + [-52.88299538575159, -15.782505343805528, 16.63316001054924, 88.09475330556671, -17.619552086641818, -19.943999528182427, -120.46286026828177, 19.354752020806302, 43.49422099308949, 28.733924806541363], + [-2.4621368711159897, -1.2074759925679757, -1.5133898639835084, 2.173715352424188, -5.988707597991683, 3.0234147182203843, 3.3284199340000797, -1.8805161326360575, 5.151910934121654, -1.2540553911612116] + ], + [ + [-0.3357437479474717, 0.01430651794222215, -0.7927524256670906, 0.2121636229648523, 1.0587803023358318, -3.759288325505095], + [-1.1988028704442968, 1.3768997508052783, -3.8480086358278816, 0.5289387340947143, 0.5769459339961177, -1.2528318145750772], + [1.0074966649240946, 1.155301164699459, -2.974254371052421, 0.47408176553219467, 0.5939042688615264, -0.7631976947131744] + ] + ]; + // From (-∞, ∞) to ~[-1, 1] + const In1 = [(Math.abs(lat) - 26.950680212887473) / 48.378128506956, (prec - 12.229929140832644) / 29.94402033696607]; + + let lastIn = In1; + let lstOut = []; + + for (let levelN = 0; levelN < weights.length; levelN++) { + const layerN = weights[levelN]; + for (let i = 0; i < layerN.length; i++) { + lstOut[i] = 0; + for (let j = 0; j < layerN[i].length; j++) { + lstOut[i] = lstOut[i] + lastIn[j] * layerN[i][j]; + } + // sigmoid + lstOut[i] = 1 / (1 + Math.exp(-lstOut[i])); + } + lastIn = lstOut.slice(0); + } + + // Standard deviation for average temperature for the year from [0, 1] to [min, max] + const yearSig = lstOut[0] * 62.9466411977018 + 0.28613807855649165; + // Standard deviation for the difference between the minimum and maximum temperatures for the year + const yearDelTmpSig = lstOut[1] * 13.541688670361175 + 0.1414213562373084 > yearSig ? yearSig : lstOut[1] * 13.541688670361175 + 0.1414213562373084; + // Expected value for the difference between the minimum and maximum temperatures for the year + const yearDelTmpMu = lstOut[2] * 15.266666666666667 + 0.6416666666666663; + + // Temperature change shape + const delT = yearDelTmpMu / 2 + (0.5 * yearDelTmpSig) / 2; + const minT = burgTemp - Math.max(yearSig + delT, 15); + const maxT = burgTemp + (burgTemp - minT); + + const chartWidth = Math.max(window.innerWidth / 2, 580); + const chartHeight = 300; + + // drawing starting point from top-left (y = 0) of SVG + const xOffset = 60; + const yOffset = 10; + + const year = new Date().getFullYear(); // use current year + const startDate = new Date(year, 0, 1); + const endDate = new Date(year, 11, 31); + const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; + + const xscale = d3.scaleTime().domain([startDate, endDate]).range([0, chartWidth]); + const yscale = d3.scaleLinear().domain([minT, maxT]).range([chartHeight, 0]); + + const tempMean = []; + const tempMin = []; + const tempMax = []; + + months.forEach((month, index) => { + const rate = index / 11; + let formTmp = Math.cos(rate * 2 * Math.PI) / 2; + if (lat > 0) formTmp = -formTmp; + + const x = rate * chartWidth + xOffset; + const tempAverage = formTmp * yearSig + burgTemp; + const tempDelta = yearDelTmpMu / 2 + (formTmp * yearDelTmpSig) / 2; + + tempMean.push([x, yscale(tempAverage) + yOffset]); + tempMin.push([x, yscale(tempAverage - tempDelta) + yOffset]); + tempMax.push([x, yscale(tempAverage + tempDelta) + yOffset]); + }); + + drawGraph(); + $("#alert").dialog({title: "Annual temperature in " + b.name, width: "auto", position: {my: "center", at: "center", of: "svg"}}); + + function drawGraph() { + alertMessage.innerHTML = ""; + const getCurve = data => round(d3.line().curve(d3.curveBasis)(data), 2); + + const legendSize = 60; + const chart = d3 + .select("#alertMessage") + .append("svg") + .attr("width", chartWidth + 120) + .attr("height", chartHeight + yOffset + legendSize); + + const legend = chart.append("g"); + const legendY = chartHeight + yOffset + legendSize * 0.8; + const legendX = n => (chartWidth * n) / 4; + const legendTextX = n => legendX(n) + 10; + legend.append("circle").attr("cx", legendX(1)).attr("cy", legendY).attr("r", 4).style("fill", "red"); + legend.append("text").attr("x", legendTextX(1)).attr("y", legendY).attr("alignment-baseline", "central").text("Day temperature"); + legend.append("circle").attr("cx", legendX(2)).attr("cy", legendY).attr("r", 4).style("fill", "orange"); + legend.append("text").attr("x", legendTextX(2)).attr("y", legendY).attr("alignment-baseline", "central").text("Mean temperature"); + legend.append("circle").attr("cx", legendX(3)).attr("cy", legendY).attr("r", 4).style("fill", "blue"); + legend.append("text").attr("x", legendTextX(3)).attr("y", legendY).attr("alignment-baseline", "central").text("Night temperature"); + + const xGrid = d3.axisBottom(xscale).ticks().tickSize(-chartHeight); + const yGrid = d3.axisLeft(yscale).ticks(5).tickSize(-chartWidth); + + const grid = chart.append("g").attr("class", "epgrid").attr("stroke-dasharray", "4 1"); + grid.append("g").attr("transform", `translate(${xOffset}, ${chartHeight + yOffset})`).call(xGrid); // prettier-ignore + grid.append("g").attr("transform", `translate(${xOffset}, ${yOffset})`).call(yGrid); + grid.selectAll("text").remove(); + + // add zero degree line + if (minT < 0 && maxT > 0) { + grid + .append("line") + .attr("x1", xOffset) + .attr("y1", yscale(0) + yOffset) + .attr("x2", chartWidth + xOffset) + .attr("y2", yscale(0) + yOffset) + .attr("stroke", "gray"); + } + + const xAxis = d3.axisBottom(xscale).ticks().tickFormat(d3.timeFormat("%B")); + const yAxis = d3.axisLeft(yscale).ticks(5).tickFormat(convertTemperature); + + const axis = chart.append("g"); + axis + .append("g") + .attr("transform", `translate(${xOffset}, ${chartHeight + yOffset})`) + .call(xAxis); + axis.append("g").attr("transform", `translate(${xOffset}, ${yOffset})`).call(yAxis); + axis.select("path.domain").attr("d", `M0.5,0.5 H${chartWidth + 0.5}`); + + const curves = chart.append("g").attr("fill", "none").style("stroke-width", 2.5); + curves.append("path").attr("d", getCurve(tempMean)).attr("data-type", "daily").attr("stroke", "orange").on("mousemove", printVal); + curves.append("path").attr("d", getCurve(tempMin)).attr("data-type", "night").attr("stroke", "blue").on("mousemove", printVal); + curves.append("path").attr("d", getCurve(tempMax)).attr("data-type", "day").attr("stroke", "red").on("mousemove", printVal); + + function printVal() { + const [x, y] = d3.mouse(this); + const type = this.getAttribute("data-type"); + const temp = convertTemperature(yscale.invert(y - yOffset)); + const month = months[rn(((x - xOffset) / chartWidth) * 12)] || months[0]; + tip(`Average ${type} temperature in ${month}: ${temp}`); + } + } +} diff --git a/modules/ui/units-editor.js b/modules/ui/units-editor.js index 3131f64c..0f1345e0 100644 --- a/modules/ui/units-editor.js +++ b/modules/ui/units-editor.js @@ -11,6 +11,8 @@ function editUnits() { position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"} }); + const drawBar = () => drawScaleBar(scale); + // add listeners document.getElementById("distanceUnitInput").addEventListener("change", changeDistanceUnit); document.getElementById("distanceScaleOutput").addEventListener("input", changeDistanceScale); @@ -19,9 +21,9 @@ function editUnits() { document.getElementById("heightExponentInput").addEventListener("input", changeHeightExponent); document.getElementById("heightExponentOutput").addEventListener("input", changeHeightExponent); document.getElementById("temperatureScale").addEventListener("change", changeTemperatureScale); - document.getElementById("barSizeOutput").addEventListener("input", drawScaleBar); - document.getElementById("barSizeInput").addEventListener("input", drawScaleBar); - document.getElementById("barLabel").addEventListener("input", drawScaleBar); + document.getElementById("barSizeOutput").addEventListener("input", drawBar); + document.getElementById("barSizeInput").addEventListener("input", drawBar); + document.getElementById("barLabel").addEventListener("input", drawBar); document.getElementById("barPosX").addEventListener("input", fitScaleBar); document.getElementById("barPosY").addEventListener("input", fitScaleBar); document.getElementById("barBackOpacity").addEventListener("input", changeScaleBarOpacity); @@ -46,19 +48,18 @@ function editUnits() { prompt("Provide a custom name for a distance unit", {default: ""}, custom => { this.options.add(new Option(custom, custom, false, true)); lock("distanceUnit"); - drawScaleBar(); + drawScaleBar(scale); calculateFriendlyGridSize(); }); return; } - drawScaleBar(); + drawScaleBar(scale); calculateFriendlyGridSize(); } function changeDistanceScale() { - distanceScale = +document.getElementById("distanceScaleInput").value; - drawScaleBar(); + drawScaleBar(scale); calculateFriendlyGridSize(); } @@ -138,7 +139,7 @@ function editUnits() { localStorage.removeItem("barBackColor"); localStorage.removeItem("barPosX"); localStorage.removeItem("barPosY"); - drawScaleBar(); + drawScaleBar(scale); // population populationRate = populationRateOutput.value = populationRateInput.value = 1000; diff --git a/modules/ui/zones-editor.js b/modules/ui/zones-editor.js index 00ea9196..122ea083 100644 --- a/modules/ui/zones-editor.js +++ b/modules/ui/zones-editor.js @@ -4,6 +4,8 @@ function editZones() { closeDialogs(); if (!layerIsOn("toggleZones")) toggleZones(); const body = document.getElementById("zonesBodySection"); + + updateFilters(); zonesEditorAddLines(); if (modules.editZones) return; @@ -18,6 +20,8 @@ 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); @@ -33,55 +37,60 @@ function editZones() { const el = ev.target, cl = el.classList, zone = el.parentNode.dataset.id; - if (cl.contains("culturePopulation")) { - changePopulation(zone); - return; - } - if (cl.contains("icon-trash-empty")) { - zoneRemove(zone); - return; - } - if (cl.contains("icon-eye")) { - toggleVisibility(el); - return; - } - if (cl.contains("icon-pin")) { - toggleFog(zone, cl); - return; - } - if (cl.contains("fillRect")) { - changeFill(el); - return; - } + if (el.tagName === "FILL-BOX") changeFill(el); + else if (cl.contains("culturePopulation")) changePopulation(zone); + else if (cl.contains("icon-trash-empty")) zoneRemove(zone); + else if (cl.contains("icon-eye")) toggleVisibility(el); + else if (cl.contains("icon-pin")) toggleFog(zone, cl); if (customization) selectZone(el); }); body.addEventListener("input", function (ev) { - const el = ev.target, - zone = el.parentNode.dataset.id; - if (el.classList.contains("religionName")) zones.select("#" + zone).attr("data-description", el.value); + const el = ev.target; + const zone = zones.select("#" + el.parentNode.dataset.id); + + if (el.classList.contains("zoneName")) zone.attr("data-description", el.value); + else if (el.classList.contains("zoneType")) zone.attr("data-type", el.value); }); + // update type filter with a list of used types + function updateFilters() { + const zones = Array.from(document.querySelectorAll("#zones > g")); + const types = unique(zones.map(zone => zone.dataset.type)); + + const filterSelect = document.getElementById("zonesFilterType"); + const typeToFilterBy = types.includes(zonesFilterType.value) ? zonesFilterType.value : "all"; + + filterSelect.innerHTML = "" + types.map(type => ``).join(""); + filterSelect.value = typeToFilterBy; + } + // add line for each zone function zonesEditorAddLines() { const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value; - let lines = ""; - zones.selectAll("g").each(function () { - const c = this.dataset.cells ? this.dataset.cells.split(",").map(c => +c) : []; - const description = this.dataset.description; - const fill = this.getAttribute("fill"); + const typeToFilterBy = document.getElementById("zonesFilterType").value; + const zones = Array.from(document.querySelectorAll("#zones > g")); + const filteredZones = typeToFilterBy === "all" ? zones : zones.filter(zone => zone.dataset.type === typeToFilterBy); + + const lines = filteredZones.map(zoneEl => { + const c = zoneEl.dataset.cells ? zoneEl.dataset.cells.split(",").map(c => +c) : []; + const description = zoneEl.dataset.description; + const type = zoneEl.dataset.type; + const fill = zoneEl.getAttribute("fill"); const area = d3.sum(c.map(i => pack.cells.area[i])) * distanceScaleInput.value ** 2; 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 population = rural + urban; const populationTip = `Total population: ${si(population)}; Rural population: ${si(rural)}; Urban population: ${si(urban)}. Click to change`; - const inactive = this.style.display === "none"; - const focused = defs.select("#fog #focus" + this.id).size(); + const inactive = zoneEl.style.display === "none"; + const focused = defs.select("#fog #focus" + zoneEl.id).size(); - lines += `
    - - + return `
    + + +
    ${c.length}
    @@ -95,13 +104,13 @@ function editZones() {
    `; }); - body.innerHTML = lines; + body.innerHTML = lines.join(""); // update footer const totalArea = (zonesFooterArea.dataset.area = graphWidth * graphHeight * distanceScaleInput.value ** 2); 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 = zones.selectAll("g").size(); + zonesFooterNumber.innerHTML = `${filteredZones.length} of ${zones.length}`; zonesFooterCells.innerHTML = pack.cells.i.length; zonesFooterArea.innerHTML = si(totalArea) + unit; zonesFooterPopulation.innerHTML = si(totalPop); @@ -127,6 +136,19 @@ function editZones() { zones.select("#" + zone).style("outline", null); } + function filterZonesByType() { + const typeToFilterBy = this.value; + const zones = Array.from(document.querySelectorAll("#zones > g")); + + for (const zone of zones) { + const type = zone.dataset.type; + const visible = typeToFilterBy === "all" || type === typeToFilterBy; + zone.style.display = visible ? "block" : "none"; + } + + zonesEditorAddLines(); + } + $(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")); @@ -142,7 +164,7 @@ function editZones() { function enterZonesManualAssignent() { if (!layerIsOn("toggleZones")) toggleZones(); customization = 10; - document.querySelectorAll("#zonesBottom > button").forEach(el => (el.style.display = "none")); + document.querySelectorAll("#zonesBottom > *").forEach(el => (el.style.display = "none")); document.getElementById("zonesManuallyButtons").style.display = "inline-block"; zonesEditor.querySelectorAll(".hide").forEach(el => el.classList.add("hidden")); @@ -256,7 +278,7 @@ function editZones() { function exitZonesManualAssignment(close) { customization = 0; removeCircle(); - document.querySelectorAll("#zonesBottom > button").forEach(el => (el.style.display = "inline-block")); + document.querySelectorAll("#zonesBottom > *").forEach(el => (el.style.display = "inline-block")); document.getElementById("zonesManuallyButtons").style.display = "none"; zonesEditor.querySelectorAll(".hide:not(.show)").forEach(el => el.classList.remove("hidden")); @@ -275,9 +297,9 @@ function editZones() { function changeFill(el) { const fill = el.getAttribute("fill"); - const callback = function (fill) { - el.setAttribute("fill", fill); - document.getElementById(el.parentNode.parentNode.dataset.id).setAttribute("fill", fill); + const callback = newFill => { + el.fill = newFill; + document.getElementById(el.parentNode.dataset.id).setAttribute("fill", newFill); }; openPicker(fill, callback); @@ -344,37 +366,22 @@ function editZones() { function addZonesLayer() { const id = getNextId("zone"); const description = "Unknown zone"; - const fill = "url(#hatch" + (id.slice(4) % 14) + ")"; - zones.append("g").attr("id", id).attr("data-description", description).attr("data-cells", "").attr("fill", fill); - const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value; + 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); - const line = `
    - - - -
    0
    - -
    0 ${unit}
    - -
    0
    - - - - -
    `; - - body.insertAdjacentHTML("beforeend", line); - zonesFooterNumber.innerHTML = zones.selectAll("g").size(); + zonesEditorAddLines(); } function downloadZonesData() { const unit = areaUnit.value === "square" ? distanceUnitInput.value + "2" : areaUnit.value; - let data = "Id,Fill,Description,Cells,Area " + unit + ",Population\n"; // headers + let data = "Id,Fill,Description,Type,Cells,Area " + unit + ",Population\n"; // headers body.querySelectorAll(":scope > div").forEach(function (el) { data += el.dataset.id + ","; data += el.dataset.fill + ","; data += el.dataset.description + ","; + data += el.dataset.type + ","; data += el.dataset.cells + ","; data += el.dataset.area + ","; data += el.dataset.population + "\n"; diff --git a/run_php_server.bat b/run_php_server.bat deleted file mode 100644 index fe11833e..00000000 --- a/run_php_server.bat +++ /dev/null @@ -1,3 +0,0 @@ -start chrome.exe http://localhost:8000/ -@echo off -php -S localhost:8000 \ No newline at end of file diff --git a/styles/ancient.json b/styles/ancient.json new file mode 100644 index 00000000..09704553 --- /dev/null +++ b/styles/ancient.json @@ -0,0 +1,389 @@ +{ + "#map": { + "background-color": "#000000", + "filter": null, + "data-filter": null + }, + "#armies": { + "font-size": 8, + "box-size": 4, + "stroke": "#000", + "stroke-width": 0.2, + "fill-opacity": 1, + "filter": null + }, + "#biomes": { + "opacity": null, + "filter": null, + "mask": "url(#land)" + }, + "#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, + "scale": 1, + "dx": 0, + "dy": 0, + "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.5, + "transform": null, + "filter": "url(#filter-sepia)", + "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": "#e3dfce", + "filter": null + }, + "#markers": { + "opacity": null, + "rescale": 1, + "filter": "" + }, + "#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.6, + "fill": "#c8d6e0", + "stroke": "#968d6e", + "stroke-width": 0.7, + "filter": null + }, + "#salt": { + "opacity": 0.5, + "fill": "#339482", + "stroke": "#836a34", + "stroke-width": 0.7, + "filter": null + }, + "#sinkhole": { + "opacity": 1, + "fill": "#c3d6df", + "stroke": "#b29062", + "stroke-width": 0.7, + "filter": null + }, + "#frozen": { + "opacity": 0.95, + "fill": "#cdd4e7", + "stroke": "#cfe0eb", + "stroke-width": 0, + "filter": null + }, + "#lava": { + "opacity": 0.7, + "fill": "#a04e18", + "stroke": "#835520", + "stroke-width": 2, + "filter": "url(#paper)" + }, + "#dry": { + "opacity": 0.7, + "fill": "#c6b795", + "stroke": "#8e816f", + "stroke-width": 0.7, + "filter": null + }, + "#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": 1, + "set": "simple", + "size": 1, + "density": 0.4, + "filter": null, + "mask": null + }, + "#rivers": { + "opacity": null, + "filter": "", + "fill": "#a69b7d" + }, + "#ruler": { + "opacity": null, + "filter": null + }, + "#roads": { + "opacity": 0.7, + "stroke": "#8d502a", + "stroke-width": 1, + "stroke-dasharray": 3, + "stroke-linecap": "inherit", + "filter": "", + "mask": null + }, + "#trails": { + "opacity": 0.7, + "stroke": "#924217", + "stroke-width": 0.5, + "stroke-dasharray": "1 2", + "stroke-linecap": "butt", + "filter": null, + "mask": null + }, + "#searoutes": { + "opacity": 0.8, + "stroke": "#b16925", + "stroke-width": 0.8, + "stroke-dasharray": "1 2", + "stroke-linecap": "round", + "filter": null, + "mask": null + }, + "#statesBody": { + "opacity": 0.2, + "filter": "url(#filter-sepia)" + }, + "#statesHalo": { + "opacity": 0.4, + "data-width": 10, + "stroke-width": 10, + "filter": "blur(6px)" + }, + "#provs": { + "opacity": 0.7, + "fill": "#000000", + "font-size": 10, + "font-family": "Georgia", + "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 + }, + "#ice": { + "opacity": 0.35, + "fill": "#e8f0f6", + "stroke": "#e8f0f6", + "stroke-width": 3, + "filter": "url(#dropShadow05)" + }, + "#emblems": { + "opacity": 0.8, + "stroke-width": 0.8, + "filter": "url(#dropShadow05)" + }, + "#texture": { + "opacity": 0.6, + "filter": "", + "mask": "" + }, + "#textureImage": { + "x": 0, + "y": 0 + }, + "#zones": { + "opacity": 0.6, + "stroke": "#333333", + "stroke-width": 0, + "stroke-dasharray": null, + "stroke-linecap": "butt", + "filter": null, + "mask": null + }, + "#oceanLayers": { + "filter": "", + "layers": "-6,-4,-2" + }, + "#oceanBase": { + "fill": "#c99f64" + }, + "#oceanicPattern": { + "href": "./images/kiwiroo.png", + "opacity": 0.4 + }, + "#terrs": { + "opacity": null, + "scheme": "bright", + "terracing": 0, + "skip": 2, + "relax": 1, + "curve": 0, + "filter": "url(#blur3)", + "mask": "url(#land)" + }, + "#legend": { + "data-size": 13, + "font-size": 13, + "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 + }, + "#burgLabels > #cities": { + "opacity": 1, + "fill": "#3e3e4b", + "text-shadow": "white 0px 0px 4px", + "data-size": 12, + "font-size": 12, + "font-family": "Great Vibes" + }, + "#burgIcons > #cities": { + "opacity": 1, + "fill": "#fdfab9", + "fill-opacity": 0.7, + "size": 1, + "stroke": "#6f4e1f", + "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", + "text-shadow": "white 0px 0px 4px", + "data-size": 5, + "font-size": 5, + "font-family": "Great Vibes" + }, + "#burgIcons > #towns": { + "opacity": 1, + "fill": "#fef4d8", + "fill-opacity": 0.7, + "size": 0.5, + "stroke": "#72472c", + "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, + "text-shadow": "white 0px 0px 4px", + "data-size": 22, + "font-size": 22, + "font-family": "Great Vibes", + "filter": "url(#filter-sepia)" + }, + "#labels > #addedLabels": { + "opacity": 1, + "fill": "#3e3e4b", + "stroke": "#3a3a3a", + "stroke-width": 0, + "text-shadow": "white 0px 0px 4px", + "data-size": 18, + "font-size": 18, + "font-family": "Times New Roman", + "filter": "url(#filter-sepia)" + }, + "#fogging": { + "opacity": 0.98, + "fill": "#30426f", + "filter": null + } +} diff --git a/styles/atlas.json b/styles/atlas.json new file mode 100644 index 00000000..cc2161db --- /dev/null +++ b/styles/atlas.json @@ -0,0 +1,385 @@ +{ + "#map": { + "background-color": "#000000", + "filter": null, + "data-filter": null + }, + "#armies": { + "font-size": 6, + "box-size": 3, + "stroke": "#000", + "stroke-width": 0.3, + "fill-opacity": 1, + "filter": null + }, + "#biomes": { + "opacity": null, + "filter": null, + "mask": "url(#land)" + }, + "#stateBorders": { + "opacity": 1, + "stroke": "#000000", + "stroke-width": 1.01, + "stroke-dasharray": 0, + "stroke-linecap": "butt", + "filter": null + }, + "#provinceBorders": { + "opacity": 0.8, + "stroke": "#000000", + "stroke-width": 0.69, + "stroke-dasharray": 0, + "stroke-linecap": "round", + "filter": null + }, + "#cells": { + "opacity": null, + "stroke": "#808080", + "stroke-width": 0.1, + "filter": null, + "mask": null + }, + "#gridOverlay": { + "opacity": 1, + "scale": 7.99, + "dx": -2, + "dy": 3, + "type": "square", + "stroke": "#000000", + "stroke-width": 0.05, + "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": "#777777", + "stroke-width": 0, + "filter": null + }, + "#cults": { + "opacity": 0.6, + "stroke": "#777777", + "stroke-width": 0.5, + "stroke-dasharray": null, + "stroke-linecap": null, + "filter": null + }, + "#landmass": { + "opacity": 1, + "fill": "#eef6fb", + "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": "#cae3f7", + "stroke": "#0089ca", + "stroke-width": 1.01, + "filter": null + }, + "#salt": { + "opacity": 1, + "fill": "#cae3f7", + "stroke": "#0089ca", + "stroke-width": 1.01, + "filter": null + }, + "#sinkhole": { + "opacity": 1, + "fill": "#cae3f7", + "stroke": "#0089ca", + "stroke-width": 1.01, + "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)" + }, + "#dry": { + "opacity": 1, + "fill": "#c9bfa7", + "stroke": "#8e816f", + "stroke-width": 0.7, + "filter": null + }, + "#sea_island": { + "opacity": 1, + "stroke": "#028ac9", + "stroke-width": 1.01, + "filter": "", + "auto-filter": 0 + }, + "#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": "#0089ca" + }, + "#ruler": { + "opacity": null, + "filter": null + }, + "#roads": { + "opacity": 1, + "stroke": "#ff2c2c", + "stroke-width": 1.05, + "stroke-dasharray": 0, + "stroke-linecap": "butt", + "filter": null, + "mask": null + }, + "#trails": { + "opacity": 1, + "stroke": "#9f5122", + "stroke-width": 0.43, + "stroke-dasharray": 0, + "stroke-linecap": "butt", + "filter": null, + "mask": null + }, + "#searoutes": { + "opacity": 1, + "stroke": "#0089ca", + "stroke-width": 0.45, + "stroke-dasharray": "1 2", + "stroke-linecap": "round", + "filter": null, + "mask": null + }, + "#statesBody": { + "opacity": 0.49, + "filter": null + }, + "#statesHalo": { + "opacity": 0.4, + "data-width": 10, + "stroke-width": 10, + "filter": "blur(5px)" + }, + "#provs": { + "opacity": 1, + "fill": "#000000", + "font-size": 10, + "font-family": "Georgia", + "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 + }, + "#ice": { + "opacity": 0.9, + "fill": "#e8f0f6", + "stroke": "#e8f0f6", + "stroke-width": 1, + "filter": "url(#dropShadow05)" + }, + "#emblems": { + "opacity": 0.9, + "stroke-width": 1, + "filter": null + }, + "#texture": { + "opacity": null, + "filter": null, + "mask": "url(#land)" + }, + "#zones": { + "opacity": 0.6, + "stroke": "#333333", + "stroke-width": 0, + "stroke-dasharray": null, + "stroke-linecap": "butt", + "filter": null, + "mask": null + }, + "#oceanLayers": { + "filter": "", + "layers": "none" + }, + "#oceanBase": { + "fill": "#b4d2f3" + }, + "#oceanicPattern": { + "href": "", + "opacity": 1 + }, + "#terrs": { + "opacity": null, + "scheme": "bright", + "terracing": 0, + "skip": 0, + "relax": 0, + "curve": 0, + "filter": null, + "mask": "url(#land)" + }, + "#legend": { + "data-size": 13, + "font-size": 13, + "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 + }, + "#burgLabels > #cities": { + "opacity": 1, + "fill": "#000000", + "text-shadow": "white 0px 0px 4px", + "data-size": 5, + "font-size": 5, + "font-family": "Questrial" + }, + "#burgIcons > #cities": { + "opacity": 1, + "fill": "#000000", + "fill-opacity": 0.7, + "size": 1, + "stroke": "#000000", + "stroke-width": 0.24, + "stroke-dasharray": "", + "stroke-linecap": "round" + }, + "#anchors > #cities": { + "opacity": 1, + "fill": "#ffffff", + "size": 2, + "stroke": "#3e3e4b", + "stroke-width": 1.2 + }, + "#burgLabels > #towns": { + "opacity": 1, + "fill": "#000000", + "text-shadow": "white 0px 0px 4px", + "data-size": 4, + "font-size": 4, + "font-family": "Questrial" + }, + "#burgIcons > #towns": { + "opacity": 1, + "fill": "#000000", + "fill-opacity": 0.7, + "size": 0.5, + "stroke": "#000000", + "stroke-width": 0.12, + "stroke-dasharray": "", + "stroke-linecap": "round" + }, + "#anchors > #towns": { + "opacity": 1, + "fill": "#ffffff", + "size": 1, + "stroke": "#3e3e4b", + "stroke-width": 1.2 + }, + "#labels > #states": { + "opacity": 0, + "fill": "#000000", + "stroke": "#000000", + "stroke-width": 0, + "text-shadow": "white 0px 0px 4px", + "data-size": 21, + "font-size": 21, + "font-family": "Questrial", + "filter": null + }, + "#labels > #addedLabels": { + "opacity": 1, + "fill": "#000000", + "stroke": "#000000", + "stroke-width": 0, + "text-shadow": "white 0px 0px 4px", + "data-size": 18, + "font-size": 18, + "font-family": "Questrial", + "filter": null + }, + "#fogging": { + "opacity": 0.98, + "fill": "#30426f", + "filter": null + } +} diff --git a/styles/clean.json b/styles/clean.json new file mode 100644 index 00000000..fd00c5ad --- /dev/null +++ b/styles/clean.json @@ -0,0 +1,388 @@ +{ + "#map": { + "background-color": "#000000", + "filter": null, + "data-filter": null + }, + "#armies": { + "font-size": 6, + "box-size": 3, + "stroke": "#000", + "stroke-width": 0, + "opacity": 1, + "fill-opacity": 1, + "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": null + }, + "#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, + "scale": 1, + "dx": 0, + "dy": "0", + "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)" + }, + "#dry": { + "opacity": 0.7, + "fill": "#c9bfa7", + "stroke": "#8e816f", + "stroke-width": 0.7, + "filter": null + }, + "#sea_island": { + "opacity": 0.6, + "stroke": "#595959", + "stroke-width": 0.4, + "filter": null, + "auto-filter": 0 + }, + "#lake_island": { + "opacity": 0, + "stroke": "#7c8eaf", + "stroke-width": 0, + "filter": null + }, + "#terrain": { + "opacity": 1, + "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)" + }, + "#statesBody": { + "opacity": 0.3, + "filter": null + }, + "#statesHalo": { + "opacity": 0.5, + "data-width": 1, + "stroke-width": 1, + "filter": null + }, + "#provs": { + "opacity": 0.7, + "fill": "#000000", + "data-size": 10, + "font-size": 10, + "font-family": "Georgia", + "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 + }, + "#ice": { + "opacity": 0.9, + "fill": "#e8f0f6", + "stroke": "#e8f0f6", + "stroke-width": 1, + "filter": "url(#dropShadow01)" + }, + "#emblems": { + "opacity": 1, + "stroke-width": 1, + "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 + }, + "#oceanLayers": { + "filter": null, + "layers": "none" + }, + "#oceanBase": { + "fill": "#aadaff" + }, + "#oceanicPattern": { + "href": "", + "opacity": 0.2 + }, + "#terrs": { + "opacity": 0.5, + "scheme": "bright", + "terracing": 0, + "skip": 5, + "relax": 0, + "curve": 0, + "filter": null, + "mask": "url(#land)" + }, + "#legend": { + "data-size": 12.74, + "font-size": 12.74, + "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", + "text-shadow": "white 0 0 4px", + "data-size": 7, + "font-size": 7, + "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, + "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, + "text-shadow": "white 0 0 2px", + "data-size": 10, + "font-size": 10, + "font-family": "Arial", + "filter": null + }, + "#labels > #addedLabels": { + "opacity": 1, + "fill": "#414141", + "stroke": "#3a3a3a", + "stroke-width": 0, + "text-shadow": "white 0 0 4px", + "data-size": 18, + "font-size": 18, + "font-family": "Arial", + "filter": null + }, + "#fogging": { + "opacity": 1, + "fill": "#ffffff", + "filter": null + } +} diff --git a/styles/cyberpunk.json b/styles/cyberpunk.json new file mode 100644 index 00000000..579d093b --- /dev/null +++ b/styles/cyberpunk.json @@ -0,0 +1,385 @@ +{ + "#map": { + "background-color": "#000000", + "filter": null, + "data-filter": null + }, + "#armies": { + "font-size": 8, + "box-size": 4, + "stroke": "#000000", + "stroke-width": 0.6, + "fill-opacity": 1, + "filter": null + }, + "#biomes": { + "opacity": 0.7, + "filter": "", + "mask": "url(#land)" + }, + "#stateBorders": { + "opacity": 1, + "stroke": "#ffffff", + "stroke-width": 1, + "stroke-dasharray": 3, + "stroke-linecap": "round", + "filter": "" + }, + "#provinceBorders": { + "opacity": 0.5, + "stroke": "#ffffff", + "stroke-width": 0.3, + "stroke-dasharray": 1, + "stroke-linecap": "round", + "filter": "" + }, + "#cells": { + "opacity": null, + "stroke": "#808080", + "stroke-width": 0.1, + "filter": null, + "mask": null + }, + "#gridOverlay": { + "opacity": 0.8, + "scale": 1, + "dx": 0, + "dy": 0, + "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": null, + "mask": null + }, + "#compass": { + "opacity": 0.9, + "transform": null, + "filter": null, + "mask": "", + "shape-rendering": "optimizespeed" + }, + "#rose": { + "transform": null + }, + "#relig": { + "opacity": 0.5, + "stroke": "#404040", + "stroke-width": 2, + "filter": "url(#splotch)" + }, + "#cults": { + "opacity": 0.35, + "stroke": "#777777", + "stroke-width": 2, + "stroke-dasharray": null, + "stroke-linecap": null, + "filter": "url(#splotch)" + }, + "#landmass": { + "opacity": 1, + "fill": "#04011e", + "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": "square", + "filter": null + }, + "#rural": { + "stroke": "#5294ff" + }, + "#urban": { + "stroke": "#5cdeff" + }, + "#freshwater": { + "opacity": 0.9, + "fill": "#381579", + "stroke": "#47228c", + "stroke-width": 3, + "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)" + }, + "#dry": { + "opacity": 0.7, + "fill": "#c9bfa7", + "stroke": "#8e816f", + "stroke-width": 0.7, + "filter": null + }, + "#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": null, + "fill": "#6738bc" + }, + "#ruler": { + "opacity": null, + "filter": null + }, + "#roads": { + "opacity": 1, + "stroke": "#c44ac0", + "stroke-width": 0.9, + "stroke-dasharray": "2 3", + "stroke-linecap": "round", + "filter": null, + "mask": null + }, + "#trails": { + "opacity": 1, + "stroke": "#df2654", + "stroke-width": 0.2, + "stroke-dasharray": ".5 1", + "stroke-linecap": "round", + "filter": null, + "mask": null + }, + "#searoutes": { + "opacity": 0.8, + "stroke": "#a890c6", + "stroke-width": 0.6, + "stroke-dasharray": "1.2 2.4", + "stroke-linecap": "round", + "filter": null, + "mask": null + }, + "#statesBody": { + "opacity": 0, + "filter": null + }, + "#statesHalo": { + "opacity": 1, + "data-width": 13, + "stroke-width": 13, + "filter": "blur(8.25px)" + }, + "#provs": { + "opacity": 0.2, + "fill": "#933e3e", + "font-size": 8, + "font-family": "Orbitron", + "filter": "" + }, + "#temperature": { + "opacity": 0.8, + "font-size": "22px", + "fill": "#551282", + "fill-opacity": 0.3, + "stroke": null, + "stroke-width": 3, + "stroke-dasharray": 2, + "stroke-linecap": null, + "filter": null + }, + "#ice": { + "opacity": 0.3, + "fill": "#919191", + "stroke": "#949494", + "stroke-width": 0, + "filter": "url(#dropShadow05)" + }, + "#emblems": { + "opacity": 0.75, + "stroke-width": 0.5, + "filter": "" + }, + "#texture": { + "opacity": 0.14, + "filter": null, + "mask": "url(#water)" + }, + "#zones": { + "opacity": 0.7, + "stroke": "#ffffff", + "stroke-width": 0.3, + "stroke-dasharray": null, + "stroke-linecap": "inherit", + "filter": "url(#dropShadow05)", + "mask": null + }, + "#oceanLayers": { + "filter": "", + "layers": "-6,-3,-1" + }, + "#oceanBase": { + "fill": "#05001f" + }, + "#oceanicPattern": { + "href": "", + "opacity": 0.15 + }, + "#terrs": { + "opacity": 1, + "scheme": "monochrome", + "terracing": 6, + "skip": 0, + "relax": 2, + "curve": 0, + "filter": "", + "mask": "url(#land)" + }, + "#legend": { + "data-size": 13, + "font-size": 13, + "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 + }, + "#burgLabels > #cities": { + "opacity": 1, + "fill": "#ffffff", + "text-shadow": "white 0px 0px 4px", + "data-size": 8, + "font-size": 8, + "font-family": "Orbitron" + }, + "#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": 1, + "fill": "#ffffff", + "size": 4, + "stroke": "#3e3e4b", + "stroke-width": 1 + }, + "#burgLabels > #towns": { + "opacity": 1, + "fill": "#ffffff", + "text-shadow": "white 0px 0px 4px", + "data-size": 3, + "font-size": 3, + "font-family": "Orbitron" + }, + "#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 + }, + "#labels > #states": { + "opacity": 1, + "fill": "#ffffff", + "stroke": "#000000", + "stroke-width": 0, + "text-shadow": "white 0px 0px 4px", + "data-size": 18, + "font-size": 18, + "font-family": "Orbitron", + "filter": "" + }, + "#labels > #addedLabels": { + "opacity": 1, + "fill": "#ffffff", + "stroke": "#000000", + "stroke-width": 0, + "text-shadow": "white 0px 0px 4px", + "data-size": 18, + "font-size": 18, + "font-family": "Almendra SC", + "filter": null + }, + "#fogging": { + "opacity": 0.98, + "fill": "#1b1423", + "filter": null + } +} diff --git a/styles/default.json b/styles/default.json new file mode 100644 index 00000000..eb4acb69 --- /dev/null +++ b/styles/default.json @@ -0,0 +1,385 @@ +{ + "#map": { + "background-color": "#000000", + "filter": null, + "data-filter": null + }, + "#armies": { + "font-size": 6, + "box-size": 3, + "stroke": "#000", + "stroke-width": 0.3, + "fill-opacity": 1, + "filter": null + }, + "#biomes": { + "opacity": null, + "filter": null, + "mask": "url(#land)" + }, + "#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.5, + "stroke-dasharray": "0 2", + "stroke-linecap": "round", + "filter": null + }, + "#cells": { + "opacity": null, + "stroke": "#808080", + "stroke-width": 0.1, + "filter": null, + "mask": null + }, + "#gridOverlay": { + "opacity": 0.8, + "scale": 1, + "dx": 0, + "dy": 0, + "type": "pointyHex", + "stroke": "#777777", + "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": "#777777", + "stroke-width": 0, + "filter": null + }, + "#cults": { + "opacity": 0.6, + "stroke": "#777777", + "stroke-width": 0.5, + "stroke-dasharray": null, + "stroke-linecap": null, + "filter": null + }, + "#landmass": { + "opacity": 1, + "fill": "#eef6fb", + "filter": null + }, + "#markers": { + "opacity": null, + "rescale": 1, + "filter": "url(#dropShadow01)" + }, + "#prec": { + "opacity": null, + "stroke": "#000000", + "stroke-width": 0, + "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)" + }, + "#dry": { + "opacity": 1, + "fill": "#c9bfa7", + "stroke": "#8e816f", + "stroke-width": 0.7, + "filter": null + }, + "#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.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 + }, + "#statesBody": { + "opacity": 0.4, + "filter": null + }, + "#statesHalo": { + "opacity": 0.4, + "data-width": 10, + "stroke-width": 10, + "filter": "blur(5px)" + }, + "#provs": { + "opacity": 0.7, + "fill": "#000000", + "font-size": 10, + "font-family": "Georgia", + "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 + }, + "#ice": { + "opacity": 0.9, + "fill": "#e8f0f6", + "stroke": "#e8f0f6", + "stroke-width": 1, + "filter": "url(#dropShadow05)" + }, + "#emblems": { + "opacity": 0.9, + "stroke-width": 1, + "filter": null + }, + "#texture": { + "opacity": null, + "filter": null, + "mask": "url(#land)" + }, + "#zones": { + "opacity": 0.6, + "stroke": "#333333", + "stroke-width": 0, + "stroke-dasharray": null, + "stroke-linecap": "butt", + "filter": null, + "mask": null + }, + "#oceanLayers": { + "filter": null, + "layers": "-6,-3,-1" + }, + "#oceanBase": { + "fill": "#466eab" + }, + "#oceanicPattern": { + "href": "./images/pattern1.png", + "opacity": 0.2 + }, + "#terrs": { + "opacity": null, + "scheme": "bright", + "terracing": 0, + "skip": 5, + "relax": 0, + "curve": 0, + "filter": null, + "mask": "url(#land)" + }, + "#legend": { + "data-size": 13, + "font-size": 13, + "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 + }, + "#burgLabels > #cities": { + "opacity": 1, + "fill": "#3e3e4b", + "text-shadow": "white 0px 0px 4px", + "data-size": 7, + "font-size": 7, + "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", + "text-shadow": "white 0px 0px 4px", + "data-size": 4, + "font-size": 4, + "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, + "text-shadow": "white 0px 0px 4px", + "data-size": 22, + "font-size": 22, + "font-family": "Almendra SC", + "filter": null + }, + "#labels > #addedLabels": { + "opacity": 1, + "fill": "#3e3e4b", + "stroke": "#3a3a3a", + "stroke-width": 0, + "text-shadow": "white 0px 0px 4px", + "data-size": 18, + "font-size": 18, + "font-family": "Almendra SC", + "filter": null + }, + "#fogging": { + "opacity": 0.98, + "fill": "#30426f", + "filter": null + } +} diff --git a/styles/gloom.json b/styles/gloom.json new file mode 100644 index 00000000..528d5764 --- /dev/null +++ b/styles/gloom.json @@ -0,0 +1,391 @@ +{ + "#map": { + "background-color": "#000000", + "filter": null, + "data-filter": null + }, + "#armies": { + "font-size": 6, + "box-size": 3, + "stroke": "#000", + "stroke-width": 0.3, + "opacity": 1, + "fill-opacity": 1, + "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": null + }, + "#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, + "scale": 1, + "dx": 0, + "dy": "0", + "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": null, + "mask": null + }, + "#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)" + }, + "#dry": { + "opacity": 0.7, + "fill": "#c9bfa7", + "stroke": "#8e816f", + "stroke-width": 0.7, + "filter": null + }, + "#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": null, + "fill": "#779582" + }, + "#ruler": { + "opacity": null, + "filter": null + }, + "#roads": { + "opacity": 1, + "stroke": "#8b4418", + "stroke-width": 0.9, + "stroke-dasharray": "2 3", + "stroke-linecap": "round", + "filter": null, + "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 + }, + "#statesBody": { + "opacity": 0.4, + "filter": null + }, + "#statesHalo": { + "opacity": 0.5, + "data-width": 12, + "stroke-width": 12, + "filter": "blur(10px)" + }, + "#provs": { + "opacity": 0.7, + "fill": "#000000", + "data-size": 10, + "font-size": 10, + "font-family": "Georgia", + "filter": null + }, + "#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 + }, + "#ice": { + "opacity": 0.9, + "fill": "#e8f0f6", + "stroke": "#e8f0f6", + "stroke-width": 1, + "filter": "url(#dropShadow05)" + }, + "#emblems": { + "opacity": 0.6, + "stroke-width": 0.5, + "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 + }, + "#oceanLayers": { + "filter": null, + "layers": "-6,-4,-2" + }, + "#oceanBase": { + "fill": "#4e6964" + }, + "#oceanicPattern": { + "href": "./images/pattern3.png", + "opacity": 0.2 + }, + "#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, + "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", + "text-shadow": "white 0 0 4px", + "data-size": 7, + "font-size": 7, + "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, + "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, + "text-shadow": "white 0 0 4px", + "data-size": 22, + "font-size": 22, + "font-family": "Almendra SC", + "filter": null + }, + "#labels > #addedLabels": { + "opacity": 1, + "fill": "#3e3e4b", + "stroke": "#3a3a3a", + "stroke-width": 0, + "text-shadow": "white 0 0 4px", + "data-size": 18, + "font-size": 18, + "font-family": "Almendra SC", + "filter": null + }, + "#fogging": { + "opacity": 0.98, + "fill": "#1b1423", + "filter": null + } +} diff --git a/styles/light.json b/styles/light.json new file mode 100644 index 00000000..5663d6c8 --- /dev/null +++ b/styles/light.json @@ -0,0 +1,385 @@ +{ + "#map": { + "background-color": "#000000", + "filter": null, + "data-filter": null + }, + "#armies": { + "font-size": 8, + "box-size": 4, + "stroke": "#000", + "stroke-width": 0.02, + "fill-opacity": 0.8, + "filter": null + }, + "#biomes": { + "opacity": 0.5, + "filter": null, + "mask": "url(#land)" + }, + "#stateBorders": { + "opacity": 0.8, + "stroke": "#4c483e", + "stroke-width": 1, + "stroke-dasharray": 2, + "stroke-linecap": "square", + "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.5, + "scale": 1, + "dx": 0, + "dy": 0, + "type": "pointyHex", + "stroke": "#808080", + "stroke-width": 1, + "stroke-dasharray": null, + "stroke-linecap": null, + "transform": null, + "filter": null, + "mask": null + }, + "#coordinates": { + "opacity": 0.7, + "data-size": 15, + "font-size": 15, + "stroke": "#734d37", + "stroke-width": 1.5, + "stroke-dasharray": 5, + "stroke-linecap": "square", + "filter": null, + "mask": "" + }, + "#compass": { + "opacity": 0.6, + "transform": null, + "filter": null, + "mask": "url(#water)", + "shape-rendering": "optimizespeed" + }, + "#rose": { + "transform": null + }, + "#relig": { + "opacity": 0.5, + "stroke": null, + "stroke-width": 0, + "filter": null + }, + "#cults": { + "opacity": 0.5, + "stroke": "#777777", + "stroke-width": 0, + "stroke-dasharray": null, + "stroke-linecap": null, + "filter": null + }, + "#landmass": { + "opacity": 1, + "fill": "#f9f2ea", + "filter": null + }, + "#markers": { + "opacity": null, + "rescale": 1, + "filter": null + }, + "#prec": { + "opacity": null, + "stroke": "#000000", + "stroke-width": 0.1, + "fill": "#2554ef", + "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": "#98cdc4", + "stroke": "#719892", + "stroke-width": 0.46, + "filter": "url(#dropShadow05)" + }, + "#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)" + }, + "#dry": { + "opacity": 1, + "fill": "#c9bfa7", + "stroke": "#8e816f", + "stroke-width": 0.7, + "filter": null + }, + "#sea_island": { + "opacity": 1, + "stroke": "#5e5e5e", + "stroke-width": 0.4, + "filter": "url(#dropShadow)", + "auto-filter": 1 + }, + "#lake_island": { + "opacity": 1, + "stroke": "#7c8eaf", + "stroke-width": 0.35, + "filter": null + }, + "#terrain": { + "opacity": 0.6, + "set": "colored", + "size": 1, + "density": 0.3, + "filter": null, + "mask": "" + }, + "#rivers": { + "opacity": null, + "filter": null, + "fill": "#6d94ba" + }, + "#ruler": { + "opacity": null, + "filter": null + }, + "#roads": { + "opacity": 0.9, + "stroke": "#3c1d0b", + "stroke-width": 1.37, + "stroke-dasharray": 2, + "stroke-linecap": "inherit", + "filter": null, + "mask": null + }, + "#trails": { + "opacity": 0.9, + "stroke": "#95481a", + "stroke-width": 0.88, + "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 + }, + "#statesBody": { + "opacity": 0.2, + "filter": null + }, + "#statesHalo": { + "opacity": 0.3, + "data-width": 25, + "stroke-width": 25, + "filter": "blur(5px)" + }, + "#provs": { + "opacity": 0.4, + "fill": "#000000", + "font-size": 5, + "font-family": "IM Fell English", + "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 + }, + "#ice": { + "opacity": 0.5, + "fill": "#e8f0f6", + "stroke": "#e8f0f6", + "stroke-width": 1.5, + "filter": "url(#dropShadow05)" + }, + "#emblems": { + "opacity": 0.9, + "stroke-width": 1, + "filter": null + }, + "#texture": { + "opacity": 0.39, + "filter": null, + "mask": "" + }, + "#zones": { + "opacity": 0.6, + "stroke": "#333333", + "stroke-width": 0, + "stroke-dasharray": null, + "stroke-linecap": "butt", + "filter": null, + "mask": null + }, + "#oceanLayers": { + "filter": "url(#dropShadow05)", + "layers": "-6,-3,-1" + }, + "#oceanBase": { + "fill": "#8dc1c8" + }, + "#oceanicPattern": { + "href": "./images/pattern1.png", + "opacity": 0.2 + }, + "#terrs": { + "opacity": 0.4, + "scheme": "light", + "terracing": 10, + "skip": 5, + "relax": 0, + "curve": 0, + "filter": "url(#turbulence)", + "mask": "url(#land)" + }, + "#legend": { + "data-size": 13, + "font-size": 13, + "font-family": "Almendra SC", + "stroke": "#812929", + "stroke-width": 2.5, + "stroke-dasharray": "0 4 10 4", + "stroke-linecap": "round", + "data-x": 54.73, + "data-y": 62.98, + "data-columns": 8 + }, + "#burgLabels > #cities": { + "opacity": 1, + "fill": "#3a3a3a", + "text-shadow": "white 0px 0px 4px", + "data-size": 8, + "font-size": 8, + "font-family": "IM Fell English" + }, + "#burgIcons > #cities": { + "opacity": 1, + "fill": "#ffffff", + "fill-opacity": 0.7, + "size": 3, + "stroke": "#3e3e4b", + "stroke-width": 0.4, + "stroke-dasharray": "0.5 0.25", + "stroke-linecap": "butt" + }, + "#anchors > #cities": { + "opacity": 1, + "fill": "#ffffff", + "size": 5.5, + "stroke": "#3e3e4b", + "stroke-width": 1.2 + }, + "#burgLabels > #towns": { + "opacity": 1, + "fill": "#3e3e4b", + "text-shadow": "white 0px 0px 4px", + "data-size": 4, + "font-size": 4, + "font-family": "IM Fell English" + }, + "#burgIcons > #towns": { + "opacity": 1, + "fill": "#ffffff", + "fill-opacity": 0.7, + "size": 1.2, + "stroke": "#3e3e4b", + "stroke-width": 0.2, + "stroke-dasharray": "", + "stroke-linecap": "butt" + }, + "#anchors > #towns": { + "opacity": 1, + "fill": "#ffffff", + "size": 2.2, + "stroke": "#3e3e4b", + "stroke-width": 1.2 + }, + "#labels > #states": { + "opacity": 1, + "fill": "#3e3e3e", + "stroke": "#000000", + "stroke-width": 0.3, + "text-shadow": "white 0px 0px 6px", + "data-size": 14, + "font-size": 14, + "font-family": "IM Fell English", + "filter": null + }, + "#labels > #addedLabels": { + "opacity": 1, + "fill": "#f24706", + "stroke": "#701b05", + "stroke-width": 0.1, + "text-shadow": "white 0px 0px 4px", + "data-size": 6, + "font-size": 6, + "font-family": "IM Fell English", + "filter": null + }, + "#fogging": { + "opacity": 1, + "fill": "#30426f", + "filter": null + } +} diff --git a/styles/monochrome.json b/styles/monochrome.json new file mode 100644 index 00000000..4d3ed9a4 --- /dev/null +++ b/styles/monochrome.json @@ -0,0 +1,381 @@ +{ + "#map": { + "background-color": "#000000", + "filter": "url(#filter-grayscale)", + "data-filter": "grayscale" + }, + "#armies": { + "font-size": 6, + "box-size": 3, + "stroke": "#000", + "stroke-width": 0.3, + "opacity": 1, + "fill-opacity": 1, + "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": 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, + "scale": 1, + "dx": 0, + "dy": "0", + "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": null + }, + "#sea_island": { + "opacity": 1, + "stroke": "#1f3846", + "stroke-width": 0, + "filter": null, + "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 + }, + "#statesBody": { + "opacity": 0.4, + "filter": null + }, + "#statesHalo": { + "opacity": 0.4, + "data-width": 10, + "stroke-width": 10, + "filter": "blur(5px)" + }, + "#provs": { + "opacity": 0.7, + "fill": "#000000", + "data-size": 10, + "font-size": 10, + "font-family": "Georgia", + "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 + }, + "#ice": { + "opacity": 0.9, + "fill": "#e8f0f6", + "stroke": "#e8f0f6", + "stroke-width": 1, + "filter": "url(#dropShadow05)" + }, + "#texture": { + "opacity": 1, + "filter": null, + "mask": "url(#land)" + }, + "#emblems": { + "opacity": 0.5, + "stroke-width": 0.5, + "filter": null + }, + "#textureImage": {}, + "#zones": { + "opacity": 0.6, + "stroke": "#333333", + "stroke-width": 0, + "stroke-dasharray": null, + "stroke-linecap": "butt", + "filter": null, + "mask": null + }, + "#oceanLayers": { + "filter": null, + "layers": "none" + }, + "#oceanBase": { + "fill": "#000000" + }, + "#oceanicPattern": { + "href": "", + "opacity": 0.2 + }, + "#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, + "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", + "text-shadow": "white 0 0 4px", + "data-size": 7, + "font-size": 7, + "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, + "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, + "text-shadow": "white 0 0 4px", + "data-size": 22, + "font-size": 22, + "font-family": "Almendra SC", + "filter": null + }, + "#labels > #addedLabels": { + "opacity": 1, + "fill": "#3e3e4b", + "stroke": "#3a3a3a", + "stroke-width": 0, + "text-shadow": "white 0 0 4px", + "data-size": 18, + "font-size": 18, + "font-family": "Almendra SC", + "filter": null + }, + "#fogging": { + "opacity": 0.98, + "fill": "#30426f", + "filter": null + } +} diff --git a/styles/watercolor.json b/styles/watercolor.json new file mode 100644 index 00000000..3e890876 --- /dev/null +++ b/styles/watercolor.json @@ -0,0 +1,385 @@ +{ + "#map": { + "background-color": "#000000", + "filter": null, + "data-filter": null + }, + "#armies": { + "font-size": 8, + "box-size": 4, + "stroke": "#000", + "stroke-width": 0.2, + "fill-opacity": 1, + "filter": null + }, + "#biomes": { + "opacity": 0.6, + "filter": null, + "mask": "url(#land)" + }, + "#stateBorders": { + "opacity": 0.6, + "stroke": "#56566d", + "stroke-width": 1, + "stroke-dasharray": 3, + "stroke-linecap": "butt", + "filter": null + }, + "#provinceBorders": { + "opacity": 0.5, + "stroke": "#56566d", + "stroke-width": 0.5, + "stroke-dasharray": "0 2", + "stroke-linecap": "round", + "filter": null + }, + "#cells": { + "opacity": null, + "stroke": "#808080", + "stroke-width": 0.1, + "filter": null, + "mask": null + }, + "#gridOverlay": { + "opacity": 0.8, + "scale": 1, + "dx": 0, + "dy": 0, + "type": "pointyHex", + "stroke": "#777777", + "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": "#777777", + "stroke-width": 0, + "filter": "url(#bluredSplotch)" + }, + "#cults": { + "opacity": 0.6, + "stroke": "#777777", + "stroke-width": 0.5, + "stroke-dasharray": null, + "stroke-linecap": null, + "filter": "url(#splotch)" + }, + "#landmass": { + "opacity": 1, + "fill": "#eef6fb", + "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)" + }, + "#dry": { + "opacity": 1, + "fill": "#c9bfa7", + "stroke": "#8e816f", + "stroke-width": 0.7, + "filter": null + }, + "#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": 1, + "set": "gray", + "size": 1, + "density": 0.4, + "filter": null, + "mask": null + }, + "#rivers": { + "opacity": null, + "filter": null, + "fill": "#2e89c2" + }, + "#ruler": { + "opacity": null, + "filter": null + }, + "#roads": { + "opacity": 0.9, + "stroke": "#969696", + "stroke-width": 0.7, + "stroke-dasharray": "", + "stroke-linecap": "butt", + "filter": null, + "mask": null + }, + "#trails": { + "opacity": 0.9, + "stroke": "#969696", + "stroke-width": 0.4, + "stroke-dasharray": "", + "stroke-linecap": "butt", + "filter": null, + "mask": null + }, + "#searoutes": { + "opacity": 0.9, + "stroke": "#969696", + "stroke-width": 0.7, + "stroke-dasharray": "", + "stroke-linecap": "round", + "filter": null, + "mask": null + }, + "#statesBody": { + "opacity": 0.05, + "filter": null + }, + "#statesHalo": { + "opacity": 0.4, + "data-width": 8, + "stroke-width": 8, + "filter": "blur(2px)" + }, + "#provs": { + "opacity": 0.7, + "fill": "#000000", + "font-size": 4, + "font-family": "Comfortaa", + "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 + }, + "#ice": { + "opacity": 0.7, + "fill": "#dfe8ec", + "stroke": "#000000", + "stroke-width": 0, + "filter": "url(#dropShadow05)" + }, + "#emblems": { + "opacity": 0.95, + "stroke-width": 1, + "filter": null + }, + "#texture": { + "opacity": 0.2, + "filter": null, + "mask": "url(#land)" + }, + "#zones": { + "opacity": 0.6, + "stroke": "#333333", + "stroke-width": 0, + "stroke-dasharray": null, + "stroke-linecap": "butt", + "filter": null, + "mask": null + }, + "#oceanLayers": { + "filter": null, + "layers": "-6,-4,-2" + }, + "#oceanBase": { + "fill": "#2d788b" + }, + "#oceanicPattern": { + "href": "./images/kiwiroo.png", + "opacity": 0.5 + }, + "#terrs": { + "opacity": 0.5, + "scheme": "light", + "terracing": 0, + "skip": 5, + "relax": 1, + "curve": 0, + "filter": null, + "mask": "url(#land)" + }, + "#legend": { + "data-size": 13, + "font-size": 13, + "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 + }, + "#burgLabels > #cities": { + "opacity": 1, + "fill": "#043449", + "text-shadow": "white 0px 0px 2px", + "data-size": 5, + "font-size": 5, + "font-family": "Comfortaa" + }, + "#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", + "text-shadow": "white 0px 0px 4px", + "data-size": 3, + "font-size": 3, + "font-family": "Comfortaa" + }, + "#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": "#ffffff", + "stroke": "#000000", + "stroke-width": 0.15, + "text-shadow": "black 1px 1px 2px", + "data-size": 20, + "font-size": 20, + "font-family": "Gloria Hallelujah", + "filter": null + }, + "#labels > #addedLabels": { + "opacity": 1, + "fill": "#3e3e4b", + "stroke": "#3a3a3a", + "stroke-width": 0, + "text-shadow": "white 0px 0px 4px", + "data-size": 18, + "font-size": 18, + "font-family": "Comfortaa", + "filter": null + }, + "#fogging": { + "opacity": 0.97, + "fill": "#8398ce", + "filter": null + } +} diff --git a/utils/unitUtils.js b/utils/unitUtils.js index 609b5eb9..141fa432 100644 --- a/utils/unitUtils.js +++ b/utils/unitUtils.js @@ -5,7 +5,7 @@ function convertTemperature(temp) { switch (temperatureScale.value) { case "°C": - return temp + "°C"; + return rn(temp) + "°C"; case "°F": return rn((temp * 9) / 5 + 32) + "°F"; case "K": @@ -21,7 +21,7 @@ function convertTemperature(temp) { case "°Rø": return rn((temp * 21) / 40 + 7.5) + "°Rø"; default: - return temp + "°C"; + return rn(temp) + "°C"; } }