feat: style scale bar

This commit is contained in:
Azgaar 2023-12-03 14:13:43 +04:00
parent fec5f421ad
commit b9f3ff6da6
25 changed files with 540 additions and 246 deletions

View file

@ -1876,12 +1876,6 @@ div.editorLine {
margin: 0.4em 0 0 -0.9em; margin: 0.4em 0 0 -0.9em;
} }
#barBackColor {
width: 3.5em;
padding: 0px;
height: 1.2em;
}
#ruler { #ruler {
cursor: move; cursor: move;
fill: none; fill: none;
@ -1921,18 +1915,6 @@ div.editorLine {
stroke: #737373; stroke: #737373;
} }
#scaleBar {
stroke: none;
fill: none;
cursor: pointer;
}
#scaleBar text {
fill: #353540;
text-anchor: middle;
font-family: var(--serif);
}
#militaryOptionsTable select { #militaryOptionsTable select {
border: 1px solid #d4d4d4; border: 1px solid #d4d4d4;
} }

View file

@ -366,7 +366,9 @@
</mask> </mask>
</defs> </defs>
<g id="viewbox"></g> <g id="viewbox"></g>
<g id="scaleBar"></g> <g id="scaleBar">
<rect id="scaleBarBack"></rect>
</g>
<g id="vignette" mask="url(#vignette-mask)"> <g id="vignette" mask="url(#vignette-mask)">
<rect x="0" y="0" width="100%" height="100%" /> <rect x="0" y="0" width="100%" height="100%" />
</g> </g>
@ -799,6 +801,7 @@
<option value="rivers">Rivers</option> <option value="rivers">Rivers</option>
<option value="routes">Routes</option> <option value="routes">Routes</option>
<option value="ruler">Rulers</option> <option value="ruler">Rulers</option>
<option value="scaleBar">Scale Bar</option>
<option value="regions" selected>States</option> <option value="regions" selected>States</option>
<option value="temperature">Temperature</option> <option value="temperature">Temperature</option>
<option value="texture">Texture</option> <option value="texture">Texture</option>
@ -1446,6 +1449,84 @@
</td> </td>
</tr> </tr>
</tbody> </tbody>
<tbody id="styleScaleBar">
<tr data-tip="Set bar and font size">
<td>Size</td>
<td>
<span>Bar </span>
<input id="styleScaleBarSize" type="number" min=".5" max="5" step=".1" />
<span>Font </span>
<input id="styleScaleBarFontSize" type="number" min="1" max="100" step=".1" />
</td>
</tr>
<tr data-tip="Set position of the Scale bar bottom right corner (in percents)">
<td>Position</td>
<td>
<span>x </span>
<input id="styleScaleBarPositionX" type="number" min="0" max="100" step="0.1" style="width: 5em" />
<span>y </span>
<input id="styleScaleBarPositionY" type="number" min="0" max="100" step="0.1" style="width: 5em" />
</td>
</tr>
<tr data-tip="Type scale bar label, leave blank to hide label">
<td>Label</td>
<td>
<input id="styleScaleBarLabel" type="text" />
</td>
</tr>
<tr data-tip="Set background opacity. 0: transparent, 1: solid">
<td>Back opacity</td>
<td>
<input id="styleScaleBarBackgroundOpacityInput" type="range" min="0" max="1" step="0.01" />
<output id="styleScaleBarBackgroundOpacityOutput"></output>
</td>
</tr>
<tr data-tip="Set background fill color">
<td>Back fill</td>
<td>
<input id="styleScaleBarBackgroundFillInput" type="color" />
<output id="styleScaleBarBackgroundFillOutput"></output>
</td>
</tr>
<tr data-tip="Set background stroke color and width">
<td>Back stroke</td>
<td>
<input id="styleScaleBarBackgroundStrokeInput" type="color" />
<output id="styleScaleBarBackgroundStrokeOutput"></output>
<span>Width </span>
<input
id="styleScaleBarBackgroundStrokeWidth"
type="number"
min="0"
max="10"
step="0.1"
style="width: 5em"
/>
</td>
</tr>
<tr data-tip="Set background element padding: top, right, bottom, left (in pixels)">
<td>Back padding</td>
<td style="display: flex; gap: 4px">
<input id="styleScaleBarBackgroundPaddingTop" type="number" min="0" max="100" style="width: 5em" />
<input id="styleScaleBarBackgroundPaddingRight" type="number" min="0" max="100" style="width: 5em" />
<input id="styleScaleBarBackgroundPaddingBottom" type="number" min="0" max="100" style="width: 5em" />
<input id="styleScaleBarBackgroundPaddingLeft" type="number" min="0" max="100" style="width: 5em" />
</td>
</tr>
<tr data-tip="Select background filter">
<td>Back filter</td>
<td><select id="styleScaleBarBackgroundFilter" /></td>
</tr>
</tbody>
</table> </table>
<div id="mapFilters" data-tip="Set a filter to be applied to the map in general"> <div id="mapFilters" data-tip="Set a filter to be applied to the map in general">
@ -5132,49 +5213,6 @@
</select> </select>
</div> </div>
<div class="unitsHeader">
<span class="icon-minus"></span>
<div>Scale bar:</div>
</div>
<div data-tip="Set scale bar size">
<div>Bar size:</div>
<input id="barSizeOutput" data-stored="barSize" type="range" min=".5" max="5" value="2" step=".1" />
<input id="barSizeInput" data-stored="barSize" type="number" min=".5" max="5" value="2" step=".1" />
</div>
<div data-tip="Type scale bar label, leave blank to hide label">
<div>Bar label:</div>
<input id="barLabel" data-stored="barLabel" type="text" placeholder="hidden" value="" />
</div>
<div data-tip="Set background for Scale bar">
<div>Bar background:</div>
<input
id="barBackOpacity"
data-stored="barBackOpacity"
type="range"
min="0"
max="1"
value=".2"
step=".01"
/>
<input id="barBackColor" data-stored="barBackColor" type="color" value="#ffffff" />
</div>
<div data-tip="Set position of the Scale bar bottom right corner in percents">
<div>Bar position:</div>
x:<input id="barPosX" data-stored="barPosX" type="number" min="0" max="100" step=".1" value="99" /> y:<input
id="barPosY"
data-stored="barPosY"
type="number"
min="0"
max="100"
step=".1"
value="99"
/>
</div>
<div class="unitsHeader"> <div class="unitsHeader">
<span class="icon-male"></span> <span class="icon-male"></span>
<div>Population:</div> <div>Population:</div>
@ -7994,16 +8032,16 @@
<script src="libs/lineclip.min.js"></script> <script src="libs/lineclip.min.js"></script>
<script src="libs/alea.min.js"></script> <script src="libs/alea.min.js"></script>
<script src="modules/fonts.js?v=1.89.18"></script> <script src="modules/fonts.js?v=1.89.18"></script>
<script src="modules/ui/layers.js?v=1.94.00"></script> <script src="modules/ui/layers.js?v=1.96.00"></script>
<script src="modules/ui/measurers.js?v=1.94.03"></script> <script src="modules/ui/measurers.js?v=1.96.00"></script>
<script src="modules/ui/stylePresets.js?v=1.95.00"></script> <script src="modules/ui/stylePresets.js?v=1.96.00"></script>
<script src="modules/ui/general.js?v=1.94.01"></script> <script src="modules/ui/general.js?v=1.94.01"></script>
<script src="modules/ui/options.js?v=1.94.06"></script> <script src="modules/ui/options.js?v=1.96.00"></script>
<script src="main.js?v=1.94.05"></script> <script src="main.js?v=1.96.00"></script>
<script defer src="modules/relief-icons.js"></script> <script defer src="modules/relief-icons.js"></script>
<script defer src="modules/ui/style.js?v=1.95.00"></script> <script defer src="modules/ui/style.js?v=1.96.00"></script>
<script defer src="modules/ui/editors.js?v=1.93.10"></script> <script defer src="modules/ui/editors.js?v=1.93.10"></script>
<script defer src="modules/ui/tools.js?v=1.92.00"></script> <script defer src="modules/ui/tools.js?v=1.92.00"></script>
<script defer src="modules/ui/world-configurator.js?v=1.91.05"></script> <script defer src="modules/ui/world-configurator.js?v=1.91.05"></script>
@ -8022,7 +8060,7 @@
<script defer src="modules/ui/rivers-creator.js?v=1.89.13"></script> <script defer src="modules/ui/rivers-creator.js?v=1.89.13"></script>
<script defer src="modules/ui/relief-editor.js"></script> <script defer src="modules/ui/relief-editor.js"></script>
<script defer src="modules/ui/burg-editor.js"></script> <script defer src="modules/ui/burg-editor.js"></script>
<script defer src="modules/ui/units-editor.js?v=1.94.02"></script> <script defer src="modules/ui/units-editor.js?v=1.96.00"></script>
<script defer src="modules/ui/notes-editor.js?v=1.93.09"></script> <script defer src="modules/ui/notes-editor.js?v=1.93.09"></script>
<script defer src="modules/ui/diplomacy-editor.js?v=1.88.04"></script> <script defer src="modules/ui/diplomacy-editor.js?v=1.88.04"></script>
<script defer src="modules/ui/zones-editor.js"></script> <script defer src="modules/ui/zones-editor.js"></script>
@ -8041,10 +8079,10 @@
<script defer src="modules/coa-renderer.js?v=1.94.00"></script> <script defer src="modules/coa-renderer.js?v=1.94.00"></script>
<script defer src="libs/rgbquant.min.js"></script> <script defer src="libs/rgbquant.min.js"></script>
<script defer src="libs/jquery.ui.touch-punch.min.js"></script> <script defer src="libs/jquery.ui.touch-punch.min.js"></script>
<script defer src="modules/io/save.js?v=1.93.02"></script> <script defer src="modules/io/save.js?v=1.96.00"></script>
<script defer src="modules/io/load.js?v=1.95.00"></script> <script defer src="modules/io/load.js?v=1.96.00"></script>
<script defer src="modules/io/cloud.js?v=1.94.04"></script> <script defer src="modules/io/cloud.js?v=1.94.04"></script>
<script defer src="modules/io/export.js?v=1.94.03"></script> <script defer src="modules/io/export.js?v=1.96.00"></script>
<script defer src="modules/io/formats.js"></script> <script defer src="modules/io/formats.js"></script>
<!-- Web Components --> <!-- Web Components -->

View file

@ -135,7 +135,6 @@ fogging
.attr("filter", "url(#splotch)"); .attr("filter", "url(#splotch)");
// assign events separately as not a viewbox child // assign events separately as not a viewbox child
scaleBar.on("mousemove", () => tip("Click to open Units Editor")).on("click", () => editUnits());
legend legend
.on("mousemove", () => tip("Drag to change the position. Click to hide the legend")) .on("mousemove", () => tip("Drag to change the position. Click to hide the legend"))
.on("click", () => clearLegend()); .on("click", () => clearLegend());

View file

@ -736,4 +736,38 @@ export function resolveVersionConflicts(version) {
.style("display", "none"); .style("display", "none");
vignette.append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%"); vignette.append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%");
} }
if (version < 1.96) {
// v1.96.00 moved scaleBar options from units editor to style
d3.select("#scaleBar").remove();
scaleBar = svg
.insert("g", "#viewbox + *")
.attr("id", "scaleBar")
.attr("opacity", 1)
.attr("fill", "#353540")
.attr("font-size", 10)
.attr("data-size", 2)
.attr("data-x", 99)
.attr("data-y", 99)
.attr("data-label", "");
scaleBar
.append("rect")
.attr("id", "scaleBarBack")
.attr("opacity", 0.2)
.attr("fill", "#ffffff")
.attr("stroke", "#000000")
.attr("stroke-width", 1)
.attr("filter", "url(#blur5)")
.attr("data-top", 20)
.attr("data-right", 15)
.attr("data-bottom", 15)
.attr("data-left", 10);
drawScaleBar(scaleBar, scale);
fitScaleBar(scaleBar, svgWidth, svgHeight);
if (!layerIsOn("toggleScaleBar")) scaleBar.style("display", "none");
}
} }

View file

@ -88,12 +88,6 @@ function getSettings() {
heightUnit: heightUnit.value, heightUnit: heightUnit.value,
heightExponent: heightExponentInput.value, heightExponent: heightExponentInput.value,
temperatureScale: temperatureScale.value, temperatureScale: temperatureScale.value,
barSize: barSizeInput.value,
barLabel: barLabel.value,
barBackOpacity: barBackOpacity.value,
barBackColor: barBackColor.value,
barPosX: barPosX.value,
barPosY: barPosY.value,
populationRate: populationRate, populationRate: populationRate,
urbanization: urbanization, urbanization: urbanization,
mapSize: mapSizeOutput.value, mapSize: mapSizeOutput.value,

View file

@ -218,6 +218,7 @@ async function parseLoadedData(data) {
INFO && console.group("Loaded Map " + seed); INFO && console.group("Loaded Map " + seed);
// TODO: move all to options object
void (function parseSettings() { void (function parseSettings() {
const settings = data[1].split("|"); const settings = data[1].split("|");
if (settings[0]) applyOption(distanceUnitInput, settings[0]); if (settings[0]) applyOption(distanceUnitInput, settings[0]);
@ -226,23 +227,16 @@ async function parseLoadedData(data) {
if (settings[3]) applyOption(heightUnit, settings[3]); if (settings[3]) applyOption(heightUnit, settings[3]);
if (settings[4]) heightExponentInput.value = heightExponentOutput.value = settings[4]; if (settings[4]) heightExponentInput.value = heightExponentOutput.value = settings[4];
if (settings[5]) temperatureScale.value = settings[5]; if (settings[5]) temperatureScale.value = settings[5];
if (settings[6]) barSizeInput.value = barSizeOutput.value = settings[6]; // setting 6-11 (scaleBar) are part of style now, kept as "" in newer versions for compatibility
if (settings[7] !== undefined) barLabel.value = settings[7];
if (settings[8] !== undefined) barBackOpacity.value = settings[8];
if (settings[9]) barBackColor.value = settings[9];
if (settings[10]) barPosX.value = settings[10];
if (settings[11]) barPosY.value = settings[11];
if (settings[12]) populationRate = populationRateInput.value = populationRateOutput.value = settings[12]; if (settings[12]) populationRate = populationRateInput.value = populationRateOutput.value = settings[12];
if (settings[13]) urbanization = urbanizationInput.value = urbanizationOutput.value = settings[13]; if (settings[13]) urbanization = urbanizationInput.value = urbanizationOutput.value = settings[13];
if (settings[14]) mapSizeInput.value = mapSizeOutput.value = minmax(settings[14], 1, 100); if (settings[14]) mapSizeInput.value = mapSizeOutput.value = minmax(settings[14], 1, 100);
if (settings[15]) latitudeInput.value = latitudeOutput.value = minmax(settings[15], 0, 100); if (settings[15]) latitudeInput.value = latitudeOutput.value = minmax(settings[15], 0, 100);
if (settings[18]) precInput.value = precOutput.value = settings[18]; if (settings[18]) precInput.value = precOutput.value = settings[18];
if (settings[19]) options = JSON.parse(settings[19]); if (settings[19]) options = JSON.parse(settings[19]);
// setting 16 and 17 (temperature) are part of options now, kept as "" in newer versions for compatibility // setting 16 and 17 (temperature) are part of options now, kept as "" in newer versions for compatibility
if (settings[16]) options.temperatureEquator = +settings[16]; if (settings[16]) options.temperatureEquator = +settings[16];
if (settings[17]) options.temperatureNorthPole = options.temperatureSouthPole = +settings[17]; if (settings[17]) options.temperatureNorthPole = options.temperatureSouthPole = +settings[17];
if (settings[20]) mapName.value = settings[20]; if (settings[20]) mapName.value = settings[20];
if (settings[21]) hideLabels.checked = +settings[21]; if (settings[21]) hideLabels.checked = +settings[21];
if (settings[22]) stylePreset.value = settings[22]; if (settings[22]) stylePreset.value = settings[22];
@ -453,7 +447,6 @@ async function parseLoadedData(data) {
})(); })();
void (function restoreEvents() { void (function restoreEvents() {
scaleBar.on("mousemove", () => tip("Click to open Units Editor")).on("click", () => editUnits());
legend legend
.on("mousemove", () => tip("Drag to change the position. Click to hide the legend")) .on("mousemove", () => tip("Drag to change the position. Click to hide the legend"))
.on("click", () => clearLegend()); .on("click", () => clearLegend());

View file

@ -49,12 +49,12 @@ function prepareMapData() {
heightUnit.value, heightUnit.value,
heightExponentInput.value, heightExponentInput.value,
temperatureScale.value, temperatureScale.value,
barSizeInput.value, "", // previously used for barSize.value
barLabel.value, "", // previously used for barLabel.value
barBackOpacity.value, "", // previously used for barBackColor.value
barBackColor.value, "", // previously used for barBackColor.value
barPosX.value, "", // previously used for barPosX.value
barPosY.value, "", // previously used for barPosY.value
populationRate, populationRate,
urbanization, urbanization,
mapSizeOutput.value, mapSizeOutput.value,

View file

@ -1670,10 +1670,7 @@ function toggleLabels(event) {
invokeActiveZooming(); invokeActiveZooming();
if (event && isCtrlClick(event)) editStyle("labels"); if (event && isCtrlClick(event)) editStyle("labels");
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) return editStyle("labels");
editStyle("labels");
return;
}
turnButtonOff("toggleLabels"); turnButtonOff("toggleLabels");
labels.style("display", "none"); labels.style("display", "none");
} }
@ -1685,10 +1682,7 @@ function toggleIcons(event) {
$("#icons").fadeIn(); $("#icons").fadeIn();
if (event && isCtrlClick(event)) editStyle("burgIcons"); if (event && isCtrlClick(event)) editStyle("burgIcons");
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) return editStyle("burgIcons");
editStyle("burgIcons");
return;
}
turnButtonOff("toggleIcons"); turnButtonOff("toggleIcons");
$("#icons").fadeOut(); $("#icons").fadeOut();
} }
@ -1701,10 +1695,7 @@ function toggleRulers(event) {
rulers.draw(); rulers.draw();
ruler.style("display", null); ruler.style("display", null);
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) return editStyle("ruler");
editStyle("ruler");
return;
}
turnButtonOff("toggleRulers"); turnButtonOff("toggleRulers");
ruler.selectAll("*").remove(); ruler.selectAll("*").remove();
ruler.style("display", "none"); ruler.style("display", "none");
@ -1715,17 +1706,113 @@ function toggleScaleBar(event) {
if (!layerIsOn("toggleScaleBar")) { if (!layerIsOn("toggleScaleBar")) {
turnButtonOn("toggleScaleBar"); turnButtonOn("toggleScaleBar");
$("#scaleBar").fadeIn(); $("#scaleBar").fadeIn();
if (event && isCtrlClick(event)) editUnits(); if (event && isCtrlClick(event)) editStyle("scaleBar");
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) return editStyle("scaleBar");
editUnits();
return;
}
$("#scaleBar").fadeOut(); $("#scaleBar").fadeOut();
turnButtonOff("toggleScaleBar"); 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-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) { function toggleZones(event) {
if (!layerIsOn("toggleZones")) { if (!layerIsOn("toggleZones")) {
turnButtonOn("toggleZones"); turnButtonOn("toggleZones");
@ -1748,10 +1835,7 @@ function toggleEmblems(event) {
$("#emblems").fadeIn(); $("#emblems").fadeIn();
if (event && isCtrlClick(event)) editStyle("emblems"); if (event && isCtrlClick(event)) editStyle("emblems");
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) return editStyle("emblems");
editStyle("emblems");
return;
}
$("#emblems").fadeOut(); $("#emblems").fadeOut();
turnButtonOff("toggleEmblems"); turnButtonOff("toggleEmblems");
} }

View file

@ -532,101 +532,3 @@ class Planimeter extends Measurer {
this.el.select("text").attr("x", c[0]).attr("y", c[1]).text(area); this.el.select("text").attr("x", c[0]).attr("y", c[1]).text(area);
} }
} }
// Scale bar
function drawScaleBar(scaleBar, scaleLevel) {
if (!scaleBar.size() || scaleBar.style("display") === "none") return;
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", "-.6em")
.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);
}
// fit ScaleBar to screen size
function fitScaleBar(scaleBar, fullWidth, fullHeight) {
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(fullWidth * px - bbox.width + 10);
const y = rn(fullHeight * py - bbox.height + 20);
scaleBar.attr("transform", `translate(${x},${y})`);
}

View file

@ -774,7 +774,7 @@ function showExportPane() {
} }
async function exportToJson(type) { 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); exportToJson(type);
} }

View file

@ -14,6 +14,7 @@
byId("styleFilterInput").innerHTML = allOptions; byId("styleFilterInput").innerHTML = allOptions;
byId("styleStatesBodyFilter").innerHTML = allOptions; byId("styleStatesBodyFilter").innerHTML = allOptions;
byId("styleScaleBarBackgroundFilter").innerHTML = allOptions;
} }
// store some style inputs as options // store some style inputs as options
@ -94,13 +95,13 @@ function selectStyleElement() {
} }
// filter // filter
if (!["landmass", "legend", "regions"].includes(styleElement)) { if (!["landmass", "legend", "regions", "scaleBar"].includes(styleElement)) {
styleFilter.style.display = "block"; styleFilter.style.display = "block";
styleFilterInput.value = el.attr("filter") || ""; styleFilterInput.value = el.attr("filter") || "";
} }
// fill // fill
if (["rivers", "lakes", "landmass", "prec", "ice", "fogging", "vignette"].includes(styleElement)) { if (["rivers", "lakes", "landmass", "prec", "ice", "fogging", "scaleBar", "vignette"].includes(styleElement)) {
styleFill.style.display = "block"; styleFill.style.display = "block";
styleFillInput.value = styleFillOutput.value = el.attr("fill"); styleFillInput.value = styleFillOutput.value = el.attr("fill");
} }
@ -356,6 +357,31 @@ function selectStyleElement() {
if (auto) styleFilter.style.display = "none"; if (auto) styleFilter.style.display = "none";
} }
if (styleElement === "scaleBar") {
styleScaleBar.style.display = "block";
styleScaleBarSize.value = el.attr("data-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") { if (styleElement === "vignette") {
styleVignette.style.display = "block"; styleVignette.style.display = "block";
@ -1043,6 +1069,44 @@ styleVignetteBlur.addEventListener("input", function () {
byId("vignette-rect")?.setAttribute("filter", `blur(${this.value}px)`); 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-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() { function updateElements() {
// burgIcons to desired size // burgIcons to desired size
burgIcons.selectAll("g").each(function () { burgIcons.selectAll("g").each(function () {

View file

@ -301,7 +301,19 @@ function addStylePreset() {
], ],
"#fogging": ["opacity", "fill", "filter"], "#fogging": ["opacity", "fill", "filter"],
"#vignette": ["opacity", "fill", "filter"], "#vignette": ["opacity", "fill", "filter"],
"#vignette-rect": ["x", "y", "width", "height", "rx", "ry", "filter"] "#vignette-rect": ["x", "y", "width", "height", "rx", "ry", "filter"],
"#scaleBar": ["opacity", "fill", "font-size", "data-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) { for (const selector in attributes) {

View file

@ -24,13 +24,6 @@ function editUnits() {
byId("heightExponentInput").addEventListener("input", changeHeightExponent); byId("heightExponentInput").addEventListener("input", changeHeightExponent);
byId("heightExponentOutput").addEventListener("input", changeHeightExponent); byId("heightExponentOutput").addEventListener("input", changeHeightExponent);
byId("temperatureScale").addEventListener("change", changeTemperatureScale); byId("temperatureScale").addEventListener("change", changeTemperatureScale);
byId("barSizeOutput").addEventListener("input", renderScaleBar);
byId("barSizeInput").addEventListener("input", renderScaleBar);
byId("barLabel").addEventListener("input", renderScaleBar);
byId("barPosX").addEventListener("input", fitScaleBar);
byId("barPosY").addEventListener("input", fitScaleBar);
byId("barBackOpacity").addEventListener("input", changeScaleBarOpacity);
byId("barBackColor").addEventListener("input", changeScaleBarColor);
byId("populationRateOutput").addEventListener("input", changePopulationRate); byId("populationRateOutput").addEventListener("input", changePopulationRate);
byId("populationRateInput").addEventListener("change", changePopulationRate); byId("populationRateInput").addEventListener("change", changePopulationRate);
@ -84,14 +77,6 @@ function editUnits() {
if (layerIsOn("toggleTemp")) drawTemp(); if (layerIsOn("toggleTemp")) drawTemp();
} }
function changeScaleBarOpacity() {
scaleBar.select("rect").attr("opacity", this.value);
}
function changeScaleBarColor() {
scaleBar.select("rect").attr("fill", this.value);
}
function changePopulationRate() { function changePopulationRate() {
populationRate = +this.value; populationRate = +this.value;
} }
@ -129,19 +114,6 @@ function editUnits() {
localStorage.removeItem("heightExponent"); localStorage.removeItem("heightExponent");
calculateTemperatures(); 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");
renderScaleBar(); renderScaleBar();
// population // population

View file

@ -398,5 +398,25 @@
"rx": "0%", "rx": "0%",
"ry": "0%", "ry": "0%",
"filter": "blur(50px)" "filter": "blur(50px)"
},
"#scaleBar": {
"opacity": 1,
"fill": "#353540",
"font-size": 10,
"data-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
} }
} }

View file

@ -398,5 +398,25 @@
"rx": "5%", "rx": "5%",
"ry": "5%", "ry": "5%",
"filter": "blur(30px)" "filter": "blur(30px)"
},
"#scaleBar": {
"opacity": 1,
"fill": "#353540",
"font-size": 10,
"data-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
} }
} }

View file

@ -400,5 +400,25 @@
"rx": "5%", "rx": "5%",
"ry": "5%", "ry": "5%",
"filter": "blur(20px)" "filter": "blur(20px)"
},
"#scaleBar": {
"opacity": 1,
"fill": "#353540",
"font-size": 10,
"data-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
} }
} }

View file

@ -398,5 +398,25 @@
"rx": "5%", "rx": "5%",
"ry": "5%", "ry": "5%",
"filter": "blur(20px)" "filter": "blur(20px)"
},
"#scaleBar": {
"opacity": 1,
"fill": "#353540",
"font-size": 10,
"data-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
} }
} }

View file

@ -398,5 +398,25 @@
"rx": "5%", "rx": "5%",
"ry": "5%", "ry": "5%",
"filter": "blur(20px)" "filter": "blur(20px)"
},
"#scaleBar": {
"opacity": 1,
"fill": "#353540",
"font-size": 10,
"data-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
} }
} }

View file

@ -400,5 +400,25 @@
"rx": "10%", "rx": "10%",
"ry": "10%", "ry": "10%",
"filter": "blur(30px)" "filter": "blur(30px)"
},
"#scaleBar": {
"opacity": 1,
"fill": "#353540",
"font-size": 10,
"data-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
} }
} }

View file

@ -398,5 +398,25 @@
"rx": "5%", "rx": "5%",
"ry": "5%", "ry": "5%",
"filter": "blur(20px)" "filter": "blur(20px)"
},
"#scaleBar": {
"opacity": 1,
"fill": "#353540",
"font-size": 10,
"data-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
} }
} }

View file

@ -394,5 +394,25 @@
"rx": "5%", "rx": "5%",
"ry": "5%", "ry": "5%",
"filter": "blur(20px)" "filter": "blur(20px)"
},
"#scaleBar": {
"opacity": 1,
"fill": "#353540",
"font-size": 10,
"data-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
} }
} }

View file

@ -398,5 +398,25 @@
"rx": "5%", "rx": "5%",
"ry": "5%", "ry": "5%",
"filter": "blur(20px)" "filter": "blur(20px)"
},
"#scaleBar": {
"opacity": 1,
"fill": "#353540",
"font-size": 10,
"data-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
} }
} }

View file

@ -398,5 +398,25 @@
"rx": "5%", "rx": "5%",
"ry": "5%", "ry": "5%",
"filter": "blur(30px)" "filter": "blur(30px)"
},
"#scaleBar": {
"opacity": 1,
"fill": "#353540",
"font-size": 10,
"data-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
} }
} }

View file

@ -398,5 +398,25 @@
"rx": "5%", "rx": "5%",
"ry": "5%", "ry": "5%",
"filter": "blur(20px)" "filter": "blur(20px)"
},
"#scaleBar": {
"opacity": 1,
"fill": "#353540",
"font-size": 10,
"data-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
} }
} }

View file

@ -1,7 +1,7 @@
"use strict"; "use strict";
// version and caching control // version and caching control
const version = "1.95.00"; // generator version, update each time const version = "1.96.00"; // generator version, update each time
{ {
document.title += " v" + version; document.title += " v" + version;