diff --git a/README.md b/README.md index 20331678..3ab245b2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ - - # Fantasy Map Generator Azgaar's _Fantasy Map Generator_ is a free web application that helps fantasy writers, game masters, and cartographers create and edit fantasy maps. @@ -8,19 +6,17 @@ Link: [azgaar.github.io/Fantasy-Map-Generator](https://azgaar.github.io/Fantasy- Refer to the [project wiki](https://github.com/Azgaar/Fantasy-Map-Generator/wiki) for guidance. The current progress is tracked in [Trello](https://trello.com/b/7x832DG4/fantasy-map-generator). Some details are covered in my old blog [_Fantasy Maps for fun and glory_](https://azgaar.wordpress.com). -[![preview](https://cdn.discordapp.com/attachments/587406457725779968/594840629213659136/preview1.png)](https://i.redd.it/8bf81ir2cy631.png) +[![preview](https://github.com/Azgaar/Fantasy-Map-Generator/assets/26469650/9502eae9-92e0-4d0d-9f17-a2ba4a565c01)](https://github.com/Azgaar/Fantasy-Map-Generator/assets/26469650/11a42446-4bd5-4526-9cb1-3ef97c868992) -[![preview](https://cdn.discordapp.com/attachments/587406457725779968/594840633911279636/preview2.png)](https://cdn.discordapp.com/attachments/515359185664344071/593888810782162964/The_Wichin_Island_sepia.png) +[![preview](https://github.com/Azgaar/Fantasy-Map-Generator/assets/26469650/e751a9e5-7986-4638-b8a9-362395ef7583)](https://github.com/Azgaar/Fantasy-Map-Generator/assets/26469650/e751a9e5-7986-4638-b8a9-362395ef7583) -[![preview](https://cdn.discordapp.com/attachments/587406457725779968/594840632296734720/preview3.png)](https://cdn.discordapp.com/attachments/515359096925454350/593891237984206848/The_Wichin_Island_-_diplomacy.png) +[![preview](https://github.com/Azgaar/Fantasy-Map-Generator/assets/26469650/b0d0efde-a0d1-4e80-8818-ea3dd83c2323)](https://github.com/Azgaar/Fantasy-Map-Generator/assets/26469650/b0d0efde-a0d1-4e80-8818-ea3dd83c2323) Join our [Discord server](https://discordapp.com/invite/X7E84HU) and [Reddit community](https://www.reddit.com/r/FantasyMapGenerator) to share your creations, discuss the Generator, suggest ideas and get the most recent updates. -Contact me via [email](mailto:azgaar.fmg@yandex.by) if you have non-public suggestions. For bug reports please use [GitHub issues](https://github.com/Azgaar/Fantasy-Map-Generator/issues) or _#bugs_ channel on Discord. If you are facing performance issues, please read [the tips](https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Tips#performance-tips). +Contact me via [email](mailto:azgaar.fmg@yandex.com) if you have non-public suggestions. For bug reports please use [GitHub issues](https://github.com/Azgaar/Fantasy-Map-Generator/issues) or _#fmg-bugs_ channel on Discord. If you are facing performance issues, please read [the tips](https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Tips#performance-tips). -Electron desktop application is available in [releases](https://github.com/Azgaar/Fantasy-Map-Generator/releases). Download archive for your architecture, unzip and run. - -Pull requests are highly welcomed. The codebase is messy and requires re-design, but I will appreciate if you start with minor changes. Check out the [data model](https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Data-model) before contributing. +Pull requests are highly welcomed. The codebase is messy and requires re-design. I will appreciate if you start with minor changes. Check out the [data model](https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Data-model) before contributing. You can support the project on [Patreon](https://www.patreon.com/azgaar). diff --git a/charges/agnusDei.svg b/charges/agnusDei.svg index 9e9fd1e0..60ea9d87 100644 --- a/charges/agnusDei.svg +++ b/charges/agnusDei.svg @@ -1,135 +1,132 @@ - - - - + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/arbalest.svg b/charges/arbalest.svg index 79cf4950..38adac50 100644 --- a/charges/arbalest.svg +++ b/charges/arbalest.svg @@ -1,39 +1,38 @@ - - - + + - - + + - + - + - + - - + + - + - + - + - - - - - - + + + + + + - - + + - + diff --git a/charges/arbalest2.svg b/charges/arbalest2.svg new file mode 100644 index 00000000..be9b1a6a --- /dev/null +++ b/charges/arbalest2.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/archer.svg b/charges/archer.svg new file mode 100644 index 00000000..00891c1b --- /dev/null +++ b/charges/archer.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/armEmbowedHoldingSabre.svg b/charges/armEmbowedHoldingSabre.svg new file mode 100644 index 00000000..2fbae9f6 --- /dev/null +++ b/charges/armEmbowedHoldingSabre.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/armEmbowedVambraced.svg b/charges/armEmbowedVambraced.svg new file mode 100644 index 00000000..ac1422b5 --- /dev/null +++ b/charges/armEmbowedVambraced.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/armEmbowedVambracedHoldingSword.svg b/charges/armEmbowedVambracedHoldingSword.svg new file mode 100644 index 00000000..d00d8bab --- /dev/null +++ b/charges/armEmbowedVambracedHoldingSword.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/armillarySphere.svg b/charges/armillarySphere.svg index c71938a8..45d09b8d 100644 --- a/charges/armillarySphere.svg +++ b/charges/armillarySphere.svg @@ -1,18 +1 @@ - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/charges/arrow.svg b/charges/arrow.svg index dca5f47e..2135169f 100644 --- a/charges/arrow.svg +++ b/charges/arrow.svg @@ -1,10 +1,10 @@ - - - - - - + + + + + + diff --git a/charges/arrowsSheaf.svg b/charges/arrowsSheaf.svg index 47d8b925..4b879e10 100644 --- a/charges/arrowsSheaf.svg +++ b/charges/arrowsSheaf.svg @@ -1,27 +1,27 @@ - - - - - - - + + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - + diff --git a/charges/badgerStatant.svg b/charges/badgerStatant.svg index 02de9b22..29cd5f39 100644 --- a/charges/badgerStatant.svg +++ b/charges/badgerStatant.svg @@ -1,62 +1,62 @@ - + - - + + - - + + - - + + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - - + + diff --git a/charges/banner.svg b/charges/banner.svg index 80ca0f4f..8ca47b97 100644 --- a/charges/banner.svg +++ b/charges/banner.svg @@ -1,35 +1,35 @@ - diff --git a/charges/bee.svg b/charges/bee.svg index db5b48b4..7f3a0069 100644 --- a/charges/bee.svg +++ b/charges/bee.svg @@ -1,116 +1,116 @@ - - + + - - + + - - - + + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - - - + + + + + + + + - + - - + + - + - - + + - - - + + + - - + + - - + + - - + + - - + + - - + + - - + + - + - + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/charges/boarHeadErased.svg b/charges/boarHeadErased.svg index 6c28ab2b..08348586 100644 --- a/charges/boarHeadErased.svg +++ b/charges/boarHeadErased.svg @@ -1,44 +1,44 @@ - - - - - + + + + + - - + + - + - - + + - - + + - + - + - + - + - + - + diff --git a/charges/bone.svg b/charges/bone.svg new file mode 100644 index 00000000..27a9e410 --- /dev/null +++ b/charges/bone.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/charges/bookClosed.svg b/charges/bookClosed.svg index f50006a1..0cd74341 100644 --- a/charges/bookClosed.svg +++ b/charges/bookClosed.svg @@ -1,20 +1,20 @@ - - - - - - + + + + + + - - - - - - - - + + + + + + + + diff --git a/charges/bookClosed2.svg b/charges/bookClosed2.svg new file mode 100644 index 00000000..bf8d2519 --- /dev/null +++ b/charges/bookClosed2.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/bookOpen.svg b/charges/bookOpen.svg index 6a760e51..62f1c6fc 100644 --- a/charges/bookOpen.svg +++ b/charges/bookOpen.svg @@ -1,21 +1,21 @@ - - - - + + + + - - - - - - + + + + + + - - + + diff --git a/charges/bowWithArrow.svg b/charges/bowWithArrow.svg index ad2e4502..12d7f9ff 100644 --- a/charges/bowWithArrow.svg +++ b/charges/bowWithArrow.svg @@ -1,15 +1,15 @@ - - + + - - - - - - + + + + + + diff --git a/charges/bowWithThreeArrows.svg b/charges/bowWithThreeArrows.svg new file mode 100644 index 00000000..0efc30f2 --- /dev/null +++ b/charges/bowWithThreeArrows.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/bridge.svg b/charges/bridge.svg index 41261f98..f5ce588e 100644 --- a/charges/bridge.svg +++ b/charges/bridge.svg @@ -1,92 +1,92 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/bridge2.svg b/charges/bridge2.svg new file mode 100644 index 00000000..6d3dfab5 --- /dev/null +++ b/charges/bridge2.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/bucket.svg b/charges/bucket.svg index 399aa92c..56c7e83c 100644 --- a/charges/bucket.svg +++ b/charges/bucket.svg @@ -1,20 +1 @@ - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/charges/bullPassant.svg b/charges/bullPassant.svg index 24143bb3..0314b64e 100644 --- a/charges/bullPassant.svg +++ b/charges/bullPassant.svg @@ -1,21 +1,21 @@ - - - - - - - - - + + + + + + + + + - - - - - + + + + + - + diff --git a/charges/butterfly.svg b/charges/butterfly.svg index e956195c..2c301fcf 100644 --- a/charges/butterfly.svg +++ b/charges/butterfly.svg @@ -1,64 +1,64 @@ - + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + - + - + - + - + - - + + - - - + + + diff --git a/charges/cannon.svg b/charges/cannon.svg index a110c596..05e88b25 100644 --- a/charges/cannon.svg +++ b/charges/cannon.svg @@ -1,67 +1,67 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/caravel.svg b/charges/caravel.svg index 39f8fd86..9eb57671 100644 --- a/charges/caravel.svg +++ b/charges/caravel.svg @@ -1,70 +1,70 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - + diff --git a/charges/castle2.svg b/charges/castle2.svg new file mode 100644 index 00000000..5f12a8aa --- /dev/null +++ b/charges/castle2.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/catPassantGuardant.svg b/charges/catPassantGuardant.svg index 5a556e4e..b49dc820 100644 --- a/charges/catPassantGuardant.svg +++ b/charges/catPassantGuardant.svg @@ -1,66 +1,66 @@ - + - - - - - + + + + + - - + + - - - + + + - + - - + + - - - - + + + + - + - + - - + + - + - - + + - - - + + + - + - + - + - + - + - + - + diff --git a/charges/cavalier.svg b/charges/cavalier.svg index 8e9d9b43..7bfad7ac 100644 --- a/charges/cavalier.svg +++ b/charges/cavalier.svg @@ -1,8 +1,75 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/centaur.svg b/charges/centaur.svg new file mode 100644 index 00000000..f4ddeb22 --- /dev/null +++ b/charges/centaur.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/chain.svg b/charges/chain.svg index 4fea5d56..cfe4a3bb 100644 --- a/charges/chain.svg +++ b/charges/chain.svg @@ -1,10 +1,10 @@ - - - - - - - + + + + + + + - \ No newline at end of file + diff --git a/charges/chalice.svg b/charges/chalice.svg index 2a8f7845..0f4f95f6 100644 --- a/charges/chalice.svg +++ b/charges/chalice.svg @@ -1,13 +1,13 @@ - - - - + + + + - - + + - + diff --git a/charges/cinquefoil.svg b/charges/cinquefoil.svg index 3e957d99..49db293e 100644 --- a/charges/cinquefoil.svg +++ b/charges/cinquefoil.svg @@ -1,14 +1,14 @@ - + - + - - - - - + + + + + diff --git a/charges/column.svg b/charges/column.svg index 80067505..38d8b2a0 100644 --- a/charges/column.svg +++ b/charges/column.svg @@ -1,17 +1,17 @@ - + - - - - - + + + + + - - - - - + + + + + diff --git a/charges/comet.svg b/charges/comet.svg new file mode 100644 index 00000000..096ddb67 --- /dev/null +++ b/charges/comet.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/charges/cossack.svg b/charges/cossack.svg new file mode 100644 index 00000000..f5cf75ed --- /dev/null +++ b/charges/cossack.svg @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/cowStatant.svg b/charges/cowStatant.svg index f28e58e0..66b46823 100644 --- a/charges/cowStatant.svg +++ b/charges/cowStatant.svg @@ -1,43 +1,43 @@ - - - - - - + + + + + + - + - - + + - + - - + + - + - + - + - - + + - + - + - + - + diff --git a/charges/crocodile.svg b/charges/crocodile.svg index b44032f7..442e456d 100644 --- a/charges/crocodile.svg +++ b/charges/crocodile.svg @@ -1,65 +1,65 @@ - + - - + + - + - + - - + + - + - + - - + + - + - + - + - + - - + + - + - + - - + + - + - + - + - + - + - + - + - + diff --git a/charges/crosier.svg b/charges/crosier.svg index 5eb26576..631ef998 100644 --- a/charges/crosier.svg +++ b/charges/crosier.svg @@ -1,16 +1 @@ - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/charges/crossCalvary.svg b/charges/crossCalvary.svg index 493579f9..dd0447b5 100644 --- a/charges/crossCalvary.svg +++ b/charges/crossCalvary.svg @@ -1,6 +1 @@ - - - - - - + \ No newline at end of file diff --git a/charges/crossDouble.svg b/charges/crossDouble.svg index 2176c0e3..1a0e4bc8 100644 --- a/charges/crossDouble.svg +++ b/charges/crossDouble.svg @@ -1,6 +1 @@ - - - - - - + \ No newline at end of file diff --git a/charges/crossSantiago.svg b/charges/crossSantiago.svg index d6b30109..7e510a90 100644 --- a/charges/crossSantiago.svg +++ b/charges/crossSantiago.svg @@ -1,6 +1 @@ - - - - - - + \ No newline at end of file diff --git a/charges/crossedBones.svg b/charges/crossedBones.svg new file mode 100644 index 00000000..3b06442f --- /dev/null +++ b/charges/crossedBones.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/charges/crosslet.svg b/charges/crosslet.svg index 3dc8b517..645b68a3 100644 --- a/charges/crosslet.svg +++ b/charges/crosslet.svg @@ -1,6 +1 @@ - - - - - - + \ No newline at end of file diff --git a/charges/crown2.svg b/charges/crown2.svg index 4be76b88..f06a106e 100644 --- a/charges/crown2.svg +++ b/charges/crown2.svg @@ -1,72 +1,69 @@ - - - + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - + - - + + - - - - + + + - - - - - - + + + + + + - - + + - - + + - + - - + + - - - - + + + + diff --git a/charges/dolphin.svg b/charges/dolphin.svg index fdc49f07..be5b00bd 100644 --- a/charges/dolphin.svg +++ b/charges/dolphin.svg @@ -21,40 +21,40 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/donkeyHeadCaboshed.svg b/charges/donkeyHeadCaboshed.svg index c9533d82..da5aee0a 100644 --- a/charges/donkeyHeadCaboshed.svg +++ b/charges/donkeyHeadCaboshed.svg @@ -1,39 +1,37 @@ - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - + - + + - - - - + + + + + + + + + + + + + + + + + + diff --git a/charges/dove.svg b/charges/dove.svg index 860ff7f5..7406a6ec 100644 --- a/charges/dove.svg +++ b/charges/dove.svg @@ -1,67 +1,67 @@ - + - - + + - - + + - + - + - - + + - - + + - + - + - - + + - - - - + + + + - + - + - - + + - + - - - + + + - + - + - + - - + + - + diff --git a/charges/doveDisplayed.svg b/charges/doveDisplayed.svg index d3a24ea1..35bd14d6 100644 --- a/charges/doveDisplayed.svg +++ b/charges/doveDisplayed.svg @@ -1,110 +1,110 @@ - + - - + + - + - - + + - + - + - - - - - + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - + - - - - - - - + + + + + + + - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - + - - - - - - - + + + + + + + - + - + - - + + - + - + - + - + - + diff --git a/charges/dragonRampant.svg b/charges/dragonRampant.svg index 016d4711..6ff64c2a 100644 --- a/charges/dragonRampant.svg +++ b/charges/dragonRampant.svg @@ -1,61 +1,61 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/dragonfly.svg b/charges/dragonfly.svg new file mode 100644 index 00000000..c8b501ca --- /dev/null +++ b/charges/dragonfly.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/charges/drakkar.svg b/charges/drakkar.svg new file mode 100644 index 00000000..f36c3c4d --- /dev/null +++ b/charges/drakkar.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/drawingCompass.svg b/charges/drawingCompass.svg new file mode 100644 index 00000000..65a252d3 --- /dev/null +++ b/charges/drawingCompass.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/charges/drum.svg b/charges/drum.svg index d80386d4..bd8fd638 100644 --- a/charges/drum.svg +++ b/charges/drum.svg @@ -1,18 +1,18 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/charges/duck.svg b/charges/duck.svg index 440b93fd..940c3e4d 100644 --- a/charges/duck.svg +++ b/charges/duck.svg @@ -1,85 +1,85 @@ - + - + - + - + - + - + - - + + - + - - - + + + - + - + - + - + - + - + - - + + - + - + - + - - + + - + - + - - + + - + - - + + - + - - + + - + - + - + - + diff --git a/charges/eagleTwoHeads.svg b/charges/eagleTwoHeads.svg index d556d380..cc8ac124 100644 --- a/charges/eagleTwoHeads.svg +++ b/charges/eagleTwoHeads.svg @@ -18,86 +18,86 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/earOfWheat.svg b/charges/earOfWheat.svg new file mode 100644 index 00000000..a1b3072c --- /dev/null +++ b/charges/earOfWheat.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/elephantHeadErased.svg b/charges/elephantHeadErased.svg index cb7acccc..f521413b 100644 --- a/charges/elephantHeadErased.svg +++ b/charges/elephantHeadErased.svg @@ -1,22 +1,22 @@ - - + + - + - - + + - + - - + + - - + + diff --git a/charges/escallop.svg b/charges/escallop.svg index d5803037..4fda9dda 100644 --- a/charges/escallop.svg +++ b/charges/escallop.svg @@ -3,17 +3,17 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/charges/falchion.svg b/charges/falchion.svg index dc28b164..ccb71d3d 100644 --- a/charges/falchion.svg +++ b/charges/falchion.svg @@ -1,10 +1,10 @@ - - - - - - - + + + + + + + diff --git a/charges/falcon.svg b/charges/falcon.svg index 66d15b9d..5e4cebd5 100644 --- a/charges/falcon.svg +++ b/charges/falcon.svg @@ -1,221 +1,221 @@ - + - - - - - - - + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - + - - - - - - - - + + + + + + + + - + - - + + - - - + + + - - + + - - - + + + - + - + - + - - - + + + - - - - - + + + + + - + - - + + - - - - - - - - - - - + + + + + + + + + + + - + - - - - - - - - + + + + + + + + - - + + - - + + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - + + + + - + - + - - - - - + + + + + - - - + + + - + - - - - - - - - - + + + + + + + + + - - + + - - - - - + + + + + - - + + - - - + + + - - + + - - + + - - + + - - - + + + - - - - - - - - - - - + + + + + + + + + + + diff --git a/charges/fan.svg b/charges/fan.svg new file mode 100644 index 00000000..d7504ac6 --- /dev/null +++ b/charges/fan.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/charges/feather.svg b/charges/feather.svg new file mode 100644 index 00000000..0be55bf5 --- /dev/null +++ b/charges/feather.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/charges/flamberge.svg b/charges/flamberge.svg new file mode 100644 index 00000000..ab9d2277 --- /dev/null +++ b/charges/flamberge.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/charges/flangedMace.svg b/charges/flangedMace.svg new file mode 100644 index 00000000..901d942f --- /dev/null +++ b/charges/flangedMace.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/fly.svg b/charges/fly.svg index 08c07a8c..9c880f72 100644 --- a/charges/fly.svg +++ b/charges/fly.svg @@ -1,61 +1,61 @@ - + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - + + + - - - - - - - + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/charges/foot.svg b/charges/foot.svg index dc354c02..22963e5b 100644 --- a/charges/foot.svg +++ b/charges/foot.svg @@ -1,14 +1,14 @@ - - - - - - + + + + + + - - - + + + diff --git a/charges/frog.svg b/charges/frog.svg index 6f6f2c1f..392d3d05 100644 --- a/charges/frog.svg +++ b/charges/frog.svg @@ -1,24 +1,24 @@ - + - + - + - + - - + + - + - - + + - + diff --git a/charges/garb.svg b/charges/garb.svg index 3bd53140..fbefacd8 100644 --- a/charges/garb.svg +++ b/charges/garb.svg @@ -1,150 +1,150 @@ - - + + - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - + + + + + + + + - - - - + + + + - - - + + + diff --git a/charges/gauntlet.svg b/charges/gauntlet.svg index 5bbd9e55..f00a03eb 100644 --- a/charges/gauntlet.svg +++ b/charges/gauntlet.svg @@ -1,54 +1,54 @@ - - - + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - + + diff --git a/charges/gear.svg b/charges/gear.svg new file mode 100644 index 00000000..2d128dfb --- /dev/null +++ b/charges/gear.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/charges/grapeBunch.svg b/charges/grapeBunch.svg index d25c92b8..38d4693f 100644 --- a/charges/grapeBunch.svg +++ b/charges/grapeBunch.svg @@ -1,52 +1,73 @@ - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/grapeBunch2.svg b/charges/grapeBunch2.svg new file mode 100644 index 00000000..0af7b6a6 --- /dev/null +++ b/charges/grapeBunch2.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/grenade.svg b/charges/grenade.svg new file mode 100644 index 00000000..07436784 --- /dev/null +++ b/charges/grenade.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/greyhoundCourant.svg b/charges/greyhoundCourant.svg index 75f0476f..916d70cf 100644 --- a/charges/greyhoundCourant.svg +++ b/charges/greyhoundCourant.svg @@ -1,31 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/charges/greyhoundRampant.svg b/charges/greyhoundRampant.svg index 73ae1448..cf607df5 100644 --- a/charges/greyhoundRampant.svg +++ b/charges/greyhoundRampant.svg @@ -1,89 +1,89 @@ - - - - - - + + + + + + - - - + + + - + - + - + - + - + - + - - - + + + - + - + - + - - + + - + - + - + - - + + - - - + + + - + - - - + + + - + - + - + - + - + - + diff --git a/charges/griffinPassant.svg b/charges/griffinPassant.svg index 4ff9c011..871b3591 100644 --- a/charges/griffinPassant.svg +++ b/charges/griffinPassant.svg @@ -19,36 +19,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/griffinRampant.svg b/charges/griffinRampant.svg index c17552c3..da2cfebe 100644 --- a/charges/griffinRampant.svg +++ b/charges/griffinRampant.svg @@ -29,87 +29,87 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/hand.svg b/charges/hand.svg index 4da98b9a..91c279ae 100644 --- a/charges/hand.svg +++ b/charges/hand.svg @@ -2,11 +2,11 @@ - - - - - + + + + + diff --git a/charges/harp.svg b/charges/harp.svg index 6047a0b5..91e5ee08 100644 --- a/charges/harp.svg +++ b/charges/harp.svg @@ -1,30 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/charges/head.svg b/charges/head.svg index a7f6198d..08e36060 100644 --- a/charges/head.svg +++ b/charges/head.svg @@ -1,16 +1 @@ - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/charges/hedgehog.svg b/charges/hedgehog.svg index d591cc02..c7a84caa 100644 --- a/charges/hedgehog.svg +++ b/charges/hedgehog.svg @@ -1,52 +1,52 @@ - + - - + + - + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - + - + - + - + diff --git a/charges/helmetCorinthian.svg b/charges/helmetCorinthian.svg new file mode 100644 index 00000000..3ccd9cdd --- /dev/null +++ b/charges/helmetCorinthian.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/helmetGreat.svg b/charges/helmetGreat.svg new file mode 100644 index 00000000..b7a7bf49 --- /dev/null +++ b/charges/helmetGreat.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/helmetZischagge.svg b/charges/helmetZischagge.svg new file mode 100644 index 00000000..8985d197 --- /dev/null +++ b/charges/helmetZischagge.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/heron.svg b/charges/heron.svg index 86d121b0..4893b082 100644 --- a/charges/heron.svg +++ b/charges/heron.svg @@ -15,14 +15,14 @@ - - - - - - - - + + + + + + + + diff --git a/charges/hindStatant.svg b/charges/hindStatant.svg index 0c2aae31..3f9cc429 100644 --- a/charges/hindStatant.svg +++ b/charges/hindStatant.svg @@ -1,35 +1,35 @@ - - - + + + - + - - - - - + + + + + - + - + - - + + - + - - + + - + diff --git a/charges/hook.svg b/charges/hook.svg new file mode 100644 index 00000000..d5679f64 --- /dev/null +++ b/charges/hook.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/charges/horseHeadCouped.svg b/charges/horseHeadCouped.svg index 712a273d..8c455c23 100644 --- a/charges/horseHeadCouped.svg +++ b/charges/horseHeadCouped.svg @@ -1,32 +1,32 @@ - - - + + + - - + + - + - + - + - - - - - + + + + + - + - + - + - - + + diff --git a/charges/horsePassant.svg b/charges/horsePassant.svg index f4d2de5b..b2361b84 100644 --- a/charges/horsePassant.svg +++ b/charges/horsePassant.svg @@ -1,119 +1,120 @@ - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/horseRampant.svg b/charges/horseRampant.svg index d2f2544a..be7fee6c 100644 --- a/charges/horseRampant.svg +++ b/charges/horseRampant.svg @@ -14,13 +14,13 @@ - - - - - - - + + + + + + + diff --git a/charges/horseSalient.svg b/charges/horseSalient.svg index 65bd744f..21b5db48 100644 --- a/charges/horseSalient.svg +++ b/charges/horseSalient.svg @@ -1,24 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/charges/hourglass.svg b/charges/hourglass.svg new file mode 100644 index 00000000..87e7930b --- /dev/null +++ b/charges/hourglass.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/key.svg b/charges/key.svg index fb677cd6..6fb883ea 100644 --- a/charges/key.svg +++ b/charges/key.svg @@ -1,16 +1,16 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/charges/ladder.svg b/charges/ladder.svg index b15d2f4a..fc72f130 100644 --- a/charges/ladder.svg +++ b/charges/ladder.svg @@ -1,12 +1,12 @@ - + - - - + + + - - + + diff --git a/charges/ladder2.svg b/charges/ladder2.svg new file mode 100644 index 00000000..5596e045 --- /dev/null +++ b/charges/ladder2.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/charges/ladybird.svg b/charges/ladybird.svg new file mode 100644 index 00000000..3cc1587e --- /dev/null +++ b/charges/ladybird.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/lamb.svg b/charges/lamb.svg index 8d4e161a..1d574b53 100644 --- a/charges/lamb.svg +++ b/charges/lamb.svg @@ -9,10 +9,10 @@ - - - - + + + + diff --git a/charges/lambPassantReguardant.svg b/charges/lambPassantReguardant.svg index b348c41d..90884eb7 100644 --- a/charges/lambPassantReguardant.svg +++ b/charges/lambPassantReguardant.svg @@ -1,119 +1,118 @@ - - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/lanceHead.svg b/charges/lanceHead.svg new file mode 100644 index 00000000..255492db --- /dev/null +++ b/charges/lanceHead.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/charges/lanceWithBanner.svg b/charges/lanceWithBanner.svg new file mode 100644 index 00000000..556e5ade --- /dev/null +++ b/charges/lanceWithBanner.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/charges/laurelWreath.svg b/charges/laurelWreath.svg index 74162f57..989e00c4 100644 --- a/charges/laurelWreath.svg +++ b/charges/laurelWreath.svg @@ -1,262 +1,262 @@ - + - - + + - + - - + + - + - + - + - - - + + + - + - + - + - + - + - + - + - - - + + + - + - + - + - + - + - + - + - + - - - - + + + + - + - + - + - + - + - + - + - + - + - - - + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - + + + + - + - + - + - + - + - + - + - + - + - - - + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - + + + - + diff --git a/charges/laurelWreath2.svg b/charges/laurelWreath2.svg new file mode 100644 index 00000000..6dfb373e --- /dev/null +++ b/charges/laurelWreath2.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/lighthouse.svg b/charges/lighthouse.svg new file mode 100644 index 00000000..b66938f5 --- /dev/null +++ b/charges/lighthouse.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/charges/lionHeadErased.svg b/charges/lionHeadErased.svg index e8221630..7ed39c67 100644 --- a/charges/lionHeadErased.svg +++ b/charges/lionHeadErased.svg @@ -1,28 +1,28 @@ - - - - - - + + + + + + - + - + - - - - - - + + + + + + - + - + diff --git a/charges/lionPassant.svg b/charges/lionPassant.svg index 10dcb448..7dd6b396 100644 --- a/charges/lionPassant.svg +++ b/charges/lionPassant.svg @@ -5,19 +5,19 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -34,148 +34,150 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/lionPassantGuardant.svg b/charges/lionPassantGuardant.svg index 9aa594fa..584e8835 100644 --- a/charges/lionPassantGuardant.svg +++ b/charges/lionPassantGuardant.svg @@ -1,243 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/charges/lionRampant.svg b/charges/lionRampant.svg index d5f6bdad..8aab2b09 100644 --- a/charges/lionRampant.svg +++ b/charges/lionRampant.svg @@ -1,23 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/charges/lionSejant.svg b/charges/lionSejant.svg index 6fe1efae..23ca98db 100644 --- a/charges/lionSejant.svg +++ b/charges/lionSejant.svg @@ -1,133 +1,125 @@ - - + + - - - - - - + + + + + + - + - + - - + + - + - + - + - - + + - - + + + - - - - - - - - + + + + + - - - - - - + + + + + + - - + + - - - + + + - + - - + + - + - + - - - - - - - + + + + + + + - + - + - + - + - - + + - - + + - + - + - + - + - - + + - - + + - + - + - - - - - - - - - - - + + + + + diff --git a/charges/lizard.svg b/charges/lizard.svg index 306e99e9..dc8dbf9d 100644 --- a/charges/lizard.svg +++ b/charges/lizard.svg @@ -1,29 +1,29 @@ - + - + - + - + - - + + - + - + - - + + - + - - + + diff --git a/charges/lute.svg b/charges/lute.svg index 195c62cf..c88cc397 100644 --- a/charges/lute.svg +++ b/charges/lute.svg @@ -1,15 +1 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/charges/lymphad.svg b/charges/lymphad.svg index 7e547eaf..457f10d7 100644 --- a/charges/lymphad.svg +++ b/charges/lymphad.svg @@ -1,75 +1,77 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + diff --git a/charges/lyre.svg b/charges/lyre.svg new file mode 100644 index 00000000..d89b8550 --- /dev/null +++ b/charges/lyre.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/charges/mace.svg b/charges/mace.svg new file mode 100644 index 00000000..a3f0e074 --- /dev/null +++ b/charges/mace.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/maces.svg b/charges/maces.svg new file mode 100644 index 00000000..93988b80 --- /dev/null +++ b/charges/maces.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/mallet.svg b/charges/mallet.svg index 381d172d..ecb418f9 100644 --- a/charges/mallet.svg +++ b/charges/mallet.svg @@ -1,8 +1,10 @@ - - + + + + diff --git a/charges/mantle.svg b/charges/mantle.svg new file mode 100644 index 00000000..5493c30b --- /dev/null +++ b/charges/mantle.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/mapleLeaf.svg b/charges/mapleLeaf.svg index 414a9797..93e63767 100644 --- a/charges/mapleLeaf.svg +++ b/charges/mapleLeaf.svg @@ -1,15 +1,15 @@ - - + + - - - - - - - + + + + + + + diff --git a/charges/martenCourant.svg b/charges/martenCourant.svg index 5efac23b..1760d038 100644 --- a/charges/martenCourant.svg +++ b/charges/martenCourant.svg @@ -1,68 +1,68 @@ - + - + - - + + - - + + - + - + - - + + - + - + - + - - + + - - - + + + - - + + - + - + - - + + - + - + - + - + - + - - + + - + - - + + - + - + diff --git a/charges/mastiffStatant.svg b/charges/mastiffStatant.svg index 4f3d3744..14feb266 100644 --- a/charges/mastiffStatant.svg +++ b/charges/mastiffStatant.svg @@ -1,157 +1,156 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/charges/millstone.svg b/charges/millstone.svg new file mode 100644 index 00000000..f8d523ca --- /dev/null +++ b/charges/millstone.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/charges/mitre.svg b/charges/mitre.svg index bba5d163..1a20e002 100644 --- a/charges/mitre.svg +++ b/charges/mitre.svg @@ -1,40 +1,40 @@ - + - - + + - + - - - - + + + + - + - - - - + + + + - - + + - + - - + + - + diff --git a/charges/moonInCrescent.svg b/charges/moonInCrescent.svg index f0da801d..27fdb512 100644 --- a/charges/moonInCrescent.svg +++ b/charges/moonInCrescent.svg @@ -1,27 +1,27 @@ - + - + - + - + - + - - + + - + - - - - - + + + + + diff --git a/charges/oak.svg b/charges/oak.svg index aa877960..b01da9b4 100644 --- a/charges/oak.svg +++ b/charges/oak.svg @@ -1,346 +1,345 @@ - - - - - - - + + + + + + + - - - - - - - - - - + + + + + + + + + + - + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/orb.svg b/charges/orb.svg index af898083..2d7354f5 100644 --- a/charges/orb.svg +++ b/charges/orb.svg @@ -1,25 +1,25 @@ - - - - - - - - - + + + + + + + + + - - - - - - - - - - + + + + + + + + + + diff --git a/charges/ouroboros.svg b/charges/ouroboros.svg new file mode 100644 index 00000000..f0f39146 --- /dev/null +++ b/charges/ouroboros.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/charges/owlDisplayed.svg b/charges/owlDisplayed.svg index c49d8b27..353fe5e7 100644 --- a/charges/owlDisplayed.svg +++ b/charges/owlDisplayed.svg @@ -1,75 +1,75 @@ - - + + - - + + - - + + - - - + + + - - + + - - - + + + - - - + + + - + - - + + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + diff --git a/charges/palace.svg b/charges/palace.svg new file mode 100644 index 00000000..9e03dd4b --- /dev/null +++ b/charges/palace.svg @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/palmTree.svg b/charges/palmTree.svg index 40264f80..590d14a3 100644 --- a/charges/palmTree.svg +++ b/charges/palmTree.svg @@ -1,154 +1,154 @@ - + - + - + - + - + - - + + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - - - - - - - - - - - - + + + + + + + + + + + + - + - + - - + + - + - + - + - + - + - - + + - + - - + + - + - + - + - - + + - + - + - + - + - + - - + + - + - - + + - + - + diff --git a/charges/peacock.svg b/charges/peacock.svg index 0ae12f99..064831f4 100644 --- a/charges/peacock.svg +++ b/charges/peacock.svg @@ -1,166 +1,166 @@ - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - + + + + + - - + + - - - - - + + + + + - - + + - - - - - + + + + + - - + + - - - - - - - - - + + + + + + + + + - - - + + + - - + + - + - + - + - - - - + + + + - + - + - + - + - + - - - + + + - + - + - + - - - + + + - + - + - - + + - + - - + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - + + - + diff --git a/charges/peacockInPride.svg b/charges/peacockInPride.svg index c235a40a..b8b4f8c7 100644 --- a/charges/peacockInPride.svg +++ b/charges/peacockInPride.svg @@ -1,216 +1,216 @@ - - - + + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - - + + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - - - + + + + - + - - + + - + - - + + - + - - - + + + - + - - + + - + - - - + + + - + - - - + + + - + - - + + - + - - - + + + - + - - - + + + - + - - - + + + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/pear.svg b/charges/pear.svg index f1f01c0f..d421e208 100644 --- a/charges/pear.svg +++ b/charges/pear.svg @@ -1,37 +1,37 @@ - + - - + + - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + - + diff --git a/charges/pegasus.svg b/charges/pegasus.svg index 2583831d..5335022d 100644 --- a/charges/pegasus.svg +++ b/charges/pegasus.svg @@ -16,28 +16,28 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/pillar.svg b/charges/pillar.svg new file mode 100644 index 00000000..d9aa943f --- /dev/null +++ b/charges/pillar.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/pincers.svg b/charges/pincers.svg new file mode 100644 index 00000000..2e91f728 --- /dev/null +++ b/charges/pincers.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/charges/pineCone.svg b/charges/pineCone.svg index 2e5c4e66..c326f2a2 100644 --- a/charges/pineCone.svg +++ b/charges/pineCone.svg @@ -1,24 +1,26 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + diff --git a/charges/pineTree.svg b/charges/pineTree.svg index 7d1aa006..2abebe11 100644 --- a/charges/pineTree.svg +++ b/charges/pineTree.svg @@ -1,16 +1,16 @@ - - - + + + - + - + - + diff --git a/charges/plaice.svg b/charges/plaice.svg index c1e66df1..8325d1ca 100644 --- a/charges/plaice.svg +++ b/charges/plaice.svg @@ -1,48 +1,47 @@ - - - + + - - + + - + - + - + - + - - - - - + + + + + - + - - + + - + - - + + - - + + - + - + - + - + diff --git a/charges/plough.svg b/charges/plough.svg index d31e4287..7c1f42fc 100644 --- a/charges/plough.svg +++ b/charges/plough.svg @@ -1,16 +1,16 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/charges/ploughshare.svg b/charges/ploughshare.svg new file mode 100644 index 00000000..45928f03 --- /dev/null +++ b/charges/ploughshare.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/charges/portcullis.svg b/charges/portcullis.svg new file mode 100644 index 00000000..de154326 --- /dev/null +++ b/charges/portcullis.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/quatrefoil.svg b/charges/quatrefoil.svg index cc7b9a33..ff33f762 100644 --- a/charges/quatrefoil.svg +++ b/charges/quatrefoil.svg @@ -1,14 +1,12 @@ - - - - - - - - - + + + + + + + diff --git a/charges/rabbitSejant.svg b/charges/rabbitSejant.svg index 7bbc22e8..c61e0a9b 100644 --- a/charges/rabbitSejant.svg +++ b/charges/rabbitSejant.svg @@ -1,39 +1,39 @@ - + - - - - + + + + - - - + + + - + - - + + - + - + - + - - + + - + - - + + - - + + diff --git a/charges/raft.svg b/charges/raft.svg new file mode 100644 index 00000000..d5b728b4 --- /dev/null +++ b/charges/raft.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/charges/rake.svg b/charges/rake.svg index 2b76bc51..6feed725 100644 --- a/charges/rake.svg +++ b/charges/rake.svg @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/ramHeadErased.svg b/charges/ramHeadErased.svg index 6ece24a6..c971f7b4 100644 --- a/charges/ramHeadErased.svg +++ b/charges/ramHeadErased.svg @@ -1,72 +1,72 @@ - + - + - + - - + + - + - + - + - + - + - + - - + + - + - - + + - + - + - + - + - + - + - - + + - - + + - + - - + + diff --git a/charges/ramPassant.svg b/charges/ramPassant.svg index 6ce7da7e..421e416c 100644 --- a/charges/ramPassant.svg +++ b/charges/ramPassant.svg @@ -1,80 +1,80 @@ - + - - - + + + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - - + + - + - + - + - + - - - + + + - + - + - + - + - + diff --git a/charges/rapier.svg b/charges/rapier.svg new file mode 100644 index 00000000..fed83920 --- /dev/null +++ b/charges/rapier.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/ratRampant.svg b/charges/ratRampant.svg index 7e1cb3d6..13c6746a 100644 --- a/charges/ratRampant.svg +++ b/charges/ratRampant.svg @@ -1,44 +1,44 @@ - - - - + + + + - - - - + + + + - - - + + + - - - + + + - + - - - - - + + + + + - - - + + + - - - + + + - - - - + + + + - + diff --git a/charges/raven.svg b/charges/raven.svg index 83eb8912..6e3c4eca 100644 --- a/charges/raven.svg +++ b/charges/raven.svg @@ -11,14 +11,14 @@ - - - - - - - - + + + + + + + + diff --git a/charges/rhinoceros.svg b/charges/rhinoceros.svg index 4b6304cd..1d43c4f4 100644 --- a/charges/rhinoceros.svg +++ b/charges/rhinoceros.svg @@ -1,61 +1,61 @@ - + - - - + + + - + - - - - - - - + + + + + + + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - - + + - - + + - + diff --git a/charges/ribbon1.svg b/charges/ribbon1.svg new file mode 100644 index 00000000..03bf3515 --- /dev/null +++ b/charges/ribbon1.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/charges/ribbon2.svg b/charges/ribbon2.svg new file mode 100644 index 00000000..0f15bb04 --- /dev/null +++ b/charges/ribbon2.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/charges/ribbon3.svg b/charges/ribbon3.svg new file mode 100644 index 00000000..dd168991 --- /dev/null +++ b/charges/ribbon3.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/charges/ribbon4.svg b/charges/ribbon4.svg new file mode 100644 index 00000000..bab35959 --- /dev/null +++ b/charges/ribbon4.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/charges/ribbon5.svg b/charges/ribbon5.svg new file mode 100644 index 00000000..3c718bce --- /dev/null +++ b/charges/ribbon5.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/charges/ribbon6.svg b/charges/ribbon6.svg new file mode 100644 index 00000000..a32eede7 --- /dev/null +++ b/charges/ribbon6.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/charges/ribbon7.svg b/charges/ribbon7.svg new file mode 100644 index 00000000..2d9a1e21 --- /dev/null +++ b/charges/ribbon7.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/charges/ribbon8.svg b/charges/ribbon8.svg new file mode 100644 index 00000000..f7c672a7 --- /dev/null +++ b/charges/ribbon8.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/charges/roundel2.svg b/charges/roundel2.svg index 79e2f6ec..fffa7ad4 100644 --- a/charges/roundel2.svg +++ b/charges/roundel2.svg @@ -1,7 +1 @@ - - - - - - - + \ No newline at end of file diff --git a/charges/sabre.svg b/charges/sabre.svg index 765fdb0b..0f1f002d 100644 --- a/charges/sabre.svg +++ b/charges/sabre.svg @@ -1,20 +1,19 @@ - - - - - - + + + + + - - - - - - - - + + + + + + + + diff --git a/charges/sabre2.svg b/charges/sabre2.svg index 44f810c0..2466a761 100644 --- a/charges/sabre2.svg +++ b/charges/sabre2.svg @@ -1,15 +1,15 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/charges/sabresCrossed.svg b/charges/sabresCrossed.svg index 16136577..e9cec5f4 100644 --- a/charges/sabresCrossed.svg +++ b/charges/sabresCrossed.svg @@ -1,39 +1,36 @@ - - - - - - - + + + + + + - - - - - - - - + + + + + + + + - - - - - - - + + + + + - - - - - - - - + + + + + + + + diff --git a/charges/sagittarius.svg b/charges/sagittarius.svg index 074a134a..ac5eaeeb 100644 --- a/charges/sagittarius.svg +++ b/charges/sagittarius.svg @@ -1,136 +1,136 @@ - + - - + + - + - - + + - + - + - + - + - + - - + + - + - - - + + + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - - + + - + - + - - + + - + - + - - + + - - + + - + - - - - - - + + + + + + - - + + - + - + - + - + - + - + - + diff --git a/charges/salmon.svg b/charges/salmon.svg index a3dc8e86..bda9bf49 100644 --- a/charges/salmon.svg +++ b/charges/salmon.svg @@ -1,127 +1,127 @@ - - - + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - + diff --git a/charges/saw.svg b/charges/saw.svg new file mode 100644 index 00000000..c356263f --- /dev/null +++ b/charges/saw.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/charges/scale.svg b/charges/scale.svg new file mode 100644 index 00000000..b2da96ea --- /dev/null +++ b/charges/scale.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/scaleImbalanced.svg b/charges/scaleImbalanced.svg new file mode 100644 index 00000000..ea151649 --- /dev/null +++ b/charges/scaleImbalanced.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/scalesHanging.svg b/charges/scalesHanging.svg new file mode 100644 index 00000000..1065211b --- /dev/null +++ b/charges/scalesHanging.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/sceptre.svg b/charges/sceptre.svg index 0d060330..57869cbf 100644 --- a/charges/sceptre.svg +++ b/charges/sceptre.svg @@ -1,28 +1,28 @@ - - - + + + - + - + - + - + - - - - - + + + + + - - - - + + + + diff --git a/charges/scissors.svg b/charges/scissors.svg index ebc0df99..a7437f1e 100644 --- a/charges/scissors.svg +++ b/charges/scissors.svg @@ -1,8 +1,8 @@ - - - - + + + + diff --git a/charges/scissors2.svg b/charges/scissors2.svg new file mode 100644 index 00000000..109d8238 --- /dev/null +++ b/charges/scissors2.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/charges/scorpion.svg b/charges/scorpion.svg index 3155f3b9..c132511d 100644 --- a/charges/scorpion.svg +++ b/charges/scorpion.svg @@ -1,60 +1,60 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + diff --git a/charges/scrollClosed.svg b/charges/scrollClosed.svg new file mode 100644 index 00000000..1f7d8034 --- /dev/null +++ b/charges/scrollClosed.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/charges/scythe.svg b/charges/scythe.svg index 62a52520..b8d0a04d 100644 --- a/charges/scythe.svg +++ b/charges/scythe.svg @@ -1,15 +1,15 @@ - - - + + + - - - - - - + + + + + + diff --git a/charges/scythe2.svg b/charges/scythe2.svg new file mode 100644 index 00000000..7fa9de5d --- /dev/null +++ b/charges/scythe2.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/charges/sextifoil.svg b/charges/sextifoil.svg index cf8b918d..ad6e3303 100644 --- a/charges/sextifoil.svg +++ b/charges/sextifoil.svg @@ -1,14 +1,14 @@ - - + + - - - - - - + + + + + + diff --git a/charges/shears.svg b/charges/shears.svg new file mode 100644 index 00000000..3b3daeb4 --- /dev/null +++ b/charges/shears.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/charges/shield.svg b/charges/shield.svg index 10f6652f..89ad41de 100644 --- a/charges/shield.svg +++ b/charges/shield.svg @@ -1,31 +1,31 @@ - + - - - + + + - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/charges/shipWheel.svg b/charges/shipWheel.svg new file mode 100644 index 00000000..fa23136c --- /dev/null +++ b/charges/shipWheel.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/sickle.svg b/charges/sickle.svg index dcf6dd44..753eeeaa 100644 --- a/charges/sickle.svg +++ b/charges/sickle.svg @@ -1,12 +1,12 @@ - + - - - + + + - - + + diff --git a/charges/skeleton.svg b/charges/skeleton.svg new file mode 100644 index 00000000..cde28dae --- /dev/null +++ b/charges/skeleton.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/skull.svg b/charges/skull.svg index 4ee33d1c..c7dc7044 100644 --- a/charges/skull.svg +++ b/charges/skull.svg @@ -1,37 +1,37 @@ - - + + - - - - + + + + - - - + + + - - - - + + + + - - + + - + - + - + - - - - + + + + diff --git a/charges/skull2.svg b/charges/skull2.svg new file mode 100644 index 00000000..a580afd7 --- /dev/null +++ b/charges/skull2.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/charges/snail.svg b/charges/snail.svg new file mode 100644 index 00000000..387dc48a --- /dev/null +++ b/charges/snail.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/charges/snowflake.svg b/charges/snowflake.svg new file mode 100644 index 00000000..d85d067b --- /dev/null +++ b/charges/snowflake.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/charges/spear.svg b/charges/spear.svg index 036318d7..9944f9d5 100644 --- a/charges/spear.svg +++ b/charges/spear.svg @@ -1,13 +1,13 @@ - - - + + + - - - - + + + + diff --git a/charges/spiral.svg b/charges/spiral.svg new file mode 100644 index 00000000..05736127 --- /dev/null +++ b/charges/spiral.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/charges/squirrel.svg b/charges/squirrel.svg index 0db644c0..bf2cc68b 100644 --- a/charges/squirrel.svg +++ b/charges/squirrel.svg @@ -1,57 +1,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - + diff --git a/charges/stagLodgedRegardant.svg b/charges/stagLodgedRegardant.svg new file mode 100644 index 00000000..024f648c --- /dev/null +++ b/charges/stagLodgedRegardant.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/stagPassant.svg b/charges/stagPassant.svg index 51fd94d3..745ed25e 100644 --- a/charges/stagPassant.svg +++ b/charges/stagPassant.svg @@ -1,55 +1,55 @@ - + - - - - + + + + - + - - + + - + - + - + - + - + - + - + - + - + - - - + + + - - + + - + diff --git a/charges/stirrup.svg b/charges/stirrup.svg index 7d77eacb..4350ad26 100644 --- a/charges/stirrup.svg +++ b/charges/stirrup.svg @@ -1,47 +1,47 @@ - + - + - - + + - - + + - - + + - - + + - - + + - + - + - + - + - - - - - - - + + + + + + + diff --git a/charges/sunInSplendour2.svg b/charges/sunInSplendour2.svg index 5fee6fcf..d56c221d 100644 --- a/charges/sunInSplendour2.svg +++ b/charges/sunInSplendour2.svg @@ -1,33 +1,33 @@ - - + + - - - + + + - + - + - - + + - - + + - + - - + + - - + + diff --git a/charges/swallow.svg b/charges/swallow.svg index da94f53a..bf363a15 100644 --- a/charges/swallow.svg +++ b/charges/swallow.svg @@ -1,60 +1,60 @@ - + - - + + - - + + - + - + - + - - + + - - + + - + - + - - - + + + - - - + + + - + - + - + - + - + - + - + - + - + - + diff --git a/charges/swan.svg b/charges/swan.svg index 01893692..26a345f7 100644 --- a/charges/swan.svg +++ b/charges/swan.svg @@ -13,15 +13,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/charges/talbotPassant.svg b/charges/talbotPassant.svg index de6649b9..121e6ba4 100644 --- a/charges/talbotPassant.svg +++ b/charges/talbotPassant.svg @@ -1,57 +1,57 @@ - - - - + + + + - - - + + + - - + + - - + + - - + + - - + + - + - + - - + + - - - + + + - - - - + + + + - + - + - - + + - + diff --git a/charges/talbotSejant.svg b/charges/talbotSejant.svg index 0cb80127..e89d4b90 100644 --- a/charges/talbotSejant.svg +++ b/charges/talbotSejant.svg @@ -1,75 +1,75 @@ - - - - + + + + - + - + - + - + - + - - - - - + + + + + - - - + + + - + - + - + - - + + - + - - + + - - - + + + - + - + - + - + - + - + - + - + diff --git a/charges/thistle.svg b/charges/thistle.svg new file mode 100644 index 00000000..09cff52a --- /dev/null +++ b/charges/thistle.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/tower.svg b/charges/tower.svg index 9e3f64ac..9754803a 100644 --- a/charges/tower.svg +++ b/charges/tower.svg @@ -1,17 +1,17 @@ - - - - - - + + + + + + - - - - + + + + - + diff --git a/charges/trefoil.svg b/charges/trefoil.svg index 83a4a036..438c993e 100644 --- a/charges/trefoil.svg +++ b/charges/trefoil.svg @@ -1,11 +1,11 @@ - - + + - - - + + + diff --git a/charges/trowel.svg b/charges/trowel.svg new file mode 100644 index 00000000..b9533474 --- /dev/null +++ b/charges/trowel.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/charges/unicornRampant.svg b/charges/unicornRampant.svg index 4eef4dba..a3102dbc 100644 --- a/charges/unicornRampant.svg +++ b/charges/unicornRampant.svg @@ -17,13 +17,13 @@ - - - - - - - + + + + + + + diff --git a/charges/wasp.svg b/charges/wasp.svg new file mode 100644 index 00000000..9d54306c --- /dev/null +++ b/charges/wasp.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/wheatStalk.svg b/charges/wheatStalk.svg index 229783fb..c6113ccd 100644 --- a/charges/wheatStalk.svg +++ b/charges/wheatStalk.svg @@ -1,41 +1,41 @@ - + - + - - + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - + - - + + - + - + diff --git a/charges/wheel.svg b/charges/wheel.svg index 5e012206..6133eee9 100644 --- a/charges/wheel.svg +++ b/charges/wheel.svg @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - diff --git a/charges/windmill.svg b/charges/windmill.svg new file mode 100644 index 00000000..b814ef1e --- /dev/null +++ b/charges/windmill.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/charges/wolfStatant.svg b/charges/wolfStatant.svg index 297390ec..d592b9ef 100644 --- a/charges/wolfStatant.svg +++ b/charges/wolfStatant.svg @@ -23,7 +23,7 @@ - + diff --git a/charges/wyvern.svg b/charges/wyvern.svg index 92c5de2b..f09b821e 100644 --- a/charges/wyvern.svg +++ b/charges/wyvern.svg @@ -38,32 +38,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/textures/antique-big.jpg b/images/textures/antique-big.jpg new file mode 100644 index 00000000..711b1681 Binary files /dev/null and b/images/textures/antique-big.jpg differ diff --git a/images/textures/antique-small.jpg b/images/textures/antique-small.jpg new file mode 100644 index 00000000..851b5d07 Binary files /dev/null and b/images/textures/antique-small.jpg differ diff --git a/images/textures/folded-paper-big.jpg b/images/textures/folded-paper-big.jpg new file mode 100644 index 00000000..c2c4d761 Binary files /dev/null and b/images/textures/folded-paper-big.jpg differ diff --git a/images/textures/folded-paper-small.jpg b/images/textures/folded-paper-small.jpg new file mode 100644 index 00000000..88418a13 Binary files /dev/null and b/images/textures/folded-paper-small.jpg differ diff --git a/images/textures/gray-paper.jpg b/images/textures/gray-paper.jpg new file mode 100644 index 00000000..238d6e4c Binary files /dev/null and b/images/textures/gray-paper.jpg differ diff --git a/images/textures/iran-small.jpg b/images/textures/iran-small.jpg new file mode 100644 index 00000000..39f34512 Binary files /dev/null and b/images/textures/iran-small.jpg differ diff --git a/images/textures/marble-big.jpg b/images/textures/marble-big.jpg new file mode 100644 index 00000000..c1d2a6d4 Binary files /dev/null and b/images/textures/marble-big.jpg differ diff --git a/images/textures/marble-blue-big.jpg b/images/textures/marble-blue-big.jpg new file mode 100644 index 00000000..dbfc0975 Binary files /dev/null and b/images/textures/marble-blue-big.jpg differ diff --git a/images/textures/marble-blue-small.jpg b/images/textures/marble-blue-small.jpg new file mode 100644 index 00000000..2e95fdcb Binary files /dev/null and b/images/textures/marble-blue-small.jpg differ diff --git a/images/textures/marble-small.jpg b/images/textures/marble-small.jpg new file mode 100644 index 00000000..10d1a9ab Binary files /dev/null and b/images/textures/marble-small.jpg differ diff --git a/images/textures/mars-big.jpg b/images/textures/mars-big.jpg new file mode 100644 index 00000000..3fd39dae Binary files /dev/null and b/images/textures/mars-big.jpg differ diff --git a/images/textures/mars-small.jpg b/images/textures/mars-small.jpg new file mode 100644 index 00000000..75de8dd3 Binary files /dev/null and b/images/textures/mars-small.jpg differ diff --git a/images/textures/mauritania-small.jpg b/images/textures/mauritania-small.jpg new file mode 100644 index 00000000..22d9cecf Binary files /dev/null and b/images/textures/mauritania-small.jpg differ diff --git a/images/textures/mercury-big.jpg b/images/textures/mercury-big.jpg new file mode 100644 index 00000000..7e06f0ee Binary files /dev/null and b/images/textures/mercury-big.jpg differ diff --git a/images/textures/mercury-small.jpg b/images/textures/mercury-small.jpg new file mode 100644 index 00000000..53f31ee3 Binary files /dev/null and b/images/textures/mercury-small.jpg differ diff --git a/images/textures/ocean.jpg b/images/textures/ocean.jpg new file mode 100644 index 00000000..981366ca Binary files /dev/null and b/images/textures/ocean.jpg differ diff --git a/images/textures/pergamena-small.jpg b/images/textures/pergamena-small.jpg new file mode 100644 index 00000000..951f9eda Binary files /dev/null and b/images/textures/pergamena-small.jpg differ diff --git a/images/textures/plaster.jpg b/images/textures/plaster.jpg new file mode 100644 index 00000000..8ec85c81 Binary files /dev/null and b/images/textures/plaster.jpg differ diff --git a/images/textures/soiled-paper-vertical.png b/images/textures/soiled-paper-vertical.png new file mode 100644 index 00000000..f8bb720e Binary files /dev/null and b/images/textures/soiled-paper-vertical.png differ diff --git a/images/textures/soiled-paper.jpg b/images/textures/soiled-paper.jpg new file mode 100644 index 00000000..00333992 Binary files /dev/null and b/images/textures/soiled-paper.jpg differ diff --git a/images/textures/spain-small.jpg b/images/textures/spain-small.jpg new file mode 100644 index 00000000..a413f508 Binary files /dev/null and b/images/textures/spain-small.jpg differ diff --git a/images/textures/timbercut-big.jpg b/images/textures/timbercut-big.jpg new file mode 100644 index 00000000..7dc9b656 Binary files /dev/null and b/images/textures/timbercut-big.jpg differ diff --git a/images/textures/timbercut-small.jpg b/images/textures/timbercut-small.jpg new file mode 100644 index 00000000..a73e47be Binary files /dev/null and b/images/textures/timbercut-small.jpg differ diff --git a/index.css b/index.css index b4ec49ce..d5c5ef34 100644 --- a/index.css +++ b/index.css @@ -169,6 +169,7 @@ t, #temperature, #texture, #landmass, +#vignette, #fogging { pointer-events: none; } @@ -625,7 +626,7 @@ input[type="color"]::-webkit-color-swatch-wrapper { .tabcontent button.sideButton { border-radius: 15%; font-size: 0.8em; - margin-bottom: -1em; + margin-block: -1em; } #layersContent button.active, @@ -1632,7 +1633,7 @@ div.states > .riverType { padding: 0.3em 0; } -#saveTilesScreen div.label { +#exportToPngTilesScreen div.label { display: inline-block; width: 5em; } @@ -1875,12 +1876,6 @@ div.editorLine { margin: 0.4em 0 0 -0.9em; } -#barBackColor { - width: 3.5em; - padding: 0px; - height: 1.2em; -} - #ruler { cursor: move; fill: none; @@ -1920,18 +1915,6 @@ div.editorLine { stroke: #737373; } -#scaleBar { - stroke: none; - fill: none; - cursor: pointer; -} - -#scaleBar text { - fill: #353540; - text-anchor: middle; - font-family: var(--serif); -} - #militaryOptionsTable select { border: 1px solid #d4d4d4; } @@ -1990,7 +1973,7 @@ input[type="checkbox"] { .checkbox + .checkbox-label:before { content: ""; display: inline-block; - vertical-align: middle; + vertical-align: bottom; width: 0.6em; height: 0.6em; padding: 0.2em; @@ -1998,6 +1981,7 @@ input[type="checkbox"] { border: 1px solid darkgrey; border-radius: 15%; background: white; + font-family: var(--monospace); } .checkbox:checked + .checkbox-label:before { diff --git a/index.html b/index.html index 72f64979..abe1116d 100644 --- a/index.html +++ b/index.html @@ -138,7 +138,7 @@ } - + @@ -359,9 +359,19 @@ + + + + + - + + + + + +
@@ -703,6 +713,15 @@ > Scale Bar +
  • + Vignette +
  • @@ -782,9 +801,11 @@ + + @@ -806,6 +827,63 @@ + + + + + + + + + + Terracing + + + 0 + + + + + Reduce layers + + + 5 + + + + + Simplify line + + + 0 + + + + + Line style + + + + + + + Color scheme + + + + + + + Opacity @@ -866,77 +944,31 @@
    +
    + Chinese localization: 8desk.top +
    + -

    `; +

    + +

    Chinese localization: 8desk.top

    `; $("#alert").dialog({ resizable: false, diff --git a/modules/ui/hotkeys.js b/modules/ui/hotkeys.js index 4543d187..a0d866c9 100644 --- a/modules/ui/hotkeys.js +++ b/modules/ui/hotkeys.js @@ -91,6 +91,7 @@ function handleKeyup(event) { else if (code === "KeyK") toggleMarkers(); else if (code === "Equal" && !customization) toggleRulers(); else if (code === "Slash") toggleScaleBar(); + else if (code === "BracketLeft") toggleVignette(); else if (code === "ArrowLeft") zoom.translateBy(svg, 10, 0); else if (code === "ArrowRight") zoom.translateBy(svg, -10, 0); else if (code === "ArrowUp") zoom.translateBy(svg, 0, 10); diff --git a/modules/ui/layers.js b/modules/ui/layers.js index be8ea995..783f4de4 100644 --- a/modules/ui/layers.js +++ b/modules/ui/layers.js @@ -14,7 +14,8 @@ function getDefaultPresets() { "toggleRivers", "toggleRoutes", "toggleScaleBar", - "toggleStates" + "toggleStates", + "toggleVignette" ], cultural: [ "toggleBorders", @@ -23,7 +24,8 @@ function getDefaultPresets() { "toggleLabels", "toggleRivers", "toggleRoutes", - "toggleScaleBar" + "toggleScaleBar", + "toggleVignette" ], religions: [ "toggleBorders", @@ -32,12 +34,13 @@ function getDefaultPresets() { "toggleReligions", "toggleRivers", "toggleRoutes", - "toggleScaleBar" + "toggleScaleBar", + "toggleVignette" ], - provinces: ["toggleBorders", "toggleIcons", "toggleProvinces", "toggleRivers", "toggleScaleBar"], - biomes: ["toggleBiomes", "toggleIce", "toggleRivers", "toggleScaleBar"], - heightmap: ["toggleHeight", "toggleRivers"], - physical: ["toggleCoordinates", "toggleHeight", "toggleIce", "toggleRivers", "toggleScaleBar"], + provinces: ["toggleBorders", "toggleIcons", "toggleProvinces", "toggleRivers", "toggleScaleBar", "toggleVignette"], + biomes: ["toggleBiomes", "toggleIce", "toggleRivers", "toggleScaleBar", "toggleVignette"], + heightmap: ["toggleHeight", "toggleRivers", "toggleVignette"], + physical: ["toggleCoordinates", "toggleHeight", "toggleIce", "toggleRivers", "toggleScaleBar", "toggleVignette"], poi: [ "toggleBorders", "toggleHeight", @@ -46,7 +49,8 @@ function getDefaultPresets() { "toggleMarkers", "toggleRivers", "toggleRoutes", - "toggleScaleBar" + "toggleScaleBar", + "toggleVignette" ], military: [ "toggleBorders", @@ -56,7 +60,8 @@ function getDefaultPresets() { "toggleRivers", "toggleRoutes", "toggleScaleBar", - "toggleStates" + "toggleStates", + "toggleVignette" ], emblems: [ "toggleBorders", @@ -66,7 +71,8 @@ function getDefaultPresets() { "toggleRivers", "toggleRoutes", "toggleScaleBar", - "toggleStates" + "toggleStates", + "toggleVignette" ], landmass: ["toggleScaleBar"] }; @@ -157,6 +163,7 @@ function getCurrentPreset() { // run on map regeneration function restoreLayers() { + if (layerIsOn("toggleTexture")) drawTexture(); if (layerIsOn("toggleHeight")) drawHeightmap(); if (layerIsOn("toggleCells")) drawCells(); if (layerIsOn("toggleGrid")) drawGrid(); @@ -181,92 +188,135 @@ function restoreLayers() { } function toggleHeight(event) { - if (customization === 1) { - tip("You cannot turn off the layer when heightmap is in edit mode", false, "error"); - return; - } + if (customization === 1) return tip("You cannot turn off the layer when heightmap is in edit mode", false, "error"); - if (!terrs.selectAll("*").size()) { + const children = terrs.selectAll("#oceanHeights > *, #landHeights > *"); + if (!children.size()) { turnButtonOn("toggleHeight"); drawHeightmap(); if (event && isCtrlClick(event)) editStyle("terrs"); } else { - if (event && isCtrlClick(event)) { - editStyle("terrs"); - return; - } + if (event && isCtrlClick(event)) return editStyle("terrs"); turnButtonOff("toggleHeight"); - terrs.selectAll("*").remove(); + children.remove(); } } function drawHeightmap() { TIME && console.time("drawHeightmap"); - terrs.selectAll("*").remove(); - const {cells, vertices} = pack; - const n = cells.i.length; - const used = new Uint8Array(cells.i.length); - const paths = new Array(101).fill(""); + const ocean = terrs.select("#oceanHeights"); + const land = terrs.select("#landHeights"); - const scheme = getColorScheme(terrs.attr("scheme")); - const terracing = terrs.attr("terracing") / 10; // add additional shifted darker layer for pseudo-3d effect - const skip = +terrs.attr("skip") + 1; - const simplification = +terrs.attr("relax"); + ocean.selectAll("*").remove(); + land.selectAll("*").remove(); - switch (+terrs.attr("curve")) { - case 0: - lineGen.curve(d3.curveBasisClosed); - break; - case 1: - lineGen.curve(d3.curveLinear); - break; - case 2: - lineGen.curve(d3.curveStep); - break; - default: - lineGen.curve(d3.curveBasisClosed); + const paths = new Array(101); + + // ocean cells + const renderOceanCells = Boolean(+ocean.attr("data-render")); + if (renderOceanCells) { + const {cells, vertices} = grid; + const used = new Uint8Array(cells.i.length); + + const skip = +ocean.attr("skip") + 1 || 1; + const relax = +ocean.attr("relax") || 0; + lineGen.curve(d3[ocean.attr("curve") || "curveBasisClosed"]); + + let currentLayer = 0; + const heights = Array.from(cells.i).sort((a, b) => cells.h[a] - cells.h[b]); + + for (const i of heights) { + const h = cells.h[i]; + if (h > currentLayer) currentLayer += skip; + if (h < currentLayer) continue; + if (currentLayer >= 20) break; + if (used[i]) continue; // already marked + const onborder = cells.c[i].some(n => cells.h[n] < h); + if (!onborder) continue; + const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.h[i] < h)); + const chain = connectVertices(cells, vertices, vertex, h, used); + if (chain.length < 3) continue; + const points = simplifyLine(chain, relax).map(v => vertices.p[v]); + if (!paths[h]) paths[h] = ""; + paths[h] += round(lineGen(points)); + } } - let currentLayer = 20; - const heights = cells.i.sort((a, b) => cells.h[a] - cells.h[b]); - for (const i of heights) { - const h = cells.h[i]; - if (h > currentLayer) currentLayer += skip; - if (currentLayer > 100) break; // no layers possible with height > 100 - if (h < currentLayer) continue; - if (used[i]) continue; // already marked - const onborder = cells.c[i].some(n => cells.h[n] < h); - if (!onborder) continue; - const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.h[i] < h)); - const chain = connectVertices(vertex, h); - if (chain.length < 3) continue; - const points = simplifyLine(chain).map(v => vertices.p[v]); - paths[h] += round(lineGen(points)); + // land cells + { + const {cells, vertices} = pack; + const used = new Uint8Array(cells.i.length); + + const skip = +land.attr("skip") + 1 || 1; + const relax = +land.attr("relax") || 0; + lineGen.curve(d3[land.attr("curve") || "curveBasisClosed"]); + + let currentLayer = 20; + const heights = Array.from(cells.i).sort((a, b) => cells.h[a] - cells.h[b]); + for (const i of heights) { + const h = cells.h[i]; + if (h > currentLayer) currentLayer += skip; + if (h < currentLayer) continue; + if (currentLayer > 100) break; // no layers possible with height > 100 + if (used[i]) continue; // already marked + const onborder = cells.c[i].some(n => cells.h[n] < h); + if (!onborder) continue; + const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.h[i] < h)); + const chain = connectVertices(cells, vertices, vertex, h, used); + if (chain.length < 3) continue; + const points = simplifyLine(chain, relax).map(v => vertices.p[v]); + if (!paths[h]) paths[h] = ""; + paths[h] += round(lineGen(points)); + } } - terrs - .append("rect") - .attr("x", 0) - .attr("y", 0) - .attr("width", graphWidth) - .attr("height", graphHeight) - .attr("fill", scheme(0.8)); // draw base layer - for (const i of d3.range(20, 101)) { - if (paths[i].length < 10) continue; - const color = getColor(i, scheme); - if (terracing) - terrs - .append("path") - .attr("d", paths[i]) - .attr("transform", "translate(.7,1.4)") - .attr("fill", d3.color(color).darker(terracing)) - .attr("data-height", i); - terrs.append("path").attr("d", paths[i]).attr("fill", color).attr("data-height", i); + // render paths + for (const height of d3.range(0, 101)) { + const group = height < 20 ? ocean : land; + const scheme = getColorScheme(group.attr("scheme")); + + if (height === 0 && renderOceanCells) { + // draw base ocean layer + group + .append("rect") + .attr("x", 0) + .attr("y", 0) + .attr("width", graphWidth) + .attr("height", graphHeight) + .attr("fill", scheme(1)); + } + + if (height === 20) { + // draw base land layer + group + .append("rect") + .attr("x", 0) + .attr("y", 0) + .attr("width", graphWidth) + .attr("height", graphHeight) + .attr("fill", scheme(0.8)); + } + + if (paths[height] && paths[height].length >= 10) { + const terracing = group.attr("terracing") / 10 || 0; + const color = getColor(height, scheme); + + if (terracing) { + group + .append("path") + .attr("d", paths[height]) + .attr("transform", "translate(.7,1.4)") + .attr("fill", d3.color(color).darker(terracing)) + .attr("data-height", height); + } + group.append("path").attr("d", paths[height]).attr("fill", color).attr("data-height", height); + } } // connect vertices to chain - function connectVertices(start, h) { + function connectVertices(cells, vertices, start, h, used) { + const n = cells.i.length; const chain = []; // vertices chain to form a path for (let i = 0, current = start; i === 0 || (current !== start && i < 20000); i++) { const prev = chain[chain.length - 1]; // previous vertex in chain @@ -288,7 +338,7 @@ function drawHeightmap() { return chain; } - function simplifyLine(chain) { + function simplifyLine(chain, simplification) { if (!simplification) return chain; const n = simplification + 1; // filter each nth element return chain.filter((d, i) => i % n === 0); @@ -297,15 +347,7 @@ function drawHeightmap() { TIME && console.timeEnd("drawHeightmap"); } -function getColorScheme(scheme) { - if (scheme === "bright") return d3.scaleSequential(d3.interpolateSpectral); - if (scheme === "light") return d3.scaleSequential(d3.interpolateRdYlGn); - if (scheme === "green") return d3.scaleSequential(d3.interpolateGreens); - if (scheme === "monochrome") return d3.scaleSequential(d3.interpolateGreys); - return d3.scaleSequential(d3.interpolateSpectral); -} - -function getColor(value, scheme = getColorScheme()) { +function getColor(value, scheme = getColorScheme("bright")) { return scheme(1 - (value < 20 ? value - 5 : value) / 100); } @@ -1517,18 +1559,30 @@ function toggleRelief(event) { function toggleTexture(event) { if (!layerIsOn("toggleTexture")) { turnButtonOn("toggleTexture"); - // href is not set directly to avoid image loading when layer is off - const textureImage = byId("textureImage"); - if (textureImage) textureImage.setAttribute("href", textureImage.getAttribute("src")); - + drawTexture(); if (event && isCtrlClick(event)) editStyle("texture"); } else { if (event && isCtrlClick(event)) return editStyle("texture"); turnButtonOff("toggleTexture"); - texture.select("image").attr("href", null); + texture.select("image").remove(); } } +function drawTexture() { + const x = Number(texture.attr("data-x") || 0); + const y = Number(texture.attr("data-y") || 0); + const href = texture.attr("data-href"); + + texture + .append("image") + .attr("preserveAspectRatio", "xMidYMid slice") + .attr("x", x) + .attr("y", y) + .attr("width", graphWidth - x) + .attr("height", graphHeight - y) + .attr("href", href); +} + function toggleRivers(event) { if (!layerIsOn("toggleRivers")) { turnButtonOn("toggleRivers"); @@ -1659,10 +1713,7 @@ function toggleLabels(event) { invokeActiveZooming(); if (event && isCtrlClick(event)) editStyle("labels"); } else { - if (event && isCtrlClick(event)) { - editStyle("labels"); - return; - } + if (event && isCtrlClick(event)) return editStyle("labels"); turnButtonOff("toggleLabels"); labels.style("display", "none"); } @@ -1674,10 +1725,7 @@ function toggleIcons(event) { $("#icons").fadeIn(); if (event && isCtrlClick(event)) editStyle("burgIcons"); } else { - if (event && isCtrlClick(event)) { - editStyle("burgIcons"); - return; - } + if (event && isCtrlClick(event)) return editStyle("burgIcons"); turnButtonOff("toggleIcons"); $("#icons").fadeOut(); } @@ -1690,10 +1738,7 @@ function toggleRulers(event) { rulers.draw(); ruler.style("display", null); } else { - if (event && isCtrlClick(event)) { - editStyle("ruler"); - return; - } + if (event && isCtrlClick(event)) return editStyle("ruler"); turnButtonOff("toggleRulers"); ruler.selectAll("*").remove(); ruler.style("display", "none"); @@ -1704,17 +1749,113 @@ function toggleScaleBar(event) { if (!layerIsOn("toggleScaleBar")) { turnButtonOn("toggleScaleBar"); $("#scaleBar").fadeIn(); - if (event && isCtrlClick(event)) editUnits(); + if (event && isCtrlClick(event)) editStyle("scaleBar"); } else { - if (event && isCtrlClick(event)) { - editUnits(); - return; - } + if (event && isCtrlClick(event)) return editStyle("scaleBar"); $("#scaleBar").fadeOut(); turnButtonOff("toggleScaleBar"); } } +function drawScaleBar(scaleBar, scaleLevel) { + if (!scaleBar.size() || scaleBar.style("display") === "none") return; + + const distanceScale = +distanceScaleInput.value; + const unit = distanceUnitInput.value; + const size = +scaleBar.attr("data-bar-size"); + + const length = (function () { + const init = 100; + let val = (init * size * distanceScale) / scaleLevel; // bar length in distance unit + if (val > 900) val = rn(val, -3); // round to 1000 + else if (val > 90) val = rn(val, -2); // round to 100 + else if (val > 9) val = rn(val, -1); // round to 10 + else val = rn(val); // round to 1 + const length = (val * scaleLevel) / distanceScale; // actual length in pixels on this scale + return length; + })(); + + scaleBar.select("#scaleBarContent").remove(); // redraw content every time + const content = scaleBar.append("g").attr("id", "scaleBarContent"); + + const lines = content.append("g"); + lines + .append("line") + .attr("x1", 0.5) + .attr("y1", 0) + .attr("x2", length + size - 0.5) + .attr("y2", 0) + .attr("stroke-width", size) + .attr("stroke", "white"); + lines + .append("line") + .attr("x1", 0) + .attr("y1", size) + .attr("x2", length + size) + .attr("y2", size) + .attr("stroke-width", size) + .attr("stroke", "#3d3d3d"); + lines + .append("line") + .attr("x1", 0) + .attr("y1", 0) + .attr("x2", length + size) + .attr("y2", 0) + .attr("stroke-width", rn(size * 3, 2)) + .attr("stroke-dasharray", size + " " + rn(length / 5 - size, 2)) + .attr("stroke", "#3d3d3d"); + + const texts = content.append("g").attr("text-anchor", "middle").attr("font-family", "var(--serif)"); + texts + .selectAll("text") + .data(d3.range(0, 6)) + .enter() + .append("text") + .attr("x", d => rn((d * length) / 5, 2)) + .attr("y", 0) + .attr("dy", "-.6em") + .text(d => rn((((d * length) / 5) * distanceScale) / scaleLevel) + (d < 5 ? "" : " " + unit)); + + const label = scaleBar.attr("data-label"); + if (label) { + texts + .append("text") + .attr("x", (length + 1) / 2) + .attr("dy", ".6em") + .attr("dominant-baseline", "text-before-edge") + .text(label); + } + + const scaleBarBack = scaleBar.select("#scaleBarBack"); + if (scaleBarBack.size()) { + const bbox = content.node().getBBox(); + const paddingTop = +scaleBarBack.attr("data-top") || 0; + const paddingLeft = +scaleBarBack.attr("data-left") || 0; + const paddingRight = +scaleBarBack.attr("data-right") || 0; + const paddingBottom = +scaleBarBack.attr("data-bottom") || 0; + + scaleBar + .select("#scaleBarBack") + .attr("x", -paddingLeft) + .attr("y", -paddingTop) + .attr("width", bbox.width + paddingRight) + .attr("height", bbox.height + paddingBottom); + } +} + +// fit ScaleBar to screen size +function fitScaleBar(scaleBar, fullWidth, fullHeight) { + if (!scaleBar.select("rect").size() || scaleBar.style("display") === "none") return; + + const posX = +scaleBar.attr("data-x") || 99; + const posY = +scaleBar.attr("data-y") || 99; + const bbox = scaleBar.select("rect").node().getBBox(); + + const x = rn((fullWidth * posX) / 100 - bbox.width + 10); + const y = rn((fullHeight * posY) / 100 - bbox.height + 20); + scaleBar.attr("transform", `translate(${x},${y})`); +} + function toggleZones(event) { if (!layerIsOn("toggleZones")) { turnButtonOn("toggleZones"); @@ -1737,10 +1878,7 @@ function toggleEmblems(event) { $("#emblems").fadeIn(); if (event && isCtrlClick(event)) editStyle("emblems"); } else { - if (event && isCtrlClick(event)) { - editStyle("emblems"); - return; - } + if (event && isCtrlClick(event)) return editStyle("emblems"); $("#emblems").fadeOut(); turnButtonOff("toggleEmblems"); } @@ -1857,6 +1995,18 @@ function drawEmblems() { TIME && console.timeEnd("drawEmblems"); } +function toggleVignette(event) { + if (!layerIsOn("toggleVignette")) { + turnButtonOn("toggleVignette"); + $("#vignette").fadeIn(); + if (event && isCtrlClick(event)) editStyle("vignette"); + } else { + if (event && isCtrlClick(event)) return editStyle("vignette"); + $("#vignette").fadeOut(); + turnButtonOff("toggleVignette"); + } +} + function layerIsOn(el) { const buttonoff = document.getElementById(el).classList.contains("buttonoff"); return !buttonoff; diff --git a/modules/ui/measurers.js b/modules/ui/measurers.js index 54a6d9f8..8120fff1 100644 --- a/modules/ui/measurers.js +++ b/modules/ui/measurers.js @@ -532,101 +532,3 @@ class Planimeter extends Measurer { this.el.select("text").attr("x", c[0]).attr("y", c[1]).text(area); } } - -// Scale bar -function drawScaleBar(scaleLevel) { - if (scaleBar.style("display") === "none") return; // no need to re-draw hidden element - scaleBar.selectAll("*").remove(); // fully redraw every time - - const distanceScale = +distanceScaleInput.value; - const unit = distanceUnitInput.value; - const size = +barSizeInput.value; - - // calculate size - const init = 100; - let val = (init * size * distanceScale) / scaleLevel; // bar length in distance unit - if (val > 900) val = rn(val, -3); - // round to 1000 - else if (val > 90) val = rn(val, -2); - // round to 100 - else if (val > 9) val = rn(val, -1); - // round to 10 - else val = rn(val); // round to 1 - const length = (val * scaleLevel) / distanceScale; // actual length in pixels on this scale - - scaleBar - .append("line") - .attr("x1", 0.5) - .attr("y1", 0) - .attr("x2", length + size - 0.5) - .attr("y2", 0) - .attr("stroke-width", size) - .attr("stroke", "white"); - scaleBar - .append("line") - .attr("x1", 0) - .attr("y1", size) - .attr("x2", length + size) - .attr("y2", size) - .attr("stroke-width", size) - .attr("stroke", "#3d3d3d"); - const dash = size + " " + rn(length / 5 - size, 2); - scaleBar - .append("line") - .attr("x1", 0) - .attr("y1", 0) - .attr("x2", length + size) - .attr("y2", 0) - .attr("stroke-width", rn(size * 3, 2)) - .attr("stroke-dasharray", dash) - .attr("stroke", "#3d3d3d"); - - const fontSize = rn(5 * size, 1); - scaleBar - .selectAll("text") - .data(d3.range(0, 6)) - .enter() - .append("text") - .attr("x", d => rn((d * length) / 5, 2)) - .attr("y", 0) - .attr("dy", "-.5em") - .attr("font-size", fontSize) - .text(d => rn((((d * length) / 5) * distanceScale) / scaleLevel) + (d < 5 ? "" : " " + unit)); - - if (barLabel.value !== "") { - scaleBar - .append("text") - .attr("x", (length + 1) / 2) - .attr("y", 2 * size) - .attr("dominant-baseline", "text-before-edge") - .attr("font-size", fontSize) - .text(barLabel.value); - } - - const bbox = scaleBar.node().getBBox(); - // append backbround rectangle - scaleBar - .insert("rect", ":first-child") - .attr("x", -10) - .attr("y", -20) - .attr("width", bbox.width + 10) - .attr("height", bbox.height + 15) - .attr("stroke-width", size) - .attr("stroke", "none") - .attr("filter", "url(#blur5)") - .attr("fill", barBackColor.value) - .attr("opacity", +barBackOpacity.value); - - fitScaleBar(); -} - -// fit ScaleBar to canvas size -function fitScaleBar() { - if (!scaleBar.select("rect").size() || scaleBar.style("display") === "none") return; - const px = isNaN(+barPosX.value) ? 0.99 : barPosX.value / 100; - const py = isNaN(+barPosY.value) ? 0.99 : barPosY.value / 100; - const bbox = scaleBar.select("rect").node().getBBox(); - const x = rn(svgWidth * px - bbox.width + 10), - y = rn(svgHeight * py - bbox.height + 20); - scaleBar.attr("transform", `translate(${x},${y})`); -} diff --git a/modules/ui/military-overview.js b/modules/ui/military-overview.js index 35a23ed4..7c83c757 100644 --- a/modules/ui/military-overview.js +++ b/modules/ui/military-overview.js @@ -54,7 +54,9 @@ function overviewMilitary() { const insert = html => document.getElementById("militaryTotal").insertAdjacentHTML("beforebegin", html); for (const u of options.military) { const label = capitalize(u.name.replace(/_/g, " ")); - insert(`
    ${label} 
    `); + insert( + `
    ${label} 
    ` + ); } header.querySelectorAll(".removable").forEach(function (e) { e.addEventListener("click", function () { @@ -76,7 +78,9 @@ function overviewMilitary() { const rate = (total / population) * 100; const sortData = options.military.map(u => `data-${u.name}="${getForces(u)}"`).join(" "); - const lineData = options.military.map(u => `
    ${getForces(u)}
    `).join(" "); + const lineData = options.military + .map(u => `
    ${getForces(u)}
    `) + .join(" "); lines += /* html */ `
    ${lineData} -
    ${si(total)}
    +
    ${si( + total + )}
    ${si(population)}
    -
    ${rn(rate, 2)}%
    +
    ${rn( + rate, + 2 + )}%
    s.military.reduce((s, r) => s + (r.u[u.name] || 0), 0); - options.military.forEach(u => (line.dataset[u.name] = line.querySelector(`div[data-type='${u.name}']`).innerHTML = getForces(u))); + options.military.forEach( + u => (line.dataset[u.name] = line.querySelector(`div[data-type='${u.name}']`).innerHTML = getForces(u)) + ); const population = rn((s.rural + s.urban * urbanization) * populationRate); const total = (line.dataset.total = options.military.reduce((s, u) => s + getForces(u) * u.crew, 0)); @@ -237,7 +248,16 @@ function overviewMilitary() { position: {my: "center", at: "center", of: "svg"}, buttons: { Apply: applyMilitaryOptions, - Add: () => addUnitLine({icon: "🛡️", name: "custom" + militaryOptionsTable.rows.length, rural: 0.2, urban: 0.5, crew: 1, power: 1, type: "melee"}), + Add: () => + addUnitLine({ + icon: "🛡️", + name: "custom" + militaryOptionsTable.rows.length, + rural: 0.2, + urban: 0.5, + crew: 1, + power: 1, + type: "melee" + }), Restore: restoreDefaultUnits, Cancel: function () { $(this).dialog("close"); @@ -262,7 +282,7 @@ function overviewMilitary() { if (el.tagName !== "BUTTON") return; const type = el.dataset.type; - if (type === "icon") return selectIcon(el.innerHTML, v => (el.innerHTML = v)); + if (type === "icon") return selectIcon(el.textContent, v => (el.textContent = v)); if (type === "biomes") { const {i, name, color} = biomesData; const biomesArray = Array(i.length).fill(null); @@ -294,7 +314,9 @@ function overviewMilitary() { function addUnitLine(unit) { const {type, icon, name, rural, urban, power, crew, separate} = unit; const row = document.createElement("tr"); - const typeOptions = types.map(t => ``).join(" "); + const typeOptions = types + .map(t => ``) + .join(" "); const getLimitButton = attr => ` + row.innerHTML = /* html */ ` ${getLimitButton("biomes")} ${getLimitButton("states")} @@ -344,7 +368,9 @@ function overviewMilitary() { const lines = filtered.map( ({i, name, fullName, color}) => ` - + ` ); @@ -387,22 +413,21 @@ function overviewMilitary() { function applyMilitaryOptions() { const unitLines = Array.from(tableBody.querySelectorAll("tr")); const names = unitLines.map(r => r.querySelector("input").value.replace(/[&\/\\#, +()$~%.'":*?<>{}]/g, "_")); - if (new Set(names).size !== names.length) { - tip("All units should have unique names", false, "error"); - return; - } + if (new Set(names).size !== names.length) return tip("All units should have unique names", false, "error"); $("#militaryOptions").dialog("close"); + options.military = unitLines.map((r, i) => { const elements = Array.from(r.querySelectorAll("input, button, select")); - const [icon, name, biomes, states, cultures, religions, rural, urban, crew, power, type, separate] = elements.map(el => { - const {type, value} = el.dataset || {}; - if (type === "icon") return el.innerHTML || "⠀"; - if (type) return value ? value.split(",").map(v => parseInt(v)) : null; - if (el.type === "number") return +el.value || 0; - if (el.type === "checkbox") return +el.checked || 0; - return el.value; - }); + const [icon, name, biomes, states, cultures, religions, rural, urban, crew, power, type, separate] = + elements.map(el => { + const {type, value} = el.dataset || {}; + if (type === "icon") return el.textContent || "⠀"; + if (type) return value ? value.split(",").map(v => parseInt(v)) : null; + if (el.type === "number") return +el.value || 0; + if (el.type === "checkbox") return +el.checked || 0; + return el.value; + }); const unit = {icon, name: names[i], rural, urban, crew, power, type, separate}; if (biomes) unit.biomes = biomes; @@ -419,7 +444,8 @@ function overviewMilitary() { } function militaryRecalculate() { - alertMessage.innerHTML = "Are you sure you want to recalculate military forces for all states?
    Regiments for all states will be regenerated"; + alertMessage.innerHTML = + "Are you sure you want to recalculate military forces for all states?
    Regiments for all states will be regenerated"; $("#alert").dialog({ resizable: false, title: "Remove regiment", diff --git a/modules/ui/namesbase-editor.js b/modules/ui/namesbase-editor.js index 0dba088a..edf472eb 100644 --- a/modules/ui/namesbase-editor.js +++ b/modules/ui/namesbase-editor.js @@ -244,11 +244,13 @@ function editNamesbase() { Names.clearChains(); if (override) nameBases = []; + const unsafe = new RegExp(/[|/]/, "g"); data.forEach(base => { - const [name, min, max, d, m, names] = base.split("|"); - const secureNames = names.replace(/[/|]/g, ""); - nameBases.push({name, min, max, d, m, b: secureNames}); + const [rawName, min, max, d, m, rawNames] = base.split("|"); + const name = rawName.replace(unsafe, ""); + const names = rawNames.replace(unsafe, ""); + nameBases.push({name, min, max, d, m, b: names}); }); createBasesList(); diff --git a/modules/ui/notes-editor.js b/modules/ui/notes-editor.js index a28885b9..38058fe5 100644 --- a/modules/ui/notes-editor.js +++ b/modules/ui/notes-editor.js @@ -2,16 +2,14 @@ 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"); + const notesLegend = byId("notesLegend"); + const notesName = byId("notesName"); + const notesSelect = byId("notesSelect"); + const notesPin = byId("notesPin"); // update list of objects notesSelect.options.length = 0; - for (const note of notes) { - notesSelect.options.add(new Option(note.id, note.id)); - } + notes.forEach(({id}) => notesSelect.options.add(new Option(id, id))); // update pin notes icon const notesArePinned = options.pinNotes; @@ -22,7 +20,7 @@ function editNotes(id, name) { if (notes.length || id) { if (!id) id = notes[0].id; let note = notes.find(note => note.id === id); - if (note === undefined) { + if (!note) { if (!name) name = id; note = {id, name, legend: ""}; notes.push(note); @@ -52,17 +50,17 @@ function editNotes(id, name) { modules.editNotes = true; // add listeners - document.getElementById("notesSelect").addEventListener("change", changeElement); - document.getElementById("notesName").addEventListener("input", changeName); - 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 () { + byId("notesSelect").addEventListener("change", changeElement); + byId("notesName").addEventListener("input", changeName); + byId("notesLegend").addEventListener("blur", updateLegend); + byId("notesPin").addEventListener("click", toggleNotesPin); + byId("notesFocus").addEventListener("click", validateHighlightElement); + byId("notesDownload").addEventListener("click", downloadLegends); + byId("notesUpload").addEventListener("click", () => legendsToLoad.click()); + byId("legendsToLoad").addEventListener("change", function () { uploadFile(this, uploadLegends); }); - document.getElementById("notesRemove").addEventListener("click", triggerNotesRemove); + byId("notesRemove").addEventListener("click", triggerNotesRemove); async function initEditor() { if (!window.tinymce) { @@ -108,8 +106,8 @@ function editNotes(id, name) { } function updateNotesBox(note) { - document.getElementById("notesHeader").innerHTML = note.name; - document.getElementById("notesBody").innerHTML = note.legend; + byId("notesHeader").innerHTML = note.name; + byId("notesBody").innerHTML = note.legend; } function changeElement() { @@ -131,7 +129,7 @@ function editNotes(id, name) { } function validateHighlightElement() { - const element = document.getElementById(notesSelect.value); + const element = byId(notesSelect.value); if (element) return highlightElement(element, 3); confirmationDialog({ @@ -157,6 +155,18 @@ function editNotes(id, name) { } function triggerNotesRemove() { + function removeLegend() { + notes = notes.filter(({id}) => id !== notesSelect.value); + + if (!notes.length) { + $("#notesEditor").dialog("close"); + return; + } + + removeEditor(); + editNotes(notes[0].id, notes[0].name); + } + confirmationDialog({ title: "Remove note", message: "Are you sure you want to remove the selected note? There is no way to undo this action", @@ -165,17 +175,6 @@ function editNotes(id, name) { }); } - function removeLegend() { - const index = notes.findIndex(n => n.id === notesSelect.value); - notes.splice(index, 1); - notesSelect.options.length = 0; - if (!notes.length) { - $("#notesEditor").dialog("close"); - return; - } - editNotes(notes[0].id, notes[0].name); - } - function toggleNotesPin() { options.pinNotes = !options.pinNotes; this.classList.toggle("pressed"); diff --git a/modules/ui/options.js b/modules/ui/options.js index dde2e176..2f14d9d7 100644 --- a/modules/ui/options.js +++ b/modules/ui/options.js @@ -20,7 +20,7 @@ function showOptions(event) { } regenerate.style.display = "none"; - document.getElementById("options").style.display = "block"; + byId("options").style.display = "block"; optionsTrigger.style.display = "none"; if (event) event.stopPropagation(); @@ -28,21 +28,21 @@ function showOptions(event) { // Hide options pane on trigger click function hideOptions(event) { - document.getElementById("options").style.display = "none"; + byId("options").style.display = "none"; optionsTrigger.style.display = "block"; if (event) event.stopPropagation(); } // To toggle options on hotkey press function toggleOptions(event) { - if (document.getElementById("options").style.display === "none") showOptions(event); + if (byId("options").style.display === "none") showOptions(event); else hideOptions(event); } // Toggle "New Map!" pane on hover optionsTrigger.addEventListener("mouseenter", function () { if (optionsTrigger.classList.contains("glow")) return; - if (document.getElementById("options").style.display === "none") regenerate.style.display = "block"; + if (byId("options").style.display === "none") regenerate.style.display = "block"; }); collapsible.addEventListener("mouseleave", function () { @@ -56,11 +56,11 @@ document .addEventListener("click", function (event) { if (event.target.tagName !== "BUTTON") return; const id = event.target.id; - const active = document.getElementById("options").querySelector(".tab > button.active"); + const active = byId("options").querySelector(".tab > button.active"); if (active && id === active.id) return; // already active tab is clicked if (active) active.classList.remove("active"); - document.getElementById(id).classList.add("active"); + byId(id).classList.add("active"); document .getElementById("options") .querySelectorAll(".tabcontent") @@ -76,7 +76,7 @@ document // show popup with a list of Patreon supportes (updated manually) async function showSupporters() { - const {supporters} = await import("../dynamic/supporters.js?v=1.93.03"); + const {supporters} = await import("../dynamic/supporters.js?v=1.93.08"); const list = supporters.split("\n").sort(); const columns = window.innerWidth < 800 ? 2 : 5; @@ -91,10 +91,10 @@ async function showSupporters() { } // on any option or dialog change -document.getElementById("options").addEventListener("change", storeValueIfRequired); -document.getElementById("dialogs").addEventListener("change", storeValueIfRequired); -document.getElementById("options").addEventListener("input", updateOutputToFollowInput); -document.getElementById("dialogs").addEventListener("input", updateOutputToFollowInput); +byId("options").addEventListener("change", storeValueIfRequired); +byId("dialogs").addEventListener("change", storeValueIfRequired); +byId("options").addEventListener("input", updateOutputToFollowInput); +byId("dialogs").addEventListener("input", updateOutputToFollowInput); function storeValueIfRequired(ev) { if (ev.target.dataset.stored) lock(ev.target.dataset.stored); @@ -109,16 +109,16 @@ function updateOutputToFollowInput(ev) { // generic case if (id.slice(-5) === "Input") { - const output = document.getElementById(id.slice(0, -5) + "Output"); + const output = byId(id.slice(0, -5) + "Output"); if (output) output.value = value; } else if (id.slice(-6) === "Output") { - const input = document.getElementById(id.slice(0, -6) + "Input"); + const input = byId(id.slice(0, -6) + "Input"); if (input) input.value = value; } } // Option listeners -const optionsContent = document.getElementById("optionsContent"); +const optionsContent = byId("optionsContent"); optionsContent.addEventListener("input", function (event) { const id = event.target.id; const value = event.target.value; @@ -139,7 +139,7 @@ optionsContent.addEventListener("change", function (event) { if (id === "zoomExtentMin" || id === "zoomExtentMax") changeZoomExtent(value); else if (id === "optionsSeed") generateMapWithSeed("seed change"); - else if (id === "uiSizeInput" || id === "uiSizeOutput") changeUIsize(value); + else if (id === "uiSizeInput" || id === "uiSizeOutput") changeUiSize(value); else if (id === "shapeRendering") setRendering(value); else if (id === "yearInput") changeYear(); else if (id === "eraInput") changeEra(); @@ -148,7 +148,7 @@ optionsContent.addEventListener("change", function (event) { optionsContent.addEventListener("click", function (event) { const id = event.target.id; - if (id === "toggleFullscreen") toggleFullscreen(); + if (id === "restoreDefaultCanvasSize") restoreDefaultCanvasSize(); else if (id === "optionsMapHistory") showSeedHistoryDialog(); else if (id === "optionsCopySeed") copyMapURL(); else if (id === "optionsEraRegenerate") regenerateEra(); @@ -165,7 +165,7 @@ function mapSizeInputChange() { const $mapWidthInput = byId("mapWidthInput"); const $mapHeightInput = byId("mapHeightInput"); - changeMapSize(); + fitMapToScreen(); localStorage.setItem("mapWidth", $mapWidthInput.value); localStorage.setItem("mapHeight", $mapHeightInput.value); @@ -173,77 +173,66 @@ function mapSizeInputChange() { const tooHigh = +$mapHeightInput.value > window.innerHeight; if (tooWide || tooHigh) { - const message = `Canvas size is larger than actual window size (${window.innerWidth} x ${window.innerHeight}). It can affect the performance if you are going to create a new map`; + const message = `Canvas size is larger than window size (${window.innerWidth} x ${window.innerHeight}). It can affect performance`; tip(message, false, "warn", 4000); } } -// change svg size on manual size change or window resize, do not change graph size -function changeMapSize() { +function restoreDefaultCanvasSize() { + mapWidthInput.value = window.innerWidth; + mapHeightInput.value = window.innerHeight; + localStorage.removeItem("mapHeight"); + localStorage.removeItem("mapWidth"); + fitMapToScreen(); +} + +// on map creation +function applyGraphSize() { + graphWidth = +mapWidthInput.value; + graphHeight = +mapHeightInput.value; + + landmass.select("rect").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight); + oceanPattern.select("rect").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight); + oceanLayers.select("rect").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight); + fogging.selectAll("rect").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight); + defs.select("mask#fog > rect").attr("width", graphWidth).attr("height", graphHeight); + defs.select("mask#water > rect").attr("width", graphWidth).attr("height", graphHeight); +} + +// on generate, on load, on resize, on canvas size change +function fitMapToScreen() { svgWidth = Math.min(+mapWidthInput.value, window.innerWidth); svgHeight = Math.min(+mapHeightInput.value, window.innerHeight); svg.attr("width", svgWidth).attr("height", svgHeight); - const maxWidth = Math.max(+mapWidthInput.value, graphWidth); - const maxHeight = Math.max(+mapHeightInput.value, graphHeight); - zoom.translateExtent([ + const zoomExtent = [ [0, 0], - [maxWidth, maxHeight] - ]); - landmass.select("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight); - oceanPattern.select("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight); - oceanLayers.select("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight); - fogging.selectAll("rect").attr("x", 0).attr("y", 0).attr("width", maxWidth).attr("height", maxHeight); - defs.select("mask#fog > rect").attr("width", maxWidth).attr("height", maxHeight); - texture.select("image").attr("width", maxWidth).attr("height", maxHeight); + [graphWidth, graphHeight] + ]; - fitScaleBar(); - if (window.fitLegendBox) fitLegendBox(); -} - -// just apply canvas size that was already set -function applyMapSize() { - const zoomMin = +zoomExtentMin.value; + const zoomMin = rn(Math.max(svgWidth / graphWidth, svgHeight / graphHeight), 3); + zoomExtentMin.value = zoomMin; const zoomMax = +zoomExtentMax.value; - graphWidth = +mapWidthInput.value; - graphHeight = +mapHeightInput.value; - svgWidth = Math.min(graphWidth, window.innerWidth); - svgHeight = Math.min(graphHeight, window.innerHeight); - svg.attr("width", svgWidth).attr("height", svgHeight); - zoom - .translateExtent([ - [0, 0], - [graphWidth, graphHeight] - ]) - .scaleExtent([zoomMin, zoomMax]) - .scaleTo(svg, zoomMin); -} -function toggleFullscreen() { - if (mapWidthInput.value != window.innerWidth || mapHeightInput.value != window.innerHeight) { - mapWidthInput.value = window.innerWidth; - mapHeightInput.value = window.innerHeight; - localStorage.removeItem("mapHeight"); - localStorage.removeItem("mapWidth"); - } else { - mapWidthInput.value = graphWidth; - mapHeightInput.value = graphHeight; - } - changeMapSize(); + zoom.translateExtent(zoomExtent).scaleExtent([zoomMin, zoomMax]).scaleTo(svg, zoomMin); + + fitScaleBar(scaleBar, svgWidth, svgHeight); + if (window.fitLegendBox) fitLegendBox(); } function toggleTranslateExtent(el) { const on = (el.dataset.on = +!+el.dataset.on); - if (on) + if (on) { zoom.translateExtent([ [-graphWidth / 2, -graphHeight / 2], [graphWidth * 1.5, graphHeight * 1.5] ]); - else + } else { zoom.translateExtent([ [0, 0], [graphWidth, graphHeight] ]); + } } // add voice options @@ -252,7 +241,7 @@ const voiceInterval = setInterval(function () { if (voices.length) clearInterval(voiceInterval); else return; - const select = document.getElementById("speakerVoice"); + const select = byId("speakerVoice"); voices.forEach((voice, i) => { select.options.add(new Option(voice.name, i, false)); }); @@ -266,7 +255,7 @@ function testSpeaker() { const speaker = new SpeechSynthesisUtterance(text); const voices = speechSynthesis.getVoices(); if (voices.length) { - const voiceId = +document.getElementById("speakerVoice").value; + const voiceId = +byId("speakerVoice").value; speaker.voice = voices[voiceId]; } speechSynthesis.speak(speaker); @@ -307,12 +296,6 @@ function restoreSeed(id) { regeneratePrompt({seed}); } -function restoreDefaultZoomExtent() { - zoomExtentMin.value = 1; - zoomExtentMax.value = 20; - zoom.scaleExtent([1, 20]).scaleTo(svg, 1); -} - function copyMapURL() { const locked = document.querySelectorAll("i.icon-lock").length; // check if some options are locked const search = `?seed=${optionsSeed.value}&width=${graphWidth}&height=${graphHeight}${ @@ -365,7 +348,7 @@ function changeCultureSet() { } function changeEmblemShape(emblemShape) { - const image = document.getElementById("emblemShapeImage"); + const image = byId("emblemShapeImage"); const shapePath = window.COArenderer && COArenderer.shieldPaths[emblemShape]; shapePath ? image.setAttribute("d", shapePath) : image.removeAttribute("d"); @@ -374,7 +357,7 @@ function changeEmblemShape(emblemShape) { pack.cultures.filter(c => !c.removed).forEach(c => (c.shield = Cultures.getRandomShield())); const rerenderCOA = (id, coa) => { - const coaEl = document.getElementById(id); + const coaEl = byId(id); if (!coaEl) return; // not rendered coaEl.remove(); COArenderer.trigger(id, coa); @@ -412,7 +395,7 @@ function changeStatesNumber(value) { labels.select("#countries").attr("data-size", Math.max(rn(18 - value / 6), 4)); } -function changeUIsize(value) { +function changeUiSize(value) { if (isNaN(+value) || +value < 0.5) return; const max = getUImaxSize(); @@ -420,7 +403,7 @@ function changeUIsize(value) { uiSizeInput.value = uiSizeOutput.value = value; document.getElementsByTagName("body")[0].style.fontSize = rn(value * 10, 2) + "px"; - document.getElementById("options").style.width = value * 300 + "px"; + byId("options").style.width = value * 300 + "px"; } function getUImaxSize() { @@ -480,7 +463,7 @@ function loadGoogleTranslate() { const script = document.createElement("script"); script.src = "https://translate.google.com/translate_a/element.js?cb=initGoogleTranslate"; script.onload = () => { - document.getElementById("loadGoogleTranslateButton")?.remove(); + byId("loadGoogleTranslateButton")?.remove(); // replace mapLayers underline with bare text to avoid translation issue document @@ -527,6 +510,12 @@ function changeZoomExtent(value) { zoom.scaleTo(svg, scale); } +function restoreDefaultZoomExtent() { + zoomExtentMin.value = 1; + zoomExtentMax.value = 20; + zoom.scaleExtent([1, 20]).scaleTo(svg, 1); +} + // restore options stored in localStorage function applyStoredOptions() { if (!stored("mapWidth") || !stored("mapHeight")) { @@ -569,8 +558,8 @@ function applyStoredOptions() { if (stored("regions")) changeStatesNumber(stored("regions")); uiSizeInput.max = uiSizeOutput.max = getUImaxSize(); - if (stored("uiSize")) changeUIsize(stored("uiSize")); - else changeUIsize(minmax(rn(mapWidthInput.value / 1280, 1), 1, 2.5)); + if (stored("uiSize")) changeUiSize(stored("uiSize")); + else changeUiSize(minmax(rn(mapWidthInput.value / 1280, 1), 1, 2.5)); // search params overwrite stored and default options const params = new URL(window.location.href).searchParams; @@ -702,7 +691,7 @@ function changeEra() { } async function openTemplateSelectionDialog() { - const HeightmapSelectionDialog = await import("../dynamic/heightmap-selection.js?v=1.87.00"); + const HeightmapSelectionDialog = await import("../dynamic/heightmap-selection.js?v=1.96.00"); HeightmapSelectionDialog.open(); } @@ -713,7 +702,7 @@ function restoreDefaultOptions() { } // Sticked menu Options listeners -document.getElementById("sticked").addEventListener("click", function (event) { +byId("sticked").addEventListener("click", function (event) { const id = event.target.id; if (id === "newMapButton") regeneratePrompt(); else if (id === "saveButton") showSavePane(); @@ -746,7 +735,7 @@ function regeneratePrompt(options) { } function showSavePane() { - const sharableLinkContainer = document.getElementById("sharableLinkContainer"); + const sharableLinkContainer = byId("sharableLinkContainer"); sharableLinkContainer.style.display = "none"; $("#saveMapData").dialog({ @@ -763,13 +752,13 @@ function showSavePane() { } function copyLinkToClickboard() { - const shrableLink = document.getElementById("sharableLink"); + const shrableLink = byId("sharableLink"); const link = shrableLink.getAttribute("href"); navigator.clipboard.writeText(link).then(() => tip("Link is copied to the clipboard", true, "success", 8000)); } function showExportPane() { - document.getElementById("showLabels").checked = !hideLabels.checked; + byId("showLabels").checked = !hideLabels.checked; $("#exportMapData").dialog({ title: "Export map data", @@ -785,7 +774,7 @@ function showExportPane() { } async function exportToJson(type) { - const {exportToJson} = await import("../dynamic/export-json.js?v=1.93.03"); + const {exportToJson} = await import("../dynamic/export-json.js?v=1.96.00"); exportToJson(type); } @@ -804,10 +793,10 @@ async function showLoadPane() { // 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"); + byId("dropboxConnectButton").style.display = "none"; + byId("loadFromDropboxSelect").style.display = "block"; + const loadFromDropboxButtons = byId("loadFromDropboxButtons"); + const fileSelect = byId("loadFromDropboxSelect"); fileSelect.innerHTML = /* html */ ``; const files = await Cloud.providers.dropbox.list(); @@ -832,9 +821,9 @@ async function showLoadPane() { } // 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"; + byId("dropboxConnectButton").style.display = "inline-block"; + byId("loadFromDropboxButtons").style.display = "none"; + byId("loadFromDropboxSelect").style.display = "none"; } async function connectToDropbox() { @@ -870,38 +859,27 @@ function loadURL() { } // load map -document.getElementById("mapToLoad").addEventListener("change", function () { +byId("mapToLoad").addEventListener("change", function () { const fileToLoad = this.files[0]; this.value = ""; closeDialogs(); uploadMap(fileToLoad); }); -function openSaveTiles() { +function openExportToPngTiles() { + byId("tileStatus").innerHTML = ""; closeDialogs(); updateTilesOptions(); - const status = document.getElementById("tileStatus"); - status.innerHTML = ""; - let loading = null; - const inputs = document.getElementById("saveTilesScreen").querySelectorAll("input"); + const inputs = byId("exportToPngTilesScreen").querySelectorAll("input"); inputs.forEach(input => input.addEventListener("input", updateTilesOptions)); - $("#saveTilesScreen").dialog({ + $("#exportToPngTilesScreen").dialog({ resizable: false, title: "Download tiles", width: "23em", buttons: { - Download: function () { - status.innerHTML = "Preparing for download..."; - setTimeout(() => (status.innerHTML = "Downloading. It may take some time."), 1000); - loading = setInterval(() => (status.innerHTML += "."), 1000); - saveTiles().then(() => { - clearInterval(loading); - status.innerHTML = /* html */ `Done. Check file in "Downloads" (crtl + J)`; - setTimeout(() => (status.innerHTML = ""), 8000); - }); - }, + Download: () => exportToPngTiles(), Cancel: function () { $(this).dialog("close"); } @@ -909,7 +887,6 @@ function openSaveTiles() { close: () => { inputs.forEach(input => input.removeEventListener("input", updateTilesOptions)); debug.selectAll("*").remove(); - clearInterval(loading); } }); } @@ -921,10 +898,10 @@ function updateTilesOptions() { if (prev?.tagName === "INPUT") prev.value = this.value; } - const tileSize = document.getElementById("tileSize"); - const tilesX = +document.getElementById("tileColsOutput").value; - const tilesY = +document.getElementById("tileRowsOutput").value; - const scale = +document.getElementById("tileScaleOutput").value; + const tileSize = byId("tileSize"); + const tilesX = +byId("tileColsOutput").value; + const tilesY = +byId("tileRowsOutput").value; + const scale = +byId("tileScaleOutput").value; // calculate size const sizeX = graphWidth * scale * tilesX; @@ -939,18 +916,22 @@ function updateTilesOptions() { const labels = []; const tileW = (graphWidth / tilesX) | 0; const tileH = (graphHeight / tilesY) | 0; - for (let y = 0, i = 0; y + tileH <= graphHeight; y += tileH) { - for (let x = 0; x + tileW <= graphWidth; x += tileW, i++) { + + const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + for (let y = 0, row = 0; y + tileH <= graphHeight; y += tileH, row++) { + for (let x = 0, column = 1; x + tileW <= graphWidth; x += tileW, column++) { rects.push(``); - labels.push(`${i}`); + const label = alphabet[row % alphabet.length] + column; + labels.push(`${label}`); } } - const rectsG = "" + rects.join("") + ""; - const labelsG = - "" + - labels.join("") + - ""; - debug.html(rectsG + labelsG); + + debug.html(` + ${rects.join("")} + ${labels.join( + "" + )} + `); } // View mode @@ -973,9 +954,9 @@ function enterStandardView() { heightmap3DView.classList.remove("pressed"); viewStandard.classList.add("pressed"); - if (!document.getElementById("canvas3d")) return; + if (!byId("canvas3d")) return; ThreeD.stop(); - document.getElementById("canvas3d").remove(); + byId("canvas3d").remove(); if (options3dUpdate.offsetParent) $("#options3d").dialog("close"); if (preview3d.offsetParent) $("#preview3d").dialog("close"); } @@ -1002,13 +983,13 @@ async function enter3dView(type) { canvas.style.display = "block"; canvas.onmouseenter = () => { const help = - "Left mouse to change angle, middle mouse / mousewheel to zoom, right mouse to pan. O to toggle options"; + "Left mouse to change angle, middle mouse. Mousewheel to zoom. Right mouse or hold Shift to pan. O to toggle options"; +canvas.dataset.hovered > 2 ? tip("") : tip(help); canvas.dataset.hovered = (+canvas.dataset.hovered | 0) + 1; }; if (type === "heightmap3DView") { - document.getElementById("preview3d").appendChild(canvas); + byId("preview3d").appendChild(canvas); $("#preview3d").dialog({ title: "3D Preview", resizable: true, @@ -1022,7 +1003,7 @@ async function enter3dView(type) { } function resize3d() { - const canvas = document.getElementById("canvas3d"); + const canvas = byId("canvas3d"); canvas.width = parseFloat(preview3d.style.width); canvas.height = parseFloat(preview3d.style.height) - 2; ThreeD.redraw(); @@ -1045,33 +1026,32 @@ function toggle3dOptions() { if (modules.options3d) return; modules.options3d = true; - document.getElementById("options3dUpdate").addEventListener("click", ThreeD.update); - document.getElementById("options3dSave").addEventListener("click", ThreeD.saveScreenshot); - document.getElementById("options3dOBJSave").addEventListener("click", ThreeD.saveOBJ); + byId("options3dUpdate").addEventListener("click", ThreeD.update); + byId("options3dSave").addEventListener("click", ThreeD.saveScreenshot); + byId("options3dOBJSave").addEventListener("click", ThreeD.saveOBJ); - document.getElementById("options3dScaleRange").addEventListener("input", changeHeightScale); - document.getElementById("options3dScaleNumber").addEventListener("change", changeHeightScale); - document.getElementById("options3dLightnessRange").addEventListener("input", changeLightness); - document.getElementById("options3dLightnessNumber").addEventListener("change", changeLightness); - document.getElementById("options3dSunX").addEventListener("change", changeSunPosition); - document.getElementById("options3dSunY").addEventListener("change", changeSunPosition); - document.getElementById("options3dSunZ").addEventListener("change", changeSunPosition); - document.getElementById("options3dMeshSkinResolution").addEventListener("change", changeResolutionScale); - document.getElementById("options3dMeshRotationRange").addEventListener("input", changeRotation); - document.getElementById("options3dMeshRotationNumber").addEventListener("change", changeRotation); - document.getElementById("options3dGlobeRotationRange").addEventListener("input", changeRotation); - document.getElementById("options3dGlobeRotationNumber").addEventListener("change", changeRotation); - document.getElementById("options3dMeshLabels3d").addEventListener("change", toggleLabels3d); - document.getElementById("options3dMeshSkyMode").addEventListener("change", toggleSkyMode); - document.getElementById("options3dMeshSky").addEventListener("input", changeColors); - document.getElementById("options3dMeshWater").addEventListener("input", changeColors); - document.getElementById("options3dGlobeResolution").addEventListener("change", changeResolution); - // document.getElementById("options3dMeshWireframeMode").addEventListener("change",toggleWireframe3d); - document.getElementById("options3dSunColor").addEventListener("input", changeSunColor); - document.getElementById("options3dSubdivide").addEventListener("change", toggle3dSubdivision); + byId("options3dScaleRange").addEventListener("input", changeHeightScale); + byId("options3dScaleNumber").addEventListener("change", changeHeightScale); + byId("options3dLightnessRange").addEventListener("input", changeLightness); + byId("options3dLightnessNumber").addEventListener("change", changeLightness); + byId("options3dSunX").addEventListener("change", changeSunPosition); + byId("options3dSunY").addEventListener("change", changeSunPosition); + byId("options3dMeshSkinResolution").addEventListener("change", changeResolutionScale); + byId("options3dMeshRotationRange").addEventListener("input", changeRotation); + byId("options3dMeshRotationNumber").addEventListener("change", changeRotation); + byId("options3dGlobeRotationRange").addEventListener("input", changeRotation); + byId("options3dGlobeRotationNumber").addEventListener("change", changeRotation); + byId("options3dMeshLabels3d").addEventListener("change", toggleLabels3d); + byId("options3dMeshSkyMode").addEventListener("change", toggleSkyMode); + byId("options3dMeshSky").addEventListener("input", changeColors); + byId("options3dMeshWater").addEventListener("input", changeColors); + byId("options3dGlobeResolution").addEventListener("change", changeResolution); + // byId("options3dMeshWireframeMode").addEventListener("change",toggleWireframe3d); + byId("options3dSunColor").addEventListener("input", changeSunColor); + byId("options3dSubdivide").addEventListener("change", toggle3dSubdivision); function updateValues() { - const globe = document.getElementById("canvas3d").dataset.type === "viewGlobe"; + const globe = byId("canvas3d").dataset.type === "viewGlobe"; options3dMesh.style.display = globe ? "none" : "block"; options3dGlobe.style.display = globe ? "block" : "none"; options3dOBJSave.style.display = globe ? "none" : "inline-block"; @@ -1079,7 +1059,6 @@ function toggle3dOptions() { options3dLightnessRange.value = options3dLightnessNumber.value = ThreeD.options.lightness * 100; options3dSunX.value = ThreeD.options.sun.x; options3dSunY.value = ThreeD.options.sun.y; - options3dSunZ.value = ThreeD.options.sun.z; options3dMeshRotationRange.value = options3dMeshRotationNumber.value = ThreeD.options.rotateMesh; options3dMeshSkinResolution.value = ThreeD.options.resolutionScale; options3dGlobeRotationRange.value = options3dGlobeRotationNumber.value = ThreeD.options.rotateGlobe; @@ -1115,8 +1094,7 @@ function toggle3dOptions() { function changeSunPosition() { const x = +options3dSunX.value; const y = +options3dSunY.value; - const z = +options3dSunZ.value; - ThreeD.setSun(x, y, z); + ThreeD.setSun(x, y); } function changeRotation() { diff --git a/modules/ui/provinces-editor.js b/modules/ui/provinces-editor.js index 07ee522d..a9a2dfa0 100644 --- a/modules/ui/provinces-editor.js +++ b/modules/ui/provinces-editor.js @@ -44,12 +44,14 @@ function editProvinces() { cl = el.classList, line = el.parentNode, p = +line.dataset.id; + const stateId = pack.provinces[p].state; 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); else if (cl.contains("icon-flag-empty")) triggerIndependencePromps(p); + else if (cl.contains("icon-dot-circled")) overviewBurgs({stateId}); else if (cl.contains("culturePopulation")) changePopulation(p); else if (cl.contains("icon-pin")) toggleFog(p, cl); else if (cl.contains("icon-trash-empty")) removeProvince(p); @@ -71,9 +73,8 @@ function editProvinces() { } function collectStatistics() { - const cells = pack.cells, - provinces = pack.provinces, - burgs = pack.burgs; + const {cells, provinces, burgs} = pack; + provinces.forEach(p => { if (!p.i || p.removed) return; p.area = p.rural = p.urban = 0; @@ -107,16 +108,18 @@ function editProvinces() { statesSorted.forEach(s => stateFilter.options.add(new Option(s.name, s.i, false, s.i == selectedState))); } - // add line for each state + // add line for each province function provincesEditorAddLines() { const unit = " " + getAreaUnit(); const selectedState = +document.getElementById("provincesFilterState").value; let filtered = pack.provinces.filter(p => p.i && !p.removed); // all valid burgs if (selectedState != -1) filtered = filtered.filter(p => p.state === selectedState); // filtered by state body.innerHTML = ""; - let lines = "", - totalArea = 0, - totalPopulation = 0; + + let lines = ""; + let totalArea = 0; + let totalPopulation = 0; + let totalBurgs = 0; for (const p of filtered) { const area = getArea(p.area); @@ -128,6 +131,7 @@ function editProvinces() { rural )}; Urban population: ${si(urban)}`; totalPopulation += population; + totalBurgs += p.burgs.length; const stateName = pack.states[p.state].name; const capital = p.burg ? pack.burgs[p.burg].name : ""; @@ -144,6 +148,7 @@ function editProvinces() { data-state="${stateName}" data-area=${area} data-population=${population} + data-burgs=${p.burgs.length} > @@ -163,6 +168,8 @@ function editProvinces() { ${p.burgs.length ? getCapitalOptions(p.burgs, p.burg) : ""} + +
    ${p.burgs.length}
    ${si(area) + unit}
    @@ -179,11 +186,12 @@ function editProvinces() { body.innerHTML = lines; // update footer - provincesFooterNumber.innerHTML = filtered.length; - provincesFooterArea.innerHTML = filtered.length ? si(totalArea / filtered.length) + unit : 0 + unit; - provincesFooterPopulation.innerHTML = filtered.length ? si(totalPopulation / filtered.length) : 0; - provincesFooterArea.dataset.area = totalArea; - provincesFooterPopulation.dataset.population = totalPopulation; + byId("provincesFooterNumber").innerHTML = filtered.length; + byId("provincesFooterBurgs").innerHTML = totalBurgs; + byId("provincesFooterArea").innerHTML = filtered.length ? si(totalArea / filtered.length) + unit : 0 + unit; + byId("provincesFooterPopulation").innerHTML = filtered.length ? si(totalPopulation / filtered.length) : 0; + byId("provincesFooterArea").dataset.area = totalArea; + byId("provincesFooterPopulation").dataset.population = totalPopulation; body.querySelectorAll("div.states").forEach(el => { el.addEventListener("click", selectProvinceOnLineClick); @@ -294,7 +302,7 @@ function editProvinces() { // move all burgs to a new state province.burgs.forEach(b => (burgs[b].state = newStateId)); - // difine new state attributes + // define new state attributes const {cell: center, culture} = burgs[burgId]; const color = getRandomColor(); const coa = province.coa; @@ -501,6 +509,9 @@ function editProvinces() { applyOption(provinceNameEditorSelectForm, p.formName); document.getElementById("provinceNameEditorFull").value = p.fullName; + const cultureId = pack.cells.culture[p.center]; + document.getElementById("provinceCultureDisplay").innerText = pack.cultures[cultureId].name; + $("#provinceNameEditor").dialog({ resizable: false, title: "Change province name", @@ -520,12 +531,12 @@ function editProvinces() { modules.editProvinceName = true; // add listeners - document.getElementById("provinceNameEditorShortCulture").addEventListener("click", regenerateShortNameCuture); + document.getElementById("provinceNameEditorShortCulture").addEventListener("click", regenerateShortNameCulture); document.getElementById("provinceNameEditorShortRandom").addEventListener("click", regenerateShortNameRandom); document.getElementById("provinceNameEditorAddForm").addEventListener("click", addCustomForm); document.getElementById("provinceNameEditorFullRegenerate").addEventListener("click", regenerateFullName); - function regenerateShortNameCuture() { + function regenerateShortNameCulture() { const province = +provinceNameEditor.dataset.province; const culture = pack.cells.culture[pack.provinces[province].center]; const name = Names.getState(Names.getCultureShort(culture), culture); @@ -576,12 +587,15 @@ function editProvinces() { function togglePercentageMode() { if (body.dataset.type === "absolute") { body.dataset.type = "percentage"; + const totalBurgs = +byId("provincesFooterBurgs").innerText; const totalArea = +provincesFooterArea.dataset.area; const totalPopulation = +provincesFooterPopulation.dataset.population; body.querySelectorAll(":scope > div").forEach(function (el) { - el.querySelector(".biomeArea").innerHTML = rn((+el.dataset.area / totalArea) * 100) + "%"; - el.querySelector(".culturePopulation").innerHTML = rn((+el.dataset.population / totalPopulation) * 100) + "%"; + const {cells, burgs, area, population} = el.dataset; + el.querySelector(".provinceBurgs").innerText = rn((+burgs / totalBurgs) * 100) + "%"; + el.querySelector(".biomeArea").innerHTML = rn((+area / totalArea) * 100) + "%"; + el.querySelector(".culturePopulation").innerHTML = rn((+population / totalPopulation) * 100) + "%"; }); } else { body.dataset.type = "absolute"; @@ -1064,10 +1078,7 @@ function editProvinces() { function downloadProvincesData() { const unit = areaUnit.value === "square" ? distanceUnitInput.value + "2" : areaUnit.value; - let data = - "Id,Province,Full Name,Form,State,Color,Capital,Area " + - unit + - ",Total Population,Rural Population,Urban Population\n"; // headers + let data = `Id,Province,Full Name,Form,State,Color,Capital,Area ${unit},Total Population,Rural Population,Urban Population,Burgs\n`; // headers body.querySelectorAll(":scope > div").forEach(function (el) { const key = parseInt(el.dataset.id); @@ -1081,8 +1092,9 @@ function editProvinces() { data += el.dataset.capital + ","; data += el.dataset.area + ","; data += el.dataset.population + ","; - data += `${Math.round(provincePack.rural * populationRate)},`; - data += `${Math.round(provincePack.urban * populationRate * urbanization)}\n`; + data += Math.round(provincePack.rural * populationRate) + ","; + data += Math.round(provincePack.urban * populationRate * urbanization) + ","; + data += el.dataset.burgs + "\n"; }); const name = getFileName("Provinces") + ".csv"; diff --git a/modules/ui/style.js b/modules/ui/style.js index 94331a11..67e87928 100644 --- a/modules/ui/style.js +++ b/modules/ui/style.js @@ -3,7 +3,7 @@ // add available filters to lists { - const filters = Array.from(document.getElementById("filters").querySelectorAll("filter")); + const filters = Array.from(byId("filters").querySelectorAll("filter")); const emptyOption = ''; const options = filters.map(filter => { const id = filter.getAttribute("id"); @@ -12,8 +12,9 @@ }); const allOptions = emptyOption + options.join(""); - document.getElementById("styleFilterInput").innerHTML = allOptions; - document.getElementById("styleStatesBodyFilter").innerHTML = allOptions; + byId("styleFilterInput").innerHTML = allOptions; + byId("styleStatesBodyFilter").innerHTML = allOptions; + byId("styleScaleBarBackgroundFilter").innerHTML = allOptions; } // store some style inputs as options @@ -31,45 +32,77 @@ function editStyle(element, group) { styleElementSelect.classList.add("glow"); if (group) styleGroupSelect.classList.add("glow"); + setTimeout(() => { styleElementSelect.classList.remove("glow"); if (group) styleGroupSelect.classList.remove("glow"); }, 1500); } +// Color schemes +const heightmapColorSchemes = { + bright: d3.scaleSequential(d3.interpolateSpectral), + light: d3.scaleSequential(d3.interpolateRdYlGn), + natural: d3.scaleSequential(d3.interpolateRgbBasis(["white", "#EEEECC", "tan", "green", "teal"])), + green: d3.scaleSequential(d3.interpolateGreens), + olive: d3.scaleSequential(d3.interpolateRgbBasis(["#ffffff", "#cea48d", "#d5b085", "#0c2c19", "#151320"])), + livid: d3.scaleSequential(d3.interpolateRgbBasis(["#BBBBDD", "#2A3440", "#17343B", "#0A1E24"])), + monochrome: d3.scaleSequential(d3.interpolateGreys) +}; + +// add default color schemes to the list of options +byId("styleHeightmapScheme").innerHTML = Object.keys(heightmapColorSchemes) + .map(scheme => ``) + .join(""); + +function addCustomColorScheme(scheme) { + const stops = scheme.split(","); + heightmapColorSchemes[scheme] = d3.scaleSequential(d3.interpolateRgbBasis(stops)); + byId("styleHeightmapScheme").options.add(new Option(scheme, scheme, false, true)); +} + +function getColorScheme(scheme = "bright") { + if (!(scheme in heightmapColorSchemes)) { + const colors = scheme.split(","); + heightmapColorSchemes[scheme] = d3.scaleSequential(d3.interpolateRgbBasis(colors)); + } + + return heightmapColorSchemes[scheme]; +} + // Toggle style sections on element select styleElementSelect.addEventListener("change", selectStyleElement); function selectStyleElement() { - const sel = styleElementSelect.value; - let el = d3.select("#" + sel); + const styleElement = styleElementSelect.value; + let el = d3.select("#" + styleElement); styleElements.querySelectorAll("tbody").forEach(e => (e.style.display = "none")); // hide all sections // show alert line if layer is not visible - const isLayerOff = sel !== "ocean" && (el.style("display") === "none" || !el.selectAll("*").size()); + const isLayerOff = styleElement !== "ocean" && (el.style("display") === "none" || !el.selectAll("*").size()); styleIsOff.style.display = isLayerOff ? "block" : "none"; // active group element - const group = styleGroupSelect.value; - if (["routes", "labels", "coastline", "lakes", "anchors", "burgIcons", "borders"].includes(sel)) { - const gEl = group && el.select("#" + group); - el = group && gEl.size() ? gEl : el.select("g"); + if (["routes", "labels", "coastline", "lakes", "anchors", "burgIcons", "borders", "terrs"].includes(styleElement)) { + const group = styleGroupSelect.value; + const defaultGroupSelector = styleElement === "terrs" ? "#landHeights" : "g"; + el = group && el.select("#" + group).size() ? el.select("#" + group) : el.select(defaultGroupSelector); } // opacity - if (!["landmass", "ocean", "regions", "legend"].includes(sel)) { + if (!["landmass", "ocean", "regions", "legend"].includes(styleElement)) { styleOpacity.style.display = "block"; styleOpacityInput.value = styleOpacityOutput.value = el.attr("opacity") || 1; } // filter - if (!["landmass", "legend", "regions"].includes(sel)) { + if (!["landmass", "legend", "regions", "scaleBar"].includes(styleElement)) { styleFilter.style.display = "block"; styleFilterInput.value = el.attr("filter") || ""; } // fill - if (["rivers", "lakes", "landmass", "prec", "ice", "fogging"].includes(sel)) { + if (["rivers", "lakes", "landmass", "prec", "ice", "fogging", "scaleBar", "vignette"].includes(styleElement)) { styleFill.style.display = "block"; styleFillInput.value = styleFillOutput.value = el.attr("fill"); } @@ -91,7 +124,7 @@ function selectStyleElement() { "coordinates", "zones", "gridOverlay" - ].includes(sel) + ].includes(styleElement) ) { styleStroke.style.display = "block"; styleStrokeInput.value = styleStrokeOutput.value = el.attr("stroke"); @@ -101,7 +134,9 @@ function selectStyleElement() { // stroke dash if ( - ["routes", "borders", "temperature", "legend", "population", "coordinates", "zones", "gridOverlay"].includes(sel) + ["routes", "borders", "temperature", "legend", "population", "coordinates", "zones", "gridOverlay"].includes( + styleElement + ) ) { styleStrokeDash.style.display = "block"; styleStrokeDasharrayInput.value = el.attr("stroke-dasharray") || ""; @@ -121,30 +156,38 @@ function selectStyleElement() { "texture", "biomes", "zones" - ].includes(sel) + ].includes(styleElement) ) { styleClipping.style.display = "block"; styleClippingInput.value = el.attr("mask") || ""; } // show specific sections - if (sel === "texture") styleTexture.style.display = "block"; - - if (sel === "terrs") { - styleHeightmap.style.display = "block"; - styleHeightmapScheme.value = terrs.attr("scheme"); - styleHeightmapTerracingInput.value = styleHeightmapTerracingOutput.value = terrs.attr("terracing"); - styleHeightmapSkipInput.value = styleHeightmapSkipOutput.value = terrs.attr("skip"); - styleHeightmapSimplificationInput.value = styleHeightmapSimplificationOutput.value = terrs.attr("relax"); - styleHeightmapCurve.value = terrs.attr("curve"); + if (styleElement === "texture") { + styleTexture.style.display = "block"; + styleTextureShiftX.value = el.attr("data-x") || 0; + styleTextureShiftY.value = el.attr("data-y") || 0; + updateTextureSelectValue(el.attr("data-href")); } - if (sel === "markers") { + if (styleElement === "terrs") { + styleHeightmap.style.display = "block"; + styleHeightmapRenderOceanOption.style.display = el.attr("id") === "oceanHeights" ? "block" : "none"; + styleHeightmapRenderOcean.checked = +el.attr("data-render"); + + styleHeightmapScheme.value = el.attr("scheme"); + styleHeightmapTerracingInput.value = styleHeightmapTerracingOutput.value = el.attr("terracing"); + styleHeightmapSkipInput.value = styleHeightmapSkipOutput.value = el.attr("skip"); + styleHeightmapSimplificationInput.value = styleHeightmapSimplificationOutput.value = el.attr("relax"); + styleHeightmapCurve.value = el.attr("curve"); + } + + if (styleElement === "markers") { styleMarkers.style.display = "block"; styleRescaleMarkers.checked = +markers.attr("rescale"); } - if (sel === "gridOverlay") { + if (styleElement === "gridOverlay") { styleGrid.style.display = "block"; styleGridType.value = el.attr("type"); styleGridScale.value = el.attr("scale") || 1; @@ -153,7 +196,7 @@ function selectStyleElement() { calculateFriendlyGridSize(); } - if (sel === "compass") { + if (styleElement === "compass") { styleCompass.style.display = "block"; const tr = parseTransform(compass.select("use").attr("transform")); styleCompassShiftX.value = tr[0]; @@ -161,14 +204,14 @@ function selectStyleElement() { styleCompassSizeInput.value = styleCompassSizeOutput.value = tr[2]; } - if (sel === "terrain") { + if (styleElement === "terrain") { styleRelief.style.display = "block"; styleReliefSizeOutput.innerHTML = styleReliefSizeInput.value = terrain.attr("size"); styleReliefDensityOutput.innerHTML = styleReliefDensityInput.value = terrain.attr("density"); styleReliefSet.value = terrain.attr("set"); } - if (sel === "population") { + if (styleElement === "population") { stylePopulation.style.display = "block"; stylePopulationRuralStrokeInput.value = stylePopulationRuralStrokeOutput.value = population .select("#rural") @@ -180,7 +223,7 @@ function selectStyleElement() { styleStrokeWidthInput.value = styleStrokeWidthOutput.value = el.attr("stroke-width") || ""; } - if (sel === "regions") { + if (styleElement === "regions") { styleStates.style.display = "block"; styleStatesBodyOpacity.value = styleStatesBodyOpacityOutput.value = statesBody.attr("opacity") || 1; styleStatesBodyFilter.value = statesBody.attr("filter") || ""; @@ -190,7 +233,7 @@ function selectStyleElement() { styleStatesHaloBlur.value = styleStatesHaloBlurOutput.value = blur; } - if (sel === "labels") { + if (styleElement === "labels") { styleFill.style.display = "block"; styleStroke.style.display = "block"; styleStrokeWidth.style.display = "block"; @@ -208,7 +251,7 @@ function selectStyleElement() { styleFontSize.value = el.attr("data-size"); } - if (sel === "provs") { + if (styleElement === "provs") { styleFill.style.display = "block"; styleSize.style.display = "block"; styleFillInput.value = styleFillOutput.value = el.attr("fill") || "#111111"; @@ -218,7 +261,7 @@ function selectStyleElement() { styleFontSize.value = el.attr("data-size"); } - if (sel == "burgIcons") { + if (styleElement == "burgIcons") { styleFill.style.display = "block"; styleStroke.style.display = "block"; styleStrokeWidth.style.display = "block"; @@ -232,7 +275,7 @@ function selectStyleElement() { styleRadiusInput.value = el.attr("size") || 1; } - if (sel == "anchors") { + if (styleElement == "anchors") { styleFill.style.display = "block"; styleStroke.style.display = "block"; styleStrokeWidth.style.display = "block"; @@ -243,7 +286,7 @@ function selectStyleElement() { styleIconSizeInput.value = el.attr("size") || 2; } - if (sel === "legend") { + if (styleElement === "legend") { styleStroke.style.display = "block"; styleStrokeWidth.style.display = "block"; styleSize.style.display = "block"; @@ -261,16 +304,16 @@ function selectStyleElement() { styleFontSize.value = el.attr("data-size"); } - if (sel === "ocean") { + if (styleElement === "ocean") { styleOcean.style.display = "block"; styleOceanFill.value = styleOceanFillOutput.value = oceanLayers.select("#oceanBase").attr("fill"); - styleOceanPattern.value = document.getElementById("oceanicPattern")?.getAttribute("href"); + styleOceanPattern.value = byId("oceanicPattern")?.getAttribute("href"); styleOceanPatternOpacity.value = styleOceanPatternOpacityOutput.value = - document.getElementById("oceanicPattern").getAttribute("opacity") || 1; + byId("oceanicPattern").getAttribute("opacity") || 1; outlineLayers.value = oceanLayers.attr("layers"); } - if (sel === "temperature") { + if (styleElement === "temperature") { styleStrokeWidth.style.display = "block"; styleTemperature.style.display = "block"; styleStrokeWidthInput.value = styleStrokeWidthOutput.value = el.attr("stroke-width") || ""; @@ -279,18 +322,18 @@ function selectStyleElement() { styleTemperatureFontSizeInput.value = styleTemperatureFontSizeOutput.value = el.attr("font-size") || "8px"; } - if (sel === "coordinates") { + if (styleElement === "coordinates") { styleSize.style.display = "block"; styleFontSize.value = el.attr("data-size"); } - if (sel === "armies") { + if (styleElement === "armies") { styleArmies.style.display = "block"; styleArmiesFillOpacity.value = styleArmiesFillOpacityOutput.value = el.attr("fill-opacity"); styleArmiesSize.value = styleArmiesSizeOutput.value = el.attr("box-size"); } - if (sel === "emblems") { + if (styleElement === "emblems") { styleEmblems.style.display = "block"; styleStrokeWidth.style.display = "block"; styleStrokeWidthInput.value = styleStrokeWidthOutput.value = el.attr("stroke-width") || 1; @@ -298,8 +341,8 @@ function selectStyleElement() { // update group options styleGroupSelect.options.length = 0; // remove all options - if (["routes", "labels", "coastline", "lakes", "anchors", "burgIcons", "borders"].includes(sel)) { - const groups = document.getElementById(sel).querySelectorAll("g"); + if (["routes", "labels", "coastline", "lakes", "anchors", "burgIcons", "borders", "terrs"].includes(styleElement)) { + const groups = byId(styleElement).querySelectorAll("g"); groups.forEach(el => { if (el.id === "burgLabels") return; const option = new Option(`${el.id} (${el.childElementCount})`, el.id, false, false); @@ -308,15 +351,56 @@ function selectStyleElement() { styleGroupSelect.value = el.attr("id"); styleGroup.style.display = "block"; } else { - styleGroupSelect.options.add(new Option(sel, sel, false, true)); + styleGroupSelect.options.add(new Option(styleElement, styleElement, false, true)); styleGroup.style.display = "none"; } - if (sel === "coastline" && styleGroupSelect.value === "sea_island") { + if (styleElement === "coastline" && styleGroupSelect.value === "sea_island") { styleCoastline.style.display = "block"; const auto = (styleCoastlineAuto.checked = coastline.select("#sea_island").attr("auto-filter")); if (auto) styleFilter.style.display = "none"; } + + if (styleElement === "scaleBar") { + styleScaleBar.style.display = "block"; + + styleScaleBarSize.value = el.attr("data-bar-size"); + styleScaleBarFontSize.value = el.attr("font-size"); + styleScaleBarPositionX.value = el.attr("data-x") || "99"; + styleScaleBarPositionY.value = el.attr("data-y") || "99"; + styleScaleBarLabel.value = el.attr("data-label") || ""; + + const scaleBarBack = el.select("#scaleBarBack"); + if (scaleBarBack.size()) { + styleScaleBarBackgroundOpacityInput.value = styleScaleBarBackgroundOpacityOutput.value = + scaleBarBack.attr("opacity"); + styleScaleBarBackgroundFillInput.value = styleScaleBarBackgroundFillOutput.value = scaleBarBack.attr("fill"); + styleScaleBarBackgroundStrokeInput.value = styleScaleBarBackgroundStrokeOutput.value = + scaleBarBack.attr("stroke"); + styleScaleBarBackgroundStrokeWidth.value = scaleBarBack.attr("stroke-width"); + styleScaleBarBackgroundFilter.value = scaleBarBack.attr("filter"); + styleScaleBarBackgroundPaddingTop.value = scaleBarBack.attr("data-top"); + styleScaleBarBackgroundPaddingRight.value = scaleBarBack.attr("data-right"); + styleScaleBarBackgroundPaddingBottom.value = scaleBarBack.attr("data-bottom"); + styleScaleBarBackgroundPaddingLeft.value = scaleBarBack.attr("data-left"); + } + } + + if (styleElement === "vignette") { + styleVignette.style.display = "block"; + + const maskRect = byId("vignette-rect"); + if (maskRect) { + const digit = str => str.replace(/[^\d.]/g, ""); + styleVignetteX.value = digit(maskRect.getAttribute("x")); + styleVignetteY.value = digit(maskRect.getAttribute("y")); + styleVignetteWidth.value = digit(maskRect.getAttribute("width")); + styleVignetteHeight.value = digit(maskRect.getAttribute("height")); + styleVignetteRx.value = digit(maskRect.getAttribute("rx")); + styleVignetteRy.value = digit(maskRect.getAttribute("ry")); + styleVignetteBlur.value = styleVignetteBlurOutput.value = digit(maskRect.getAttribute("filter")); + } + } } // Handle style inputs change @@ -367,12 +451,26 @@ styleFilterInput.addEventListener("change", function () { }); styleTextureInput.addEventListener("change", function () { - texture.select("image").attr("src", this.value); - if (layerIsOn("toggleTexture")) texture.select("image").attr("href", this.value); - zoom.scaleBy(svg, 1.00001); + changeTexture(this.value); }); +function changeTexture(href) { + texture.attr("data-href", href); + texture.select("image").attr("href", href); +} + +function updateTextureSelectValue(href) { + const isAdded = Array.from(styleTextureInput.options).some(option => option.value === href); + if (isAdded) { + styleTextureInput.value = href; + } else { + const name = href.split("/").pop().slice(0, 20); + styleTextureInput.add(new Option(name, href, false, true)); + } +} + styleTextureShiftX.addEventListener("input", function () { + texture.attr("data-x", this.value); texture .select("image") .attr("x", this.value) @@ -380,6 +478,7 @@ styleTextureShiftX.addEventListener("input", function () { }); styleTextureShiftY.addEventListener("input", function () { + texture.attr("data-y", this.value); texture .select("image") .attr("y", this.value) @@ -418,15 +517,6 @@ styleGridShiftY.addEventListener("input", function () { if (layerIsOn("toggleGrid")) drawGrid(); }); -styleShiftX.addEventListener("input", shiftElement); -styleShiftY.addEventListener("input", shiftElement); - -function shiftElement() { - const x = styleShiftX.value || 0; - const y = styleShiftY.value || 0; - getEl().attr("transform", `translate(${x},${y})`); -} - styleRescaleMarkers.addEventListener("change", function () { markers.attr("rescale", +this.checked); invokeActiveZooming(); @@ -444,11 +534,11 @@ styleOceanFill.addEventListener("input", function () { }); styleOceanPattern.addEventListener("change", function () { - document.getElementById("oceanicPattern")?.setAttribute("href", this.value); + byId("oceanicPattern")?.setAttribute("href", this.value); }); styleOceanPatternOpacity.addEventListener("input", function () { - document.getElementById("oceanicPattern").setAttribute("opacity", this.value); + byId("oceanicPattern").setAttribute("opacity", this.value); styleOceanPatternOpacityOutput.value = this.value; }); @@ -459,27 +549,151 @@ outlineLayers.addEventListener("change", function () { }); styleHeightmapScheme.addEventListener("change", function () { - terrs.attr("scheme", this.value); + getEl().attr("scheme", this.value); + drawHeightmap(); +}); + +openCreateHeightmapSchemeButton.addEventListener("click", function () { + // start with current scheme + const scheme = getEl().attr("scheme"); + this.dataset.stops = scheme.startsWith("#") + ? scheme + : (() => [0, 0.25, 0.5, 0.75, 1].map(heightmapColorSchemes[scheme]).map(toHEX).join(","))(); + + // render dialog base structure + alertMessage.innerHTML = /* html */ `
    + Define heightmap gradient colors from high to low altitude + heightmap preview +
    +
    +
    `; + + renderPreview(); + renderStops(); + renderGradient(); + + function renderPreview() { + const stops = openCreateHeightmapSchemeButton.dataset.stops.split(","); + const scheme = d3.scaleSequential(d3.interpolateRgbBasis(stops)); + + const preview = drawHeights({ + heights: grid.cells.h, + width: grid.cellsX, + height: grid.cellsY, + scheme, + renderOcean: false + }); + + byId("heightmapSchemePreview").src = preview; + } + + function renderStops() { + const stops = openCreateHeightmapSchemeButton.dataset.stops.split(","); + + const colorInput = color => + ``; + const removeStopButton = index => + ``; + const addStopButton = () => + ``; + + const container = byId("heightmapSchemeStops"); + container.innerHTML = stops + .map( + (stop, index) => `${colorInput(stop)} + ${index && index < stops.length - 1 ? removeStopButton(index) : ""}` + ) + .join(addStopButton()); + + Array.from(container.querySelectorAll("input.stop")).forEach( + (input, index) => + (input.oninput = function () { + stops[index] = this.value; + openCreateHeightmapSchemeButton.dataset.stops = stops.join(","); + renderPreview(); + renderGradient(); + }) + ); + + Array.from(container.querySelectorAll("button.remove")).forEach( + button => + (button.onclick = function () { + const index = +this.dataset.index; + stops.splice(index, 1); + openCreateHeightmapSchemeButton.dataset.stops = stops.join(","); + renderPreview(); + renderStops(); + renderGradient(); + }) + ); + + Array.from(container.querySelectorAll("button.add")).forEach( + (button, index) => + (button.onclick = function () { + const middleColor = d3.interpolateRgb(stops[index], stops[index + 1])(0.5); + stops.splice(index + 1, 0, toHEX(middleColor)); + openCreateHeightmapSchemeButton.dataset.stops = stops.join(","); + renderPreview(); + renderStops(); + renderGradient(); + }) + ); + } + + function renderGradient() { + const stops = openCreateHeightmapSchemeButton.dataset.stops; + byId("heightmapSchemeGradient").style.background = `linear-gradient(to right, ${stops})`; + } + + function handleCreate() { + const stops = openCreateHeightmapSchemeButton.dataset.stops; + if (stops in heightmapColorSchemes) return tip("This scheme already exists", false, "error"); + + addCustomColorScheme(stops); + getEl().attr("scheme", stops); + drawHeightmap(); + + handleClose(); + } + + function handleClose() { + $("#alert").dialog("close"); + } + + $("#alert").dialog({ + resizable: false, + title: "Create heightmap color scheme", + width: "28em", + buttons: { + Create: handleCreate, + Cancel: handleClose + }, + position: {my: "center top+150", at: "center top", of: "svg"} + }); +}); + +styleHeightmapRenderOcean.addEventListener("change", function () { + getEl().attr("data-render", +this.checked); drawHeightmap(); }); styleHeightmapTerracingInput.addEventListener("input", function () { - terrs.attr("terracing", this.value); + getEl().attr("terracing", this.value); drawHeightmap(); }); styleHeightmapSkipInput.addEventListener("input", function () { - terrs.attr("skip", this.value); + getEl().attr("skip", this.value); drawHeightmap(); }); styleHeightmapSimplificationInput.addEventListener("input", function () { - terrs.attr("relax", this.value); + getEl().attr("relax", this.value); drawHeightmap(); }); styleHeightmapCurve.addEventListener("change", function () { - terrs.attr("curve", this.value); + getEl().attr("curve", this.value); drawHeightmap(); }); @@ -753,27 +967,19 @@ emblemsBurgSizeInput.addEventListener("change", drawEmblems); // request a URL to image to be used as a texture function textureProvideURL() { - alertMessage.innerHTML = /* html */ `Provide an image URL to be used as a texture: + alertMessage.innerHTML = /* html */ `Provide a texture image URL: `; + $("#alert").dialog({ resizable: false, title: "Load custom texture", - width: "26em", + width: "28em", buttons: { Apply: function () { - const name = textureURL.value.split("/").pop(); - if (!name || name === "") return tip("Please provide a valid URL", false, "error"); - - const opt = document.createElement("option"); - opt.value = textureURL.value; - opt.text = name.slice(0, 20); - styleTextureInput.add(opt); - styleTextureInput.value = textureURL.value; - - const image = texture.select("image"); - image.attr("src", textureURL.value); - if (layerIsOn("toggleTexture")) image.attr("href", textureURL.value); + if (!textureURL.value) return tip("Please provide a valid URL", false, "error"); + changeTexture(textureURL.value); + updateTextureSelectValue(textureURL.value); $(this).dialog("close"); }, Cancel: function () { @@ -784,10 +990,10 @@ function textureProvideURL() { } function fetchTextureURL(url) { - INFO && console.log("Provided URL is", url); + INFO && console.info("Provided URL is", url); const img = new Image(); img.onload = function () { - const canvas = document.getElementById("texturePreview"); + const canvas = byId("texturePreview"); const ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, 0, 0, canvas.width, canvas.height); @@ -795,6 +1001,119 @@ function fetchTextureURL(url) { img.src = url; } +const vignettePresets = { + default: `{ "#vignette": { "opacity": 0.3, "fill": "#000000", "filter": null }, "#vignette-rect": { "x": "0.3%", "y": "0.4%", "width": "99.6%", "height": "99.2%", "rx": "5%", "ry": "5%", "filter": "blur(20px)" } }`, + neon: `{ "#vignette": { "opacity": 0.5, "fill": "#7300ff", "filter": null }, "#vignette-rect": { "x": "0.3%", "y": "0.4%", "width": "99.6%", "height": "99.2%", "rx": "0%", "ry": "0%", "filter": "blur(15px)" } }`, + smoke: `{ "#vignette": { "opacity": 1, "fill": "#000000", "filter": "url(#splotch)" }, "#vignette-rect": { "x": "3%", "y": "5%", "width": "96%", "height": "90%", "rx": "10%", "ry": "10%", "filter": "blur(100px)" } }`, + wound: `{ "#vignette": { "opacity": 0.8, "fill": "#ff0000", "filter": "url(#paper)"}, "#vignette-rect": {"x": "0.5%", "y": "1%", "width": "99%", "height": "98%", "rx": "5%", "ry": "5%", "filter": "blur(50px)" } }`, + paper: `{ "#vignette": { "opacity": 1, "fill": "#000000", "filter": "url(#paper)" }, "#vignette-rect": { "x": "0.3%", "y": "0.4%", "width": "99.6%", "height": "99.2%", "rx": "20%", "ry": "20%", "filter": "blur(150px)" } }`, + granite: `{ "#vignette": { "opacity": 0.95, "fill": "#231b1b", "filter": "url(#crumpled)" }, "#vignette-rect": { "x": "3%", "y": "5%", "width": "94%", "height": "90%", "rx": "20%", "ry": "20%", "filter": "blur(150px)" } }`, + spotlight: `{ "#vignette": { "opacity": 0.96, "fill": "#000000", "filter": null }, "#vignette-rect": { "x": "20%", "y": "30%", "width": "24%", "height": "30%", "rx": "50%", "ry": "50%", "filter": "blur(30px) "} }` +}; + +Object.keys(vignettePresets).forEach(preset => { + styleVignettePreset.options.add(new Option(preset, preset, false, false)); +}); + +styleVignettePreset.addEventListener("change", function () { + const attributes = JSON.parse(vignettePresets[this.value]); + + for (const selector in attributes) { + const el = document.querySelector(selector); + if (!el) continue; + for (const attr in attributes[selector]) { + const value = attributes[selector][attr]; + el.setAttribute(attr, value); + } + } + + const vignette = byId("vignette"); + if (vignette) { + styleOpacityInput.value = styleOpacityOutput.value = vignette.getAttribute("opacity"); + styleFillInput.value = styleFillOutput.value = vignette.getAttribute("fill"); + styleFilterInput.value = vignette.getAttribute("filter"); + } + + const maskRect = byId("vignette-rect"); + if (maskRect) { + const digit = str => str.replace(/[^\d.]/g, ""); + styleVignetteX.value = digit(maskRect.getAttribute("x")); + styleVignetteY.value = digit(maskRect.getAttribute("y")); + styleVignetteWidth.value = digit(maskRect.getAttribute("width")); + styleVignetteHeight.value = digit(maskRect.getAttribute("height")); + styleVignetteRx.value = digit(maskRect.getAttribute("rx")); + styleVignetteRy.value = digit(maskRect.getAttribute("ry")); + styleVignetteBlur.value = styleVignetteBlurOutput.value = digit(maskRect.getAttribute("filter")); + } +}); + +styleVignetteX.addEventListener("input", function () { + byId("vignette-rect")?.setAttribute("x", `${this.value}%`); +}); + +styleVignetteWidth.addEventListener("input", function () { + byId("vignette-rect")?.setAttribute("width", `${this.value}%`); +}); + +styleVignetteY.addEventListener("input", function () { + byId("vignette-rect")?.setAttribute("y", `${this.value}%`); +}); + +styleVignetteHeight.addEventListener("input", function () { + byId("vignette-rect")?.setAttribute("height", `${this.value}%`); +}); + +styleVignetteRx.addEventListener("input", function () { + byId("vignette-rect")?.setAttribute("rx", `${this.value}%`); +}); + +styleVignetteRy.addEventListener("input", function () { + byId("vignette-rect")?.setAttribute("ry", `${this.value}%`); +}); + +styleVignetteBlur.addEventListener("input", function () { + styleVignetteBlurOutput.value = this.value; + byId("vignette-rect")?.setAttribute("filter", `blur(${this.value}px)`); +}); + +styleScaleBar.addEventListener("input", function (event) { + const scaleBarBack = scaleBar.select("#scaleBarBack"); + if (!scaleBarBack.size()) return; + + const {id, value} = event.target; + + if (id === "styleScaleBarSize") scaleBar.attr("data-bar-size", value); + else if (id === "styleScaleBarFontSize") scaleBar.attr("font-size", value); + else if (id === "styleScaleBarPositionX") scaleBar.attr("data-x", value); + else if (id === "styleScaleBarPositionY") scaleBar.attr("data-y", value); + else if (id === "styleScaleBarLabel") scaleBar.attr("data-label", value); + else if (id === "styleScaleBarBackgroundOpacityInput") scaleBarBack.attr("opacity", value); + else if (id === "styleScaleBarBackgroundFillInput") scaleBarBack.attr("fill", value); + else if (id === "styleScaleBarBackgroundStrokeInput") scaleBarBack.attr("stroke", value); + else if (id === "styleScaleBarBackgroundStrokeWidth") scaleBarBack.attr("stroke-width", value); + else if (id === "styleScaleBarBackgroundFilter") scaleBarBack.attr("filter", value); + else if (id === "styleScaleBarBackgroundPaddingTop") scaleBarBack.attr("data-top", value); + else if (id === "styleScaleBarBackgroundPaddingRight") scaleBarBack.attr("data-right", value); + else if (id === "styleScaleBarBackgroundPaddingBottom") scaleBarBack.attr("data-bottom", value); + else if (id === "styleScaleBarBackgroundPaddingLeft") scaleBarBack.attr("data-left", value); + + if ( + [ + "styleScaleBarSize", + "styleScaleBarPositionX", + "styleScaleBarPositionY", + "styleScaleBarLabel", + "styleScaleBarBackgroundPaddingLeft", + "styleScaleBarBackgroundPaddingTop", + "styleScaleBarBackgroundPaddingRight", + "styleScaleBarBackgroundPaddingBottom" + ].includes(id) + ) { + drawScaleBar(scaleBar, scale); + fitScaleBar(scaleBar, svgWidth, svgHeight); + } +}); + function updateElements() { // burgIcons to desired size burgIcons.selectAll("g").each(function () { diff --git a/modules/ui/stylePresets.js b/modules/ui/stylePresets.js index c0d32af7..aa13d800 100644 --- a/modules/ui/stylePresets.js +++ b/modules/ui/stylePresets.js @@ -11,6 +11,7 @@ const systemPresets = [ "clean", "atlas", "cyberpunk", + "night", "monochrome" ]; const customPresetPrefix = "fmgStyle_"; @@ -61,21 +62,19 @@ async function getStylePreset(desiredPreset) { } 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; + try { + const res = await fetch(`./styles/${preset}.json`); + return await res.json(); + } catch (err) { + throw new Error("Cannot fetch style preset", preset); + } } 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]; @@ -90,8 +89,18 @@ function applyStyle(style) { el.setAttribute(attribute, value); } - if (layerIsOn("toggleTexture") && selector === "#textureImage" && attribute === "src") { - el.setAttribute("href", value); + if (selector === "#texture") { + const image = document.querySelector("#texture > image"); + if (image) { + if (attribute === "data-x") image.setAttribute("x", value); + if (attribute === "data-y") image.setAttribute("y", value); + if (attribute === "data-href") image.setAttribute("href", value); + } + } + + // add custom heightmap color scheme + if (selector === "#terrs" && attribute === "scheme" && !(value in heightmapColorSchemes)) { + addCustomColorScheme(value); } } } @@ -99,10 +108,7 @@ function applyStyle(style) { function requestStylePresetChange(preset) { const isConfirmed = sessionStorage.getItem("styleChangeConfirmed"); - if (isConfirmed) { - changeStyle(preset); - return; - } + if (isConfirmed) return changeStyle(preset); confirmationDialog({ title: "Change style preset", @@ -120,8 +126,8 @@ function requestStylePresetChange(preset) { async function changeStyle(desiredPreset) { const styleData = await getStylePreset(desiredPreset); - const [appliedPreset, style] = styleData; - localStorage.setItem("presetStyle", appliedPreset); + const [presetName, style] = styleData; + localStorage.setItem("presetStyle", presetName); applyStyleWithUiRefresh(style); } @@ -134,6 +140,9 @@ function applyStyleWithUiRefresh(style) { invokeActiveZooming(); setPresetRemoveButtonVisibiliy(); + + drawScaleBar(scaleBar, scale); + fitScaleBar(scaleBar, svgWidth, svgHeight); } function addStylePreset() { @@ -228,13 +237,23 @@ function addStylePreset() { ], "#ice": ["opacity", "fill", "stroke", "stroke-width", "filter"], "#emblems": ["opacity", "stroke-width", "filter"], - "#texture": ["opacity", "filter", "mask"], - "#textureImage": ["x", "y", "src"], + "#texture": ["opacity", "filter", "mask", "data-x", "data-y", "data-href"], "#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"], + "#terrs #oceanHeights": [ + "data-render", + "opacity", + "scheme", + "terracing", + "skip", + "relax", + "curve", + "filter", + "mask" + ], + "#terrs #landHeights": ["opacity", "scheme", "terracing", "skip", "relax", "curve", "filter", "mask"], "#legend": [ "data-size", "font-size", @@ -294,7 +313,21 @@ function addStylePreset() { "font-family", "filter" ], - "#fogging": ["opacity", "fill", "filter"] + "#fogging": ["opacity", "fill", "filter"], + "#vignette": ["opacity", "fill", "filter"], + "#vignette-rect": ["x", "y", "width", "height", "rx", "ry", "filter"], + "#scaleBar": ["opacity", "fill", "font-size", "data-bar-size", "data-x", "data-y", "data-label"], + "#scaleBarBack": [ + "opacity", + "fill", + "stroke", + "stroke-width", + "filter", + "data-top", + "data-right", + "data-bottom", + "data-left" + ] }; for (const selector in attributes) { diff --git a/modules/ui/submap.js b/modules/ui/submap.js index 737560c3..2a476faa 100644 --- a/modules/ui/submap.js +++ b/modules/ui/submap.js @@ -136,7 +136,14 @@ window.UISubmap = (function () { } async function loadPreview($container, w, h) { - const url = await getMapURL("png", {globe: false, noWater: true, fullMap: true, noLabels: true, noScaleBar: true, noIce: true}); + const url = await getMapURL("png", { + globe: false, + noWater: true, + fullMap: true, + noLabels: true, + noScaleBar: true, + noIce: true + }); const canvas = document.createElement("canvas"); const ctx = canvas.getContext("2d"); @@ -173,7 +180,11 @@ window.UISubmap = (function () { const {angle, shiftX, shiftY, ratio, mirrorH, mirrorV} = getTransformInput(); const [cx, cy] = [graphWidth / 2, graphHeight / 2]; - const rot = alfa => (x, y) => [(x - cx) * Math.cos(alfa) - (y - cy) * Math.sin(alfa) + cx, (y - cy) * Math.cos(alfa) + (x - cx) * Math.sin(alfa) + cy]; + const rot = alfa => (x, y) => + [ + (x - cx) * Math.cos(alfa) - (y - cy) * Math.sin(alfa) + cx, + (y - cy) * Math.cos(alfa) + (x - cx) * Math.sin(alfa) + cy + ]; const shift = (dx, dy) => (x, y) => [x + dx, y + dy]; const scale = r => (x, y) => [(x - cx) * r + cx, (y - cy) * r + cy]; const flipH = (x, y) => [-x + 2 * cx, y]; @@ -185,7 +196,11 @@ window.UISubmap = (function () { let inverse = id; if (angle) [projection, inverse] = [rot(angle), rot(-angle)]; - if (ratio) [projection, inverse] = [app(scale(Math.pow(1.1, ratio)), projection), app(inverse, scale(Math.pow(1.1, -ratio)))]; + if (ratio) + [projection, inverse] = [ + app(scale(Math.pow(1.1, ratio)), projection), + app(inverse, scale(Math.pow(1.1, -ratio))) + ]; if (mirrorH) [projection, inverse] = [app(flipH, projection), app(inverse, flipH)]; if (mirrorV) [projection, inverse] = [app(flipV, projection), app(inverse, flipV)]; if (shiftX || shiftY) { @@ -244,7 +259,10 @@ window.UISubmap = (function () { // fix scale distanceScaleInput.value = distanceScaleOutput.value = rn((distanceScale = distanceScaleOutput.value / scale), 2); - populationRateInput.value = populationRateOutput.value = rn((populationRate = populationRateOutput.value / scale), 2); + populationRateInput.value = populationRateOutput.value = rn( + (populationRate = populationRateOutput.value / scale), + 2 + ); customization = 0; startResample(options); }, 1000); diff --git a/modules/ui/tools.js b/modules/ui/tools.js index e1d554da..4d62305c 100644 --- a/modules/ui/tools.js +++ b/modules/ui/tools.js @@ -247,13 +247,16 @@ function recreateStates() { capitalsTree.add([x, y]); // update label id reference - labels - .select("#states") - .select(`#stateLabel${state.i}`) - .attr("id", `stateLabel${newId}`) - .select("textPath") - .attr("xlink:href", `#textPath_stateLabel${newId}`); - defs.select("#textPaths").select(`#textPath_stateLabel${state.i}`).attr("id", `textPath_stateLabel${newId}`); + byId(`textPath_stateLabel${state.i}`)?.setAttribute("id", `textPath_stateLabel${newId}`); + const $label = byId(`stateLabel${state.i}`); + if ($label) { + $label.setAttribute("id", `stateLabel${newId}`); + const $textPath = $label.querySelector("textPath"); + if ($textPath) { + $textPath.removeAttribute("href"); + $textPath.setAttribute("href", `#textPath_stateLabel${newId}`); + } + } // update emblem id reference byId(`stateCOA${state.i}`)?.setAttribute("id", `stateCOA${newId}`); @@ -361,10 +364,10 @@ function regenerateBurgs() { const score = new Int16Array(cells.s.map(s => s * Math.random())); // cell score for capitals placement const sorted = cells.i.filter(i => score[i] > 0 && cells.culture[i]).sort((a, b) => score[b] - score[a]); // filtered and sorted array of indexes + const existingStatesCount = states.filter(s => s.i && !s.removed).length; const burgsCount = - manorsInput.value === "1000" - ? rn(sorted.length / 5 / (grid.points.length / 10000) ** 0.8) + states.length - : +manorsInput.value + states.length; + (manorsInput.value === "1000" ? rn(sorted.length / 5 / (grid.points.length / 10000) ** 0.8) : +manorsInput.value) + + existingStatesCount; const spacing = (graphWidth + graphHeight) / 150 / (burgsCount ** 0.7 / 66); // base min distance between towns for (let i = 0; i < sorted.length && burgs.length < burgsCount; i++) { diff --git a/modules/ui/units-editor.js b/modules/ui/units-editor.js index 37645978..97a3573f 100644 --- a/modules/ui/units-editor.js +++ b/modules/ui/units-editor.js @@ -11,55 +11,51 @@ function editUnits() { position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"} }); - const drawBar = () => drawScaleBar(scale); + const renderScaleBar = () => { + drawScaleBar(scaleBar, scale); + fitScaleBar(scaleBar, svgWidth, svgHeight); + }; // add listeners - document.getElementById("distanceUnitInput").addEventListener("change", changeDistanceUnit); - document.getElementById("distanceScaleOutput").addEventListener("input", changeDistanceScale); - document.getElementById("distanceScaleInput").addEventListener("change", changeDistanceScale); - document.getElementById("heightUnit").addEventListener("change", changeHeightUnit); - document.getElementById("heightExponentInput").addEventListener("input", changeHeightExponent); - document.getElementById("heightExponentOutput").addEventListener("input", changeHeightExponent); - document.getElementById("temperatureScale").addEventListener("change", changeTemperatureScale); - 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); - document.getElementById("barBackColor").addEventListener("input", changeScaleBarColor); + byId("distanceUnitInput").addEventListener("change", changeDistanceUnit); + byId("distanceScaleOutput").addEventListener("input", changeDistanceScale); + byId("distanceScaleInput").addEventListener("change", changeDistanceScale); + byId("heightUnit").addEventListener("change", changeHeightUnit); + byId("heightExponentInput").addEventListener("input", changeHeightExponent); + byId("heightExponentOutput").addEventListener("input", changeHeightExponent); + byId("temperatureScale").addEventListener("change", changeTemperatureScale); - document.getElementById("populationRateOutput").addEventListener("input", changePopulationRate); - document.getElementById("populationRateInput").addEventListener("change", changePopulationRate); - document.getElementById("urbanizationOutput").addEventListener("input", changeUrbanizationRate); - document.getElementById("urbanizationInput").addEventListener("change", changeUrbanizationRate); - document.getElementById("urbanDensityOutput").addEventListener("input", changeUrbanDensity); - document.getElementById("urbanDensityInput").addEventListener("change", changeUrbanDensity); + byId("populationRateOutput").addEventListener("input", changePopulationRate); + byId("populationRateInput").addEventListener("change", changePopulationRate); + byId("urbanizationOutput").addEventListener("input", changeUrbanizationRate); + byId("urbanizationInput").addEventListener("change", changeUrbanizationRate); + byId("urbanDensityOutput").addEventListener("input", changeUrbanDensity); + byId("urbanDensityInput").addEventListener("change", changeUrbanDensity); - document.getElementById("addLinearRuler").addEventListener("click", addRuler); - document.getElementById("addOpisometer").addEventListener("click", toggleOpisometerMode); - document.getElementById("addRouteOpisometer").addEventListener("click", toggleRouteOpisometerMode); - document.getElementById("addPlanimeter").addEventListener("click", togglePlanimeterMode); - document.getElementById("removeRulers").addEventListener("click", removeAllRulers); - document.getElementById("unitsRestore").addEventListener("click", restoreDefaultUnits); + byId("addLinearRuler").addEventListener("click", addRuler); + byId("addOpisometer").addEventListener("click", toggleOpisometerMode); + byId("addRouteOpisometer").addEventListener("click", toggleRouteOpisometerMode); + byId("addPlanimeter").addEventListener("click", togglePlanimeterMode); + byId("removeRulers").addEventListener("click", removeAllRulers); + byId("unitsRestore").addEventListener("click", restoreDefaultUnits); function changeDistanceUnit() { if (this.value === "custom_name") { prompt("Provide a custom name for a distance unit", {default: ""}, custom => { this.options.add(new Option(custom, custom, false, true)); lock("distanceUnit"); - drawScaleBar(scale); + renderScaleBar(); calculateFriendlyGridSize(); }); return; } - drawScaleBar(scale); + renderScaleBar(); calculateFriendlyGridSize(); } function changeDistanceScale() { - drawScaleBar(scale); + renderScaleBar(); calculateFriendlyGridSize(); } @@ -81,14 +77,6 @@ function editUnits() { if (layerIsOn("toggleTemp")) drawTemp(); } - function changeScaleBarOpacity() { - scaleBar.select("rect").attr("opacity", this.value); - } - - function changeScaleBarColor() { - scaleBar.select("rect").attr("fill", this.value); - } - function changePopulationRate() { populationRate = +this.value; } @@ -104,8 +92,8 @@ function editUnits() { function restoreDefaultUnits() { // distanceScale distanceScale = 3; - document.getElementById("distanceScaleOutput").value = 3; - document.getElementById("distanceScaleInput").value = 3; + byId("distanceScaleOutput").value = 3; + byId("distanceScaleInput").value = 3; unlock("distanceScale"); // units @@ -126,20 +114,7 @@ function editUnits() { localStorage.removeItem("heightExponent"); calculateTemperatures(); - // scale bar - barSizeOutput.value = barSizeInput.value = 2; - barLabel.value = ""; - barBackOpacity.value = 0.2; - barBackColor.value = "#ffffff"; - barPosX.value = barPosY.value = 99; - - localStorage.removeItem("barSize"); - localStorage.removeItem("barLabel"); - localStorage.removeItem("barBackOpacity"); - localStorage.removeItem("barBackColor"); - localStorage.removeItem("barPosX"); - localStorage.removeItem("barPosY"); - drawScaleBar(scale); + renderScaleBar(); // population populationRate = populationRateOutput.value = populationRateInput.value = 1000; @@ -152,7 +127,7 @@ function editUnits() { function addRuler() { if (!layerIsOn("toggleRulers")) toggleRulers(); - const pt = document.getElementById("map").createSVGPoint(); + const pt = byId("map").createSVGPoint(); (pt.x = graphWidth / 2), (pt.y = graphHeight / 4); const p = pt.matrixTransform(viewbox.node().getScreenCTM().inverse()); const dx = graphWidth / 4 / scale; diff --git a/styles/ancient.json b/styles/ancient.json index 6bacb0d5..78cac9e1 100644 --- a/styles/ancient.json +++ b/styles/ancient.json @@ -261,12 +261,10 @@ "#texture": { "opacity": 0.6, "filter": "", - "mask": "" - }, - "#textureImage": { - "x": 0, - "y": 0, - "src": "https://i2.wp.com/azgaar.files.wordpress.com/2019/07/antique-small.jpg" + "mask": "", + "data-x": 0, + "data-y": 0, + "data-href": "./images/textures/antique-small.jpg" }, "#zones": { "opacity": 0.6, @@ -288,14 +286,25 @@ "href": "./images/kiwiroo.png", "opacity": 0.4 }, - "#terrs": { - "opacity": null, - "scheme": "bright", + "#terrs > #oceanHeights": { + "data-render": 0, + "opacity": 1, + "scheme": "light", + "terracing": 0, + "skip": 0, + "relax": 1, + "curve": "curveBasisClosed", + "filter": "url(#filter-sepia)", + "mask": null + }, + "#terrs > #landHeights": { + "opacity": 1, + "scheme": "light", "terracing": 0, "skip": 2, "relax": 1, - "curve": 0, - "filter": "url(#blur3)", + "curve": "curveBasisClosed", + "filter": "url(#filter-sepia)", "mask": "url(#land)" }, "#legend": { @@ -386,5 +395,39 @@ "opacity": 0.98, "fill": "#30426f", "filter": null + }, + "#vignette": { + "opacity": 0.2, + "fill": "#000000", + "filter": "" + }, + "#vignette-rect": { + "x": "0%", + "y": "0%", + "width": "100%", + "height": "100%", + "rx": "0%", + "ry": "0%", + "filter": "blur(50px)" + }, + "#scaleBar": { + "opacity": 1, + "fill": "#353540", + "font-size": 10, + "data-bar-size": 2, + "data-x": 99, + "data-y": 99, + "data-label": "" + }, + "#scaleBarBack": { + "opacity": 0, + "fill": "#ffffff", + "stroke": "#000000", + "stroke-width": 1, + "filter": "url(#blur5)", + "data-top": 20, + "data-right": 15, + "data-bottom": 15, + "data-left": 10 } } diff --git a/styles/atlas.json b/styles/atlas.json index 72a31027..040e551c 100644 --- a/styles/atlas.json +++ b/styles/atlas.json @@ -261,12 +261,10 @@ "#texture": { "opacity": 0.2, "filter": null, - "mask": "url(#land)" - }, - "#textureImage": { - "x": 0, - "y": 0, - "src": "https://i2.wp.com/azgaar.files.wordpress.com/2021/10/plaster.jpg" + "mask": "url(#land)", + "data-x": 0, + "data-y": 0, + "data-href": "./images/textures/plaster.jpg" }, "#zones": { "opacity": 0.6, @@ -288,13 +286,24 @@ "href": "", "opacity": 1 }, - "#terrs": { - "opacity": null, + "#terrs > #oceanHeights": { + "data-render": 1, + "opacity": 1, + "scheme": "bright", + "terracing": 0, + "skip": 0, + "relax": 1, + "curve": "curveBasisClosed", + "filter": null, + "mask": null + }, + "#terrs > #landHeights": { + "opacity": 1, "scheme": "bright", "terracing": 0, "skip": 0, "relax": 0, - "curve": 0, + "curve": "curveBasisClosed", "filter": null, "mask": "url(#land)" }, @@ -386,5 +395,39 @@ "opacity": 0.98, "fill": "#30426f", "filter": null + }, + "#vignette": { + "opacity": 0.2, + "fill": "#000000", + "filter": null + }, + "#vignette-rect": { + "x": "0.2%", + "y": "0.3%", + "width": "99.8%", + "height": "99.4%", + "rx": "5%", + "ry": "5%", + "filter": "blur(30px)" + }, + "#scaleBar": { + "opacity": 1, + "fill": "#353540", + "font-size": 9, + "data-bar-size": 1.5, + "data-x": 99, + "data-y": 99, + "data-label": "" + }, + "#scaleBarBack": { + "opacity": 0.2, + "fill": "#ffffff", + "stroke": "#000000", + "stroke-width": 1, + "filter": null, + "data-top": 18, + "data-right": 15, + "data-bottom": 15, + "data-left": 10 } } diff --git a/styles/clean.json b/styles/clean.json index a65beffb..6f2e7ac6 100644 --- a/styles/clean.json +++ b/styles/clean.json @@ -263,12 +263,10 @@ "#texture": { "opacity": 0.2, "filter": null, - "mask": "url(#land)" - }, - "#textureImage": { - "x": 0, - "y": 0, - "src": "https://i2.wp.com/azgaar.files.wordpress.com/2021/10/plaster.jpg" + "mask": "url(#land)", + "data-x": 0, + "data-y": 0, + "data-href": "./images/textures/plaster.jpg" }, "#zones": { "opacity": 0.7, @@ -290,13 +288,24 @@ "href": "", "opacity": 0.2 }, - "#terrs": { + "#terrs > #oceanHeights": { + "data-render": 1, + "opacity": 0.5, + "scheme": "bright", + "terracing": 0, + "skip": 0, + "relax": 1, + "curve": "curveBasisClosed", + "filter": null, + "mask": null + }, + "#terrs > #landHeights": { "opacity": 0.5, "scheme": "bright", "terracing": 0, "skip": 5, "relax": 0, - "curve": 0, + "curve": "curveBasisClosed", "filter": null, "mask": "url(#land)" }, @@ -388,5 +397,39 @@ "opacity": 1, "fill": "#ffffff", "filter": null + }, + "#vignette": { + "opacity": 0, + "fill": "#000000", + "filter": null + }, + "#vignette-rect": { + "x": "0.3%", + "y": "0.4%", + "width": "99.6%", + "height": "99.2%", + "rx": "5%", + "ry": "5%", + "filter": "blur(20px)" + }, + "#scaleBar": { + "opacity": 1, + "fill": "#353540", + "font-size": 8, + "data-bar-size": 1.5, + "data-x": 99, + "data-y": 99, + "data-label": "" + }, + "#scaleBarBack": { + "opacity": 0, + "fill": "#ffffff", + "stroke": "#000000", + "stroke-width": 1, + "filter": "", + "data-top": 17, + "data-right": 15, + "data-bottom": 15, + "data-left": 10 } } diff --git a/styles/cyberpunk.json b/styles/cyberpunk.json index 02b815e3..7b8d64b6 100644 --- a/styles/cyberpunk.json +++ b/styles/cyberpunk.json @@ -261,12 +261,10 @@ "#texture": { "opacity": 0.2, "filter": null, - "mask": "url(#water)" - }, - "#textureImage": { - "x": 0, - "y": 0, - "src": "https://i2.wp.com/azgaar.files.wordpress.com/2019/07/mercury-small.jpg" + "mask": "url(#water)", + "data-x": 0, + "data-y": 0, + "data-href": "./images/textures/mercury-small.jpg" }, "#zones": { "opacity": 0.7, @@ -288,14 +286,25 @@ "href": "", "opacity": 0.15 }, - "#terrs": { + "#terrs > #oceanHeights": { + "data-render": 1, "opacity": 1, - "scheme": "monochrome", + "scheme": "olive", + "terracing": 0, + "skip": 0, + "relax": 1, + "curve": "curveBasisClosed", + "filter": null, + "mask": null + }, + "#terrs > #landHeights": { + "opacity": 0.8, + "scheme": "livid", "terracing": 6, "skip": 0, "relax": 2, - "curve": 0, - "filter": "", + "curve": "curveBasisClosed", + "filter": null, "mask": "url(#land)" }, "#legend": { @@ -386,5 +395,39 @@ "opacity": 0.98, "fill": "#1b1423", "filter": null + }, + "#vignette": { + "opacity": 0, + "fill": "#000000", + "filter": null + }, + "#vignette-rect": { + "x": "0.3%", + "y": "0.4%", + "width": "99.6%", + "height": "99.2%", + "rx": "5%", + "ry": "5%", + "filter": "blur(20px)" + }, + "#scaleBar": { + "opacity": 1, + "fill": "#d0d0dc", + "font-size": 11, + "data-bar-size": 2, + "data-x": 99, + "data-y": 99, + "data-label": "" + }, + "#scaleBarBack": { + "opacity": 0.3, + "fill": "#05001f", + "stroke": "#000000", + "stroke-width": 1, + "filter": "", + "data-top": 23, + "data-right": 18, + "data-bottom": 18, + "data-left": 12 } } diff --git a/styles/default.json b/styles/default.json index b68d2474..251042f7 100644 --- a/styles/default.json +++ b/styles/default.json @@ -261,12 +261,10 @@ "#texture": { "opacity": null, "filter": null, - "mask": "url(#land)" - }, - "#textureImage": { - "x": 0, - "y": 0, - "src": "https://i2.wp.com/azgaar.files.wordpress.com/2021/10/marble-big.jpg" + "mask": "url(#land)", + "data-x": 0, + "data-y": 0, + "data-href": "./images/textures/marble-big.jpg" }, "#zones": { "opacity": 0.6, @@ -288,13 +286,24 @@ "href": "./images/pattern1.png", "opacity": 0.2 }, - "#terrs": { - "opacity": null, + "#terrs > #oceanHeights": { + "data-render": 0, + "opacity": 1, + "scheme": "bright", + "terracing": 0, + "skip": 0, + "relax": 1, + "curve": "curveBasisClosed", + "filter": null, + "mask": null + }, + "#terrs > #landHeights": { + "opacity": 1, "scheme": "bright", "terracing": 0, "skip": 5, "relax": 0, - "curve": 0, + "curve": "curveBasisClosed", "filter": null, "mask": "url(#land)" }, @@ -386,5 +395,39 @@ "opacity": 0.98, "fill": "#30426f", "filter": null + }, + "#vignette": { + "opacity": 0.3, + "fill": "#000000", + "filter": null + }, + "#vignette-rect": { + "x": "0.3%", + "y": "0.4%", + "width": "99.6%", + "height": "99.2%", + "rx": "5%", + "ry": "5%", + "filter": "blur(20px)" + }, + "#scaleBar": { + "opacity": 1, + "fill": "#353540", + "font-size": 10, + "data-bar-size": 2, + "data-x": 99, + "data-y": 99, + "data-label": "" + }, + "#scaleBarBack": { + "opacity": 0.2, + "fill": "#ffffff", + "stroke": "#000000", + "stroke-width": 1, + "filter": "url(#blur5)", + "data-top": 20, + "data-right": 15, + "data-bottom": 15, + "data-left": 10 } } diff --git a/styles/gloom.json b/styles/gloom.json index 5dde229f..72c123e1 100644 --- a/styles/gloom.json +++ b/styles/gloom.json @@ -263,12 +263,10 @@ "#texture": { "opacity": 0.8, "filter": null, - "mask": "url(#land)" - }, - "#textureImage": { - "x": 0, - "y": 0, - "src": "https://i2.wp.com/azgaar.files.wordpress.com/2019/07/iran-small.jpg" + "mask": "url(#land)", + "data-x": 0, + "data-y": 0, + "data-href": "./images/textures/iran-small.jpg" }, "#zones": { "opacity": 0.5, @@ -290,14 +288,25 @@ "href": "./images/pattern3.png", "opacity": 0.2 }, - "#terrs": { - "opacity": 1, + "#terrs > #oceanHeights": { + "data-render": 1, + "opacity": 0.8, "scheme": "bright", "terracing": 0, "skip": 0, "relax": 1, - "curve": 1, - "filter": "url(#filter-grayscale)", + "curve": "curveBasisClosed", + "filter": null, + "mask": null + }, + "#terrs > #landHeights": { + "opacity": 0.8, + "scheme": "bright", + "terracing": 2, + "skip": 1, + "relax": 2, + "curve": "curveBasisClosed", + "filter": null, "mask": "url(#land)" }, "#legend": { @@ -388,5 +397,39 @@ "opacity": 0.98, "fill": "#1b1423", "filter": null + }, + "#vignette": { + "opacity": 0.5, + "fill": "#042603", + "filter": null + }, + "#vignette-rect": { + "x": "0.1%", + "y": "0.2%", + "width": "99.8%", + "height": "99.6%", + "rx": "10%", + "ry": "10%", + "filter": "blur(30px)" + }, + "#scaleBar": { + "opacity": 1, + "fill": "#121212", + "font-size": 10, + "data-bar-size": 2, + "data-x": 99, + "data-y": 99, + "data-label": "" + }, + "#scaleBarBack": { + "opacity": 0.2, + "fill": "#607671", + "stroke": "#000000", + "stroke-width": 1, + "filter": "url(#blur5)", + "data-top": 20, + "data-right": 15, + "data-bottom": 15, + "data-left": 10 } } diff --git a/styles/light.json b/styles/light.json index 358f3315..955c7091 100644 --- a/styles/light.json +++ b/styles/light.json @@ -261,12 +261,10 @@ "#texture": { "opacity": 0.4, "filter": null, - "mask": "" - }, - "#textureImage": { - "x": 0, - "y": 0, - "src": "https://i2.wp.com/azgaar.files.wordpress.com/2021/10/plaster.jpg" + "mask": "", + "data-x": 0, + "data-y": 0, + "data-href": "./images/textures/plaster.jpg" }, "#zones": { "opacity": 0.6, @@ -288,13 +286,24 @@ "href": "./images/pattern1.png", "opacity": 0.2 }, - "#terrs": { + "#terrs > #oceanHeights": { + "data-render": 1, "opacity": 0.4, - "scheme": "light", + "scheme": "bright", + "terracing": 0, + "skip": 0, + "relax": 1, + "curve": "curveBasisClosed", + "filter": "url(#turbulence)", + "mask": null + }, + "#terrs > #landHeights": { + "opacity": 0.4, + "scheme": "bright", "terracing": 10, "skip": 5, "relax": 0, - "curve": 0, + "curve": "curveBasisClosed", "filter": "url(#turbulence)", "mask": "url(#land)" }, @@ -386,5 +395,39 @@ "opacity": 1, "fill": "#30426f", "filter": null + }, + "#vignette": { + "opacity": 0.15, + "fill": "#000000", + "filter": null + }, + "#vignette-rect": { + "x": "0.2%", + "y": "0.3%", + "width": "99.8%", + "height": "99.4%", + "rx": "5%", + "ry": "5%", + "filter": "blur(20px)" + }, + "#scaleBar": { + "opacity": 1, + "fill": "#353540", + "font-size": 10, + "data-bar-size": 2, + "data-x": 99, + "data-y": 99, + "data-label": "" + }, + "#scaleBarBack": { + "opacity": 0.2, + "fill": "#ffffff", + "stroke": "#000000", + "stroke-width": 1, + "filter": "url(#blur5)", + "data-top": 20, + "data-right": 15, + "data-bottom": 15, + "data-left": 10 } } diff --git a/styles/monochrome.json b/styles/monochrome.json index a4273144..c0810154 100644 --- a/styles/monochrome.json +++ b/styles/monochrome.json @@ -251,12 +251,10 @@ "#texture": { "opacity": 0.2, "filter": null, - "mask": "url(#land)" - }, - "#textureImage": { - "x": 0, - "y": 0, - "src": "https://i2.wp.com/azgaar.files.wordpress.com/2021/10/plaster.jpg" + "mask": "url(#land)", + "data-x": 0, + "data-y": 0, + "data-href": "./images/textures/plaster.jpg" }, "#emblems": { "opacity": 0.5, @@ -283,14 +281,25 @@ "href": "", "opacity": 0.2 }, - "#terrs": { + "#terrs #oceanHeights": { + "data-render": 1, "opacity": 1, "scheme": "monochrome", "terracing": 0, - "skip": 5, - "relax": 0, - "curve": 0, - "filter": "url(#blur3)", + "skip": 0, + "relax": 1, + "curve": "curveBasisClosed", + "filter": "url(#turbulence)", + "mask": null + }, + "#terrs #landHeights": { + "opacity": 1, + "scheme": "monochrome", + "terracing": 0, + "skip": 0, + "relax": 1, + "curve": "curveBasisClosed", + "filter": "url(#turbulence)", "mask": "url(#land)" }, "#legend": { @@ -382,5 +391,39 @@ "opacity": 0.98, "fill": "#30426f", "filter": null + }, + "#vignette": { + "opacity": 0.3, + "fill": "#000000", + "filter": null + }, + "#vignette-rect": { + "x": "0.3%", + "y": "0.4%", + "width": "99.6%", + "height": "99.2%", + "rx": "5%", + "ry": "5%", + "filter": "blur(20px)" + }, + "#scaleBar": { + "opacity": 1, + "fill": "#ffffff", + "font-size": 8, + "data-bar-size": 1.5, + "data-x": 99, + "data-y": 99, + "data-label": "" + }, + "#scaleBarBack": { + "opacity": 0, + "fill": "#ffffff", + "stroke": "#000000", + "stroke-width": 1, + "filter": "", + "data-top": 18, + "data-right": 15, + "data-bottom": 15, + "data-left": 10 } } diff --git a/styles/night.json b/styles/night.json new file mode 100644 index 00000000..dbbcf0bf --- /dev/null +++ b/styles/night.json @@ -0,0 +1,433 @@ +{ + "#map": { + "background-color": "#000000", + "filter": null, + "data-filter": null + }, + "#armies": { + "font-size": 6, + "box-size": 3, + "stroke": "#000", + "stroke-width": 0, + "fill-opacity": 0.4, + "filter": "" + }, + "#biomes": { + "opacity": 1, + "filter": null, + "mask": "url(#land)" + }, + "#stateBorders": { + "opacity": 0.4, + "stroke": "#ffffff", + "stroke-width": 0.67, + "stroke-dasharray": "", + "stroke-linecap": "square", + "filter": "url(#outline)" + }, + "#provinceBorders": { + "opacity": 0.4, + "stroke": "#f0f2e3", + "stroke-width": 0.2, + "stroke-dasharray": 0.5, + "stroke-linecap": "square", + "filter": "" + }, + "#cells": { + "opacity": null, + "stroke": "#808080", + "stroke-width": 0.1, + "filter": null, + "mask": null + }, + "#gridOverlay": { + "opacity": 0.8, + "scale": 2, + "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": "#465053", + "stroke-width": 1, + "stroke-dasharray": 5, + "stroke-linecap": "butt", + "filter": "", + "mask": null + }, + "#compass": { + "opacity": 1, + "transform": null, + "filter": null, + "mask": "url(#water)", + "shape-rendering": "optimizespeed" + }, + "#rose": { + "transform": "translate(80 80) scale(0.25)" + }, + "#relig": { + "opacity": 0.4, + "stroke": "#404040", + "stroke-width": 0.7, + "filter": null + }, + "#cults": { + "opacity": 0.4, + "stroke": "#777777", + "stroke-width": 1.5, + "stroke-dasharray": null, + "stroke-linecap": null, + "filter": "url(#dropShadow)" + }, + "#landmass": { + "opacity": 1, + "fill": "#04121a", + "filter": null + }, + "#markers": { + "opacity": 1, + "rescale": null, + "filter": "url(#dropShadow01)" + }, + "#prec": { + "opacity": null, + "stroke": "#ffffff", + "stroke-width": 0, + "fill": "#5069b9", + "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.62, + "fill": "#00050a", + "stroke": "#000000", + "stroke-width": 0.43, + "filter": "url(#dropShadow)" + }, + "#salt": { + "opacity": 0.62, + "fill": "#000a0a", + "stroke": "#173634", + "stroke-width": 1.72, + "filter": "url(#dropShadow)" + }, + "#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.62, + "fill": "#c9bfa7", + "stroke": "#000000", + "stroke-width": 1.72, + "filter": "url(#dropShadow)" + }, + "#sea_island": { + "opacity": 1, + "stroke": "#000000", + "stroke-width": 0.29, + "filter": "", + "auto-filter": null + }, + "#lake_island": { + "opacity": 1, + "stroke": "#7c8eaf", + "stroke-width": 0.35, + "filter": null + }, + "#terrain": { + "opacity": 0.54, + "set": "simple", + "size": 1, + "density": 0.3, + "filter": null, + "mask": null + }, + "#rivers": { + "opacity": null, + "filter": "", + "fill": "#00050a" + }, + "#ruler": { + "opacity": 1, + "filter": null + }, + "#roads": { + "opacity": 0.72, + "stroke": "#7f96f0", + "stroke-width": 0.75, + "stroke-dasharray": 0, + "stroke-linecap": "butt", + "filter": "", + "mask": "url(#land)" + }, + "#trails": { + "opacity": 0.62, + "stroke": "#7f96f0", + "stroke-width": 0.35, + "stroke-dasharray": 0, + "stroke-linecap": "butt", + "filter": "", + "mask": null + }, + "#searoutes": { + "opacity": 1, + "stroke": "#7f96f0", + "stroke-width": 0.5, + "stroke-dasharray": "2 1", + "stroke-linecap": "butt", + "filter": "", + "mask": "" + }, + "#statesBody": { + "opacity": 0.07, + "filter": "" + }, + "#statesHalo": { + "opacity": 0, + "data-width": 0, + "stroke-width": 0, + "filter": null + }, + "#provs": { + "opacity": 0.4, + "fill": null, + "font-size": null, + "font-family": null, + "filter": "" + }, + "#temperature": { + "opacity": 1, + "font-size": "12px", + "fill": "#000000", + "fill-opacity": 1, + "stroke": null, + "stroke-width": 1.5, + "stroke-dasharray": null, + "stroke-linecap": null, + "filter": "" + }, + "#ice": { + "opacity": 0.15, + "fill": "#e8f0f6", + "stroke": "#e8f0f6", + "stroke-width": 0, + "filter": "" + }, + "#emblems": { + "opacity": null, + "stroke-width": null, + "filter": null + }, + "#texture": { + "opacity": 0.1, + "filter": null, + "mask": "url(#water)", + "data-x": 0, + "data-y": 0, + "data-href": "./images/textures/marble-blue-small.jpg" + }, + "#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": "#000000" + }, + "#oceanicPattern": { + "href": "", + "opacity": 0.3 + }, + "#terrs > #oceanHeights": { + "data-render": 1, + "opacity": 0.5, + "scheme": "livid", + "terracing": 0, + "skip": 0, + "relax": 1, + "curve": "curveBasisClosed", + "filter": null, + "mask": null + }, + "#terrs > #landHeights": { + "opacity": 1, + "scheme": "livid", + "terracing": 0, + "skip": 10, + "relax": 0, + "curve": "curveBasisClosed", + "filter": null, + "mask": "url(#land)" + }, + "#legend": { + "data-size": 11.7, + "font-size": 11.7, + "font-family": "MedievalSharp", + "stroke": "#812929", + "stroke-width": 2.67, + "stroke-dasharray": "0 4 10 4", + "stroke-linecap": "square", + "data-x": 14.26, + "data-y": 99.37, + "data-columns": null + }, + "#burgLabels > #cities": { + "opacity": 1, + "fill": "#dbdbe1", + "text-shadow": "black 0px 0px 4px", + "data-size": 8, + "font-size": 8, + "font-family": "Courier New" + }, + "#burgIcons > #cities": { + "opacity": 1, + "fill": "#ffffff", + "fill-opacity": 0.7, + "size": 2.1, + "stroke": "#000000", + "stroke-width": 0.2, + "stroke-dasharray": "", + "stroke-linecap": "butt" + }, + "#anchors > #cities": { + "opacity": 1, + "fill": "#ffffff", + "size": 4.2, + "stroke": "#000000", + "stroke-width": 1.46 + }, + "#burgLabels > #towns": { + "opacity": 1, + "fill": "#ffffff", + "text-shadow": "black 0px 0px 4px", + "data-size": 4.28, + "font-size": 4.28, + "font-family": "Courier New" + }, + "#burgIcons > #towns": { + "opacity": 1, + "fill": "#ffffff", + "fill-opacity": 0.7, + "size": 0.8, + "stroke": "#000000", + "stroke-width": 0.1, + "stroke-dasharray": "", + "stroke-linecap": "butt" + }, + "#anchors > #towns": { + "opacity": 1, + "fill": "#ffffff", + "size": 1.6, + "stroke": "#000000", + "stroke-width": 1.53 + }, + "#labels > #states": { + "opacity": 1, + "fill": "#5d77a2", + "stroke": "#7a83ae", + "stroke-width": 0.3, + "text-shadow": "black 0px 0px 0.1px", + "data-size": 14, + "font-size": 14, + "font-family": "Courier New", + "filter": "" + }, + "#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.8, + "fill": "#000000", + "filter": null + }, + "#vignette": { + "opacity": 0, + "fill": "#000000", + "filter": null + }, + "#vignette-rect": { + "x": "0.3%", + "y": "0.4%", + "width": "99.6%", + "height": "99.2%", + "rx": "5%", + "ry": "5%", + "filter": "blur(20px)" + }, + "#scaleBar": { + "opacity": 1, + "fill": "#b5c1d4", + "font-size": 11, + "data-bar-size": 2, + "data-x": 99, + "data-y": 99, + "data-label": "" + }, + "#scaleBarBack": { + "opacity": 0.5, + "fill": "#0a1e24", + "stroke": "#40547a", + "stroke-width": 1, + "filter": "", + "data-top": 22, + "data-right": 15, + "data-bottom": 16, + "data-left": 10 + } +} diff --git a/styles/pale.json b/styles/pale.json index a0c444e1..883c614b 100644 --- a/styles/pale.json +++ b/styles/pale.json @@ -261,12 +261,10 @@ "#texture": { "opacity": 0.4, "filter": null, - "mask": "url(#land)" - }, - "#textureImage": { - "x": 0, - "y": 0, - "src": "https://i2.wp.com/azgaar.files.wordpress.com/2021/10/plaster.jpg" + "mask": "url(#land)", + "data-x": 0, + "data-y": 0, + "data-href": "./images/textures/plaster.jpg" }, "#zones": { "opacity": 0.6, @@ -288,14 +286,25 @@ "href": "./images/kiwiroo.png", "opacity": 0.3 }, - "#terrs": { + "#terrs > #oceanHeights": { + "data-render": 0, + "opacity": 0.7, + "scheme": "bright", + "terracing": 0, + "skip": 0, + "relax": 1, + "curve": "curveBasisClosed", + "filter": null, + "mask": null + }, + "#terrs > #landHeights": { "opacity": 0.7, "scheme": "bright", "terracing": 0, "skip": 2, "relax": 1, - "curve": 0, - "filter": "", + "curve": "curveBasisClosed", + "filter": null, "mask": "url(#land)" }, "#legend": { @@ -386,5 +395,39 @@ "opacity": 1, "fill": "#30426f", "filter": null + }, + "#vignette": { + "opacity": 0.2, + "fill": "#000000", + "filter": null + }, + "#vignette-rect": { + "x": "0.3%", + "y": "0.4%", + "width": "99.6%", + "height": "99.2%", + "rx": "5%", + "ry": "5%", + "filter": "blur(30px)" + }, + "#scaleBar": { + "opacity": 1, + "fill": "#353540", + "font-size": 10, + "data-bar-size": 2, + "data-x": 99, + "data-y": 99, + "data-label": "" + }, + "#scaleBarBack": { + "opacity": 0.2, + "fill": "#ffffff", + "stroke": "#000000", + "stroke-width": 1, + "filter": "url(#blur5)", + "data-top": 20, + "data-right": 15, + "data-bottom": 15, + "data-left": 10 } } diff --git a/styles/watercolor.json b/styles/watercolor.json index b0bda134..2605433c 100644 --- a/styles/watercolor.json +++ b/styles/watercolor.json @@ -261,12 +261,10 @@ "#texture": { "opacity": 0.2, "filter": null, - "mask": "url(#land)" - }, - "#textureImage": { - "x": 0, - "y": 0, - "src": "https://i2.wp.com/azgaar.files.wordpress.com/2021/10/plaster.jpg" + "mask": "url(#land)", + "data-x": 0, + "data-y": 0, + "data-href": "./images/textures/plaster.jpg" }, "#zones": { "opacity": 0.6, @@ -288,13 +286,24 @@ "href": "./images/kiwiroo.png", "opacity": 0.5 }, - "#terrs": { + "#terrs > #oceanHeights": { + "data-render": 1, + "opacity": 0.5, + "scheme": "light", + "terracing": 0, + "skip": 0, + "relax": 1, + "curve": "curveBasisClosed", + "filter": null, + "mask": null + }, + "#terrs > #landHeights": { "opacity": 0.5, "scheme": "light", "terracing": 0, "skip": 5, "relax": 1, - "curve": 0, + "curve": "curveBasisClosed", "filter": null, "mask": "url(#land)" }, @@ -386,5 +395,39 @@ "opacity": 0.97, "fill": "#8398ce", "filter": null + }, + "#vignette": { + "opacity": 0.2, + "fill": "#000000", + "filter": null + }, + "#vignette-rect": { + "x": "0.3%", + "y": "0.4%", + "width": "99.6%", + "height": "99.2%", + "rx": "5%", + "ry": "5%", + "filter": "blur(20px)" + }, + "#scaleBar": { + "opacity": 1, + "fill": "#353540", + "font-size": 10, + "data-bar-size": 2, + "data-x": 99, + "data-y": 99, + "data-label": "" + }, + "#scaleBarBack": { + "opacity": 0.2, + "fill": "#ffffff", + "stroke": "#000000", + "stroke-width": 1, + "filter": "url(#blur5)", + "data-top": 20, + "data-right": 15, + "data-bottom": 15, + "data-left": 10 } } diff --git a/utils/graphUtils.js b/utils/graphUtils.js index 780dc931..ec6fb59a 100644 --- a/utils/graphUtils.js +++ b/utils/graphUtils.js @@ -325,11 +325,12 @@ function drawCellsValue(data) { .text(d => d); } -// helper function non-used for the generation +// helper function non-used for the main generation function drawPolygons(data) { - const max = d3.max(data), - min = d3.min(data), - scheme = getColorScheme(terrs.attr("scheme")); + const max = d3.max(data); + const min = d3.min(data); + const scheme = getColorScheme(terrs.select("#landHeights").attr("scheme")); + data = data.map(d => 1 - normalize(d, min, max)); debug.selectAll("polygon").remove(); @@ -338,7 +339,32 @@ function drawPolygons(data) { .data(data) .enter() .append("polygon") - .attr("points", (d, i) => getPackPolygon(i)) + .attr("points", (d, i) => getGridPolygon(i)) .attr("fill", d => scheme(d)) .attr("stroke", d => scheme(d)); } + +// draw raster heightmap preview (not used in main generation) +function drawHeights({heights, width, height, scheme, renderOcean}) { + const canvas = document.createElement("canvas"); + canvas.width = width; + canvas.height = height; + const ctx = canvas.getContext("2d"); + const imageData = ctx.createImageData(width, height); + + const getHeight = height => (height < 20 ? (renderOcean ? height : 0) : height); + + for (let i = 0; i < heights.length; i++) { + const color = scheme(1 - getHeight(heights[i]) / 100); + const {r, g, b} = d3.color(color); + + const n = i * 4; + imageData.data[n] = r; + imageData.data[n + 1] = g; + imageData.data[n + 2] = b; + imageData.data[n + 3] = 255; + } + + ctx.putImageData(imageData, 0, 0); + return canvas.toDataURL("image/png"); +} diff --git a/utils/polyfills.js b/utils/polyfills.js index 667d81ab..ffc10f74 100644 --- a/utils/polyfills.js +++ b/utils/polyfills.js @@ -15,6 +15,15 @@ if (Array.prototype.flat === undefined) { }; } +// at +if (Array.prototype.at === undefined) { + Array.prototype.at = function (index) { + if (index < 0) index += this.length; + if (index < 0 || index >= this.length) return undefined; + return this[index]; + }; +} + // readable stream iterator: https://bugs.chromium.org/p/chromium/issues/detail?id=929585#c10 if (ReadableStream.prototype[Symbol.asyncIterator] === undefined) { ReadableStream.prototype[Symbol.asyncIterator] = async function* () { diff --git a/versioning.js b/versioning.js index 564a69b2..1574e729 100644 --- a/versioning.js +++ b/versioning.js @@ -1,7 +1,7 @@ "use strict"; // version and caching control -const version = "1.93.04"; // generator version, update each time +const version = "1.97.04"; // generator version, update each time { document.title += " v" + version; @@ -28,6 +28,12 @@ const version = "1.93.04"; // generator version, update each time
      Latest changes: +
    • Preview villages map
    • +
    • Ability to render ocean heightmap
    • +
    • Scale bar styling features
    • +
    • Vignette visual layer and vignette styling options
    • +
    • Ability to define custom heightmap color scheme
    • +
    • New style preset Night and new heightmap color schemes
    • Random encounter markers (integration with Deorum)
    • Auto-load of the last saved map is now optional (see Onload behavior in Options)
    • New label placement algorithm for states
    • @@ -37,8 +43,6 @@ const version = "1.93.04"; // generator version, update each time
    • New 3D scene options and improvements
    • Autosave feature (in Options)
    • Google translation support (in Options)
    • -
    • Religions can be edited and redrawn like cultures
    • -
    • Lock states, provinces, cultures, and religions from regeneration

    Join our Discord server and Reddit community to ask questions, share maps, discuss the Generator and Worlbuilding, report bugs and propose new features.