11const $body = insertEditorHtml ( ) ;
22addListeners ( ) ;
3+ let statesManualHistory = [ ] ;
34
45export function open ( ) {
56 closeDialogs ( "#statesEditor, .stable" ) ;
@@ -71,11 +72,16 @@ function insertEditorHtml() {
7172
7273 <button id="statesManually" data-tip="Manually re-assign states" class="icon-brush"></button>
7374 <div id="statesManuallyButtons" style="display: none">
74- <div data-tip="Change brush size. Shortcut : + to increase; – to decrease" style="margin-block: 0.3em;">
75+ <div data-tip="Change brush size. Shortcuts : + / ] to increase; - / [ to decrease" style="margin-block: 0.3em;">
7576 <slider-input id="statesBrush" min="1" max="100" value="15">Brush size:</slider-input>
7677 </div>
78+ <button id="statesManuallyUndo" data-tip="Undo last brush stroke" class="icon-ccw"></button>
7779 <button id="statesManuallyApply" data-tip="Apply assignment" class="icon-check"></button>
7880 <button id="statesManuallyCancel" data-tip="Cancel assignment" class="icon-cancel"></button>
81+ <div data-tip="When enabled, only neutral cells can be painted" style="display: inline-block">
82+ <input id="statesManuallyProtect" class="checkbox" type="checkbox" />
83+ <label for="statesManuallyProtect" class="checkbox-label"><i>do not overwrite existing</i></label>
84+ </div>
7985 </div>
8086
8187 <button id="statesAdd" data-tip="Add a new state. Hold Shift to add multiple" class="icon-plus"></button>
@@ -102,6 +108,7 @@ function addListeners() {
102108 byId ( "statesRandomize" ) . on ( "click" , randomizeStatesExpansion ) ;
103109 byId ( "statesGrowthRate" ) . on ( "input" , ( ) => recalculateStates ( false ) ) ;
104110 byId ( "statesManually" ) . on ( "click" , enterStatesManualAssignent ) ;
111+ byId ( "statesManuallyUndo" ) . on ( "click" , undoStatesManualAssignment ) ;
105112 byId ( "statesManuallyApply" ) . on ( "click" , applyStatesManualAssignent ) ;
106113 byId ( "statesManuallyCancel" ) . on ( "click" , ( ) => exitStatesManualAssignment ( false ) ) ;
107114 byId ( "statesAdd" ) . on ( "click" , enterAddStateMode ) ;
@@ -249,8 +256,8 @@ function statesEditorAddLines() {
249256 <span data-tip="${ populationTip } " class="icon-male hide"></span>
250257 <div data-tip="${ populationTip } " class="statePopulation pointer hide" style="width: 5em">${ si ( population ) } </div>
251258 <select data-tip="State type. Defines growth model. Click to change" class="cultureType ${ hidden } show hide">${ getTypeOptions (
252- s . type
253- ) } </select>
259+ s . type
260+ ) } </select>
254261 <span data-tip="State expansionism" class="icon-resize-full ${ hidden } show hide"></span>
255262 <input data-tip="Expansionism (defines competitive size). Change to re-calculate states based on new value"
256263 class="statePower ${ hidden } show hide" type="number" min="0" max="99" step=".1" value=${ s . expansionism } />
@@ -771,12 +778,12 @@ function showStatesChart() {
771778 option === "area"
772779 ? "Area: " + area
773780 : option === "rural"
774- ? "Rural population: " + si ( rural )
775- : option === "urban"
776- ? "Urban population: " + si ( urban )
777- : option === "burgs"
778- ? "Burgs number: " + d . data . burgs
779- : "Population: " + si ( rural + urban ) ;
781+ ? "Rural population: " + si ( rural )
782+ : option === "urban"
783+ ? "Urban population: " + si ( urban )
784+ : option === "burgs"
785+ ? "Burgs number: " + d . data . burgs
786+ : "Population: " + si ( rural + urban ) ;
780787
781788 statesInfo . innerHTML = /* html */ `${ state } . ${ value } ` ;
782789 stateHighlightOn ( ev ) ;
@@ -794,12 +801,12 @@ function showStatesChart() {
794801 this . value === "area"
795802 ? d => d . area
796803 : this . value === "rural"
797- ? d => d . rural
798- : this . value === "urban"
799- ? d => d . urban
800- : this . value === "burgs"
801- ? d => d . burgs
802- : d => d . rural + d . urban ;
804+ ? d => d . rural
805+ : this . value === "urban"
806+ ? d => d . urban
807+ : this . value === "burgs"
808+ ? d => d . burgs
809+ : d => d . rural + d . urban ;
803810
804811 root . sum ( value ) ;
805812 node . data ( treeLayout ( root ) . leaves ( ) ) ;
@@ -903,6 +910,7 @@ function enterStatesManualAssignent() {
903910 . on ( "touchmove mousemove" , moveStateBrush ) ;
904911
905912 $body . querySelector ( "div" ) . classList . add ( "selected" ) ;
913+ statesManualHistory = [ ] ;
906914}
907915
908916function selectStateOnLineClick ( ) {
@@ -926,6 +934,7 @@ function selectStateOnMapClick() {
926934
927935function dragStateBrush ( ) {
928936 const r = + statesBrush . value ;
937+ saveStatesManualSnapshot ( ) ;
929938
930939 d3 . event . on ( "drag" , ( ) => {
931940 if ( ! d3 . event . dx && ! d3 . event . dy ) return ;
@@ -945,11 +954,13 @@ function changeStateForSelection(selection) {
945954 const $selected = $body . querySelector ( "div.selected" ) ;
946955 const stateNew = + $selected . dataset . id ;
947956 const color = pack . states [ stateNew ] . color || "#ffffff" ;
957+ const preventOverwrite = byId ( "statesManuallyProtect" ) ?. checked ;
948958
949959 selection . forEach ( function ( i ) {
950960 const exists = temp . select ( "polygon[data-cell='" + i + "']" ) ;
951961 const stateOld = exists . size ( ) ? + exists . attr ( "data-state" ) : pack . cells . state [ i ] ;
952962 if ( stateNew === stateOld ) return ;
963+ if ( preventOverwrite && stateOld ) return ;
953964 if ( i === pack . states [ stateOld ] . center ) return ;
954965
955966 // change of append new element
@@ -1148,6 +1159,7 @@ function adjustProvinces(affectedProvinces) {
11481159
11491160function exitStatesManualAssignment ( close ) {
11501161 customization = 0 ;
1162+ statesManualHistory = [ ] ;
11511163 statesBody . select ( "#temp" ) . remove ( ) ;
11521164 removeCircle ( ) ;
11531165 document . querySelectorAll ( "#statesBottom > button" ) . forEach ( el => ( el . style . display = "inline-block" ) ) ;
@@ -1168,6 +1180,21 @@ function exitStatesManualAssignment(close) {
11681180 if ( selected ) selected . classList . remove ( "selected" ) ;
11691181}
11701182
1183+ function saveStatesManualSnapshot ( ) {
1184+ const temp = statesBody . select ( "#temp" ) . node ( ) ;
1185+ if ( ! temp ) return ;
1186+
1187+ statesManualHistory . push ( temp . innerHTML ) ;
1188+ if ( statesManualHistory . length > 100 ) statesManualHistory . shift ( ) ;
1189+ }
1190+
1191+ function undoStatesManualAssignment ( ) {
1192+ const temp = statesBody . select ( "#temp" ) . node ( ) ;
1193+ if ( ! temp || ! statesManualHistory . length ) return ;
1194+
1195+ temp . innerHTML = statesManualHistory . pop ( ) ;
1196+ }
1197+
11711198function enterAddStateMode ( ) {
11721199 if ( this . classList . contains ( "pressed" ) ) {
11731200 exitAddStateMode ( ) ;
0 commit comments