mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 09:41:24 +01:00
collect statistics for a short period
This commit is contained in:
parent
2a9edd2458
commit
5d714c8c17
9 changed files with 160 additions and 53 deletions
|
|
@ -554,12 +554,6 @@ input[type="color"]::-webkit-color-swatch-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#optionsSeedGenerate:before {
|
|
||||||
content: "✓";
|
|
||||||
margin-left: -2px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#options input[type="color"] {
|
#options input[type="color"] {
|
||||||
width: 2em;
|
width: 2em;
|
||||||
padding: 1px;
|
padding: 1px;
|
||||||
|
|
|
||||||
|
|
@ -235,7 +235,7 @@
|
||||||
|
|
||||||
<div id="collapsible">
|
<div id="collapsible">
|
||||||
<button id="optionsTrigger" data-t="tipOptionsTrigger" data-tip="Click to show the Menu. Shortcut: Tab" class="options glow" onclick="showOptions(event)" style="padding:.6em .45em">►</button>
|
<button id="optionsTrigger" data-t="tipOptionsTrigger" data-tip="Click to show the Menu. Shortcut: Tab" class="options glow" onclick="showOptions(event)" style="padding:.6em .45em">►</button>
|
||||||
<button id="regenerate" data-t="tipRegenerate" data-tip="Click to generate a new map. Shortcut: F2" onclick="regeneratePrompt()" class="options" style="display: none"><t data-t="newMap">New Map!</t></button>
|
<button id="regenerate" data-t="tipRegenerate" data-tip="Click to generate a new map. Shortcut: F2" onclick="regeneratePrompt('drawer')" class="options" style="display: none"><t data-t="newMap">New Map!</t></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="options" style="display:none">
|
<div id="options" style="display:none">
|
||||||
|
|
@ -942,14 +942,13 @@
|
||||||
|
|
||||||
<tr data-tip="Map seed number. Seed produces the same map only if canvas size and options are the same">
|
<tr data-tip="Map seed number. Seed produces the same map only if canvas size and options are the same">
|
||||||
<td>
|
<td>
|
||||||
<i data-tip="Click to generate a map for this seed" id="optionsSeedGenerate"></i>
|
<i data-tip="Show seed history to apply a previous seed" id="optionsMapHistory" class="icon-history"></i>
|
||||||
</td>
|
</td>
|
||||||
<td>Map seed</td>
|
<td>Map seed</td>
|
||||||
<td>
|
<td>
|
||||||
<input id="optionsSeed" class="long" type="number" min=1 max=999999999 step=1>
|
<input id="optionsSeed" class="long" type="number" min=1 max=999999999 step=1>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<i data-tip="Show seed history to apply a previous seed" id="optionsMapHistory" class="icon-history"></i>
|
|
||||||
<i data-tip="Copy map seed as URL. It will produce the same map only if options are default or the same" id="optionsCopySeed" class="icon-docs"></i>
|
<i data-tip="Copy map seed as URL. It will produce the same map only if options are default or the same" id="optionsCopySeed" class="icon-docs"></i>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -4304,6 +4303,7 @@
|
||||||
<script src="modules/fonts.js"></script>
|
<script src="modules/fonts.js"></script>
|
||||||
<script src="modules/ui/layers.js"></script>
|
<script src="modules/ui/layers.js"></script>
|
||||||
<script src="modules/ui/measurers.js"></script>
|
<script src="modules/ui/measurers.js"></script>
|
||||||
|
<script src="libs/umami.js"></script>
|
||||||
|
|
||||||
<script async defer src="https://unpkg.com/dropbox@10.8.0/dist/Dropbox-sdk.min.js"></script>
|
<script async defer src="https://unpkg.com/dropbox@10.8.0/dist/Dropbox-sdk.min.js"></script>
|
||||||
<script async defer src="modules/ui/general.js"></script>
|
<script async defer src="modules/ui/general.js"></script>
|
||||||
|
|
@ -4354,6 +4354,5 @@
|
||||||
<script async defer src="libs/jquery.ui.touch-punch.min.js"></script>
|
<script async defer src="libs/jquery.ui.touch-punch.min.js"></script>
|
||||||
<script async defer src="libs/pell.min.js"></script>
|
<script async defer src="libs/pell.min.js"></script>
|
||||||
<script async defer src="libs/jszip.min.js"></script>
|
<script async defer src="libs/jszip.min.js"></script>
|
||||||
<script async defer data-website-id="4f6fd0ae-646a-4946-a9da-7aad63284e48" src="https://fmg-stats.herokuapp.com/umami.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
48
libs/umami.js
Normal file
48
libs/umami.js
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
(window => {
|
||||||
|
const noTrack = window.localStorage.getItem("noTrack");
|
||||||
|
if (noTrack) return;
|
||||||
|
|
||||||
|
const {
|
||||||
|
screen: {width, height},
|
||||||
|
navigator: {language},
|
||||||
|
location: {hostname, pathname, search},
|
||||||
|
document: {referrer}
|
||||||
|
} = window;
|
||||||
|
|
||||||
|
const website = "4f6fd0ae-646a-4946-a9da-7aad63284e48";
|
||||||
|
const root = "https://fmg-stats.herokuapp.com";
|
||||||
|
const screen = `${width}x${height}`;
|
||||||
|
const url = `${pathname}${search}`;
|
||||||
|
|
||||||
|
const post = (url, data) => {
|
||||||
|
const req = new XMLHttpRequest();
|
||||||
|
req.open("POST", url, true);
|
||||||
|
req.setRequestHeader("Content-Type", "application/json");
|
||||||
|
req.send(JSON.stringify(data));
|
||||||
|
};
|
||||||
|
|
||||||
|
const collect = (type, params) => {
|
||||||
|
const payload = {website, hostname, screen, language, cache: false};
|
||||||
|
Object.keys(params).forEach(key => {
|
||||||
|
payload[key] = params[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
post(`${root}/api/collect`, {type, payload});
|
||||||
|
};
|
||||||
|
|
||||||
|
// const addEvents = () => {
|
||||||
|
// document.querySelectorAll("[class*='umami--']").forEach(element => {
|
||||||
|
// element.className.split(" ").forEach(className => {
|
||||||
|
// if (/^umami--([a-z]+)--([\w]+[\w-]*)$/.test(className)) {
|
||||||
|
// const [, type, value] = className.split("--");
|
||||||
|
// const listener = () => collect("event", {event_type: type, event_value: value});
|
||||||
|
// element.addEventListener(type, listener, true);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
// addEvents();
|
||||||
|
|
||||||
|
collect("pageview", {url, referrer});
|
||||||
|
window.track = (event_type = "reach", event_value = "") => collect("event", {event_type, event_value, url});
|
||||||
|
})(window);
|
||||||
12
main.js
12
main.js
|
|
@ -652,11 +652,13 @@ function generate() {
|
||||||
INFO && console.groupEnd("Generated Map " + seed);
|
INFO && console.groupEnd("Generated Map " + seed);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ERROR && console.error(error);
|
ERROR && console.error(error);
|
||||||
|
const parsedError = parseError(error);
|
||||||
|
track("error", parsedError);
|
||||||
clearMainTip();
|
clearMainTip();
|
||||||
|
|
||||||
alertMessage.innerHTML = `An error is occured on map generation. Please retry.
|
alertMessage.innerHTML = `An error is occured on map generation. Please retry.
|
||||||
<br>If error is critical, clear the stored data and try again.
|
<br>If error is critical, clear the stored data and try again.
|
||||||
<p id="errorBox">${parseError(error)}</p>`;
|
<p id="errorBox">${parsedError}</p>`;
|
||||||
$("#alert").dialog({
|
$("#alert").dialog({
|
||||||
resizable: false,
|
resizable: false,
|
||||||
title: "Generation error",
|
title: "Generation error",
|
||||||
|
|
@ -667,7 +669,7 @@ function generate() {
|
||||||
localStorage.setItem("version", version);
|
localStorage.setItem("version", version);
|
||||||
},
|
},
|
||||||
Regenerate: function () {
|
Regenerate: function () {
|
||||||
regenerateMap();
|
regenerateMap("generation error");
|
||||||
$(this).dialog("close");
|
$(this).dialog("close");
|
||||||
},
|
},
|
||||||
Ignore: function () {
|
Ignore: function () {
|
||||||
|
|
@ -1830,7 +1832,7 @@ function addZones(number = 1) {
|
||||||
|
|
||||||
// show map stats on generation complete
|
// show map stats on generation complete
|
||||||
function showStatistics() {
|
function showStatistics() {
|
||||||
const template = templateInput.value;
|
const template = templateInput.options[templateInput.selectedIndex].text;
|
||||||
const templateRandom = locked("template") ? "" : "(random)";
|
const templateRandom = locked("template") ? "" : "(random)";
|
||||||
const stats = ` Seed: ${seed}
|
const stats = ` Seed: ${seed}
|
||||||
Canvas size: ${graphWidth}x${graphHeight}
|
Canvas size: ${graphWidth}x${graphHeight}
|
||||||
|
|
@ -1848,9 +1850,10 @@ function showStatistics() {
|
||||||
mapId = Date.now(); // unique map id is it's creation date number
|
mapId = Date.now(); // unique map id is it's creation date number
|
||||||
mapHistory.push({seed, width: graphWidth, height: graphHeight, template, created: mapId});
|
mapHistory.push({seed, width: graphWidth, height: graphHeight, template, created: mapId});
|
||||||
INFO && console.log(stats);
|
INFO && console.log(stats);
|
||||||
|
track("generate", `Template: ${template} ${templateRandom}. Points: ${pointsInput.dataset.cells}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const regenerateMap = debounce(function () {
|
const regenerateMap = debounce(function (source) {
|
||||||
WARN && console.warn("Generate new random map");
|
WARN && console.warn("Generate new random map");
|
||||||
closeDialogs("#worldConfigurator, #options3d");
|
closeDialogs("#worldConfigurator, #options3d");
|
||||||
customization = 0;
|
customization = 0;
|
||||||
|
|
@ -1860,6 +1863,7 @@ const regenerateMap = debounce(function () {
|
||||||
restoreLayers();
|
restoreLayers();
|
||||||
if (ThreeD.options.isOn) ThreeD.redraw();
|
if (ThreeD.options.isOn) ThreeD.redraw();
|
||||||
if ($("#worldConfigurator").is(":visible")) editWorld();
|
if ($("#worldConfigurator").is(":visible")) editWorld();
|
||||||
|
track("regenerate", `from ${source}`);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
// clear the map
|
// clear the map
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
// download map as SVG
|
// download map as SVG
|
||||||
async function saveSVG() {
|
async function saveSVG() {
|
||||||
TIME && console.time("saveSVG");
|
TIME && console.time("saveSVG");
|
||||||
|
track("export", "svg");
|
||||||
const url = await getMapURL("svg");
|
const url = await getMapURL("svg");
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
link.download = getFileName() + ".svg";
|
link.download = getFileName() + ".svg";
|
||||||
|
|
@ -17,6 +18,7 @@ async function saveSVG() {
|
||||||
// download map as PNG
|
// download map as PNG
|
||||||
async function savePNG() {
|
async function savePNG() {
|
||||||
TIME && console.time("savePNG");
|
TIME && console.time("savePNG");
|
||||||
|
track("export", "png");
|
||||||
const url = await getMapURL("png");
|
const url = await getMapURL("png");
|
||||||
|
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
|
|
@ -47,6 +49,7 @@ async function savePNG() {
|
||||||
// download map as JPEG
|
// download map as JPEG
|
||||||
async function saveJPEG() {
|
async function saveJPEG() {
|
||||||
TIME && console.time("saveJPEG");
|
TIME && console.time("saveJPEG");
|
||||||
|
track("export", "jpg");
|
||||||
const url = await getMapURL("png");
|
const url = await getMapURL("png");
|
||||||
|
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
|
|
@ -264,7 +267,11 @@ async function getMapURL(type, options = {}) {
|
||||||
if (!cloneEl.getElementById("labels")) cloneEl.getElementById("textPaths")?.remove(); // removed unused textPaths
|
if (!cloneEl.getElementById("labels")) cloneEl.getElementById("textPaths")?.remove(); // removed unused textPaths
|
||||||
|
|
||||||
// add armies style
|
// add armies style
|
||||||
if (cloneEl.getElementById("armies")) cloneEl.insertAdjacentHTML("afterbegin", "<style>#armies text {stroke: none; fill: #fff; text-shadow: 0 0 4px #000; dominant-baseline: central; text-anchor: middle; font-family: Helvetica; fill-opacity: 1;}#armies text.regimentIcon {font-size: .8em;}</style>");
|
if (cloneEl.getElementById("armies"))
|
||||||
|
cloneEl.insertAdjacentHTML(
|
||||||
|
"afterbegin",
|
||||||
|
"<style>#armies text {stroke: none; fill: #fff; text-shadow: 0 0 4px #000; dominant-baseline: central; text-anchor: middle; font-family: Helvetica; fill-opacity: 1;}#armies text.regimentIcon {font-size: .8em;}</style>"
|
||||||
|
);
|
||||||
|
|
||||||
// add xlink: for href to support svg1.1
|
// add xlink: for href to support svg1.1
|
||||||
if (type === "svg") {
|
if (type === "svg") {
|
||||||
|
|
@ -372,6 +379,7 @@ function inlineStyle(clone) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveGeoJSON_Cells() {
|
function saveGeoJSON_Cells() {
|
||||||
|
track("export", "getJSON cells");
|
||||||
const json = {type: "FeatureCollection", features: []};
|
const json = {type: "FeatureCollection", features: []};
|
||||||
const cells = pack.cells;
|
const cells = pack.cells;
|
||||||
const getPopulation = i => {
|
const getPopulation = i => {
|
||||||
|
|
@ -402,6 +410,7 @@ function saveGeoJSON_Cells() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveGeoJSON_Routes() {
|
function saveGeoJSON_Routes() {
|
||||||
|
track("export", "getJSON routes");
|
||||||
const json = {type: "FeatureCollection", features: []};
|
const json = {type: "FeatureCollection", features: []};
|
||||||
|
|
||||||
routes.selectAll("g > path").each(function () {
|
routes.selectAll("g > path").each(function () {
|
||||||
|
|
@ -418,6 +427,7 @@ function saveGeoJSON_Routes() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveGeoJSON_Rivers() {
|
function saveGeoJSON_Rivers() {
|
||||||
|
track("export", "getJSON rivers");
|
||||||
const json = {type: "FeatureCollection", features: []};
|
const json = {type: "FeatureCollection", features: []};
|
||||||
|
|
||||||
rivers.selectAll("path").each(function () {
|
rivers.selectAll("path").each(function () {
|
||||||
|
|
@ -440,6 +450,8 @@ function saveGeoJSON_Rivers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveGeoJSON_Markers() {
|
function saveGeoJSON_Markers() {
|
||||||
|
// TODO: rework for new markers
|
||||||
|
track("export", "getJSON markers");
|
||||||
const json = {type: "FeatureCollection", features: []};
|
const json = {type: "FeatureCollection", features: []};
|
||||||
|
|
||||||
markers.selectAll("use").each(function () {
|
markers.selectAll("use").each(function () {
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ function quickLoad() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadFromDropbox() {
|
async function loadFromDropbox() {
|
||||||
|
track("load", `from dropbox`);
|
||||||
const mapPath = document.getElementById("loadFromDropboxSelect")?.value;
|
const mapPath = document.getElementById("loadFromDropboxSelect")?.value;
|
||||||
|
|
||||||
DEBUG && console.log("Loading map from Dropbox:", mapPath);
|
DEBUG && console.log("Loading map from Dropbox:", mapPath);
|
||||||
|
|
@ -68,6 +69,7 @@ function loadMapPrompt(blob) {
|
||||||
|
|
||||||
function loadLastSavedMap() {
|
function loadLastSavedMap() {
|
||||||
WARN && console.warn("Load last saved map");
|
WARN && console.warn("Load last saved map");
|
||||||
|
track("load", `from browser storage`);
|
||||||
try {
|
try {
|
||||||
uploadMap(blob);
|
uploadMap(blob);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -78,6 +80,7 @@ function loadMapPrompt(blob) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadMapFromURL(maplink, random) {
|
function loadMapFromURL(maplink, random) {
|
||||||
|
track("load", `from url`);
|
||||||
const URL = decodeURIComponent(maplink);
|
const URL = decodeURIComponent(maplink);
|
||||||
|
|
||||||
fetch(URL, {method: "GET", mode: "cors"})
|
fetch(URL, {method: "GET", mode: "cors"})
|
||||||
|
|
@ -93,6 +96,7 @@ function loadMapFromURL(maplink, random) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function showUploadErrorMessage(error, URL, random) {
|
function showUploadErrorMessage(error, URL, random) {
|
||||||
|
track("error", `map load from url`);
|
||||||
ERROR && console.error(error);
|
ERROR && console.error(error);
|
||||||
alertMessage.innerHTML = `Cannot load map from the ${link(URL, "link provided")}.
|
alertMessage.innerHTML = `Cannot load map from the ${link(URL, "link provided")}.
|
||||||
${random ? `A new random map is generated. ` : ""}
|
${random ? `A new random map is generated. ` : ""}
|
||||||
|
|
@ -431,12 +435,27 @@ function parseLoadedData(data) {
|
||||||
|
|
||||||
// 1.0 adds a legend box
|
// 1.0 adds a legend box
|
||||||
legend = svg.append("g").attr("id", "legend");
|
legend = svg.append("g").attr("id", "legend");
|
||||||
legend.attr("font-family", "Almendra SC").attr("font-size", 13).attr("data-size", 13).attr("data-x", 99).attr("data-y", 93).attr("stroke-width", 2.5).attr("stroke", "#812929").attr("stroke-dasharray", "0 4 10 4").attr("stroke-linecap", "round");
|
legend
|
||||||
|
.attr("font-family", "Almendra SC")
|
||||||
|
.attr("font-size", 13)
|
||||||
|
.attr("data-size", 13)
|
||||||
|
.attr("data-x", 99)
|
||||||
|
.attr("data-y", 93)
|
||||||
|
.attr("stroke-width", 2.5)
|
||||||
|
.attr("stroke", "#812929")
|
||||||
|
.attr("stroke-dasharray", "0 4 10 4")
|
||||||
|
.attr("stroke-linecap", "round");
|
||||||
|
|
||||||
// 1.0 separated drawBorders fron drawStates()
|
// 1.0 separated drawBorders fron drawStates()
|
||||||
stateBorders = borders.append("g").attr("id", "stateBorders");
|
stateBorders = borders.append("g").attr("id", "stateBorders");
|
||||||
provinceBorders = borders.append("g").attr("id", "provinceBorders");
|
provinceBorders = borders.append("g").attr("id", "provinceBorders");
|
||||||
borders.attr("opacity", null).attr("stroke", null).attr("stroke-width", null).attr("stroke-dasharray", null).attr("stroke-linecap", null).attr("filter", null);
|
borders
|
||||||
|
.attr("opacity", null)
|
||||||
|
.attr("stroke", null)
|
||||||
|
.attr("stroke-width", null)
|
||||||
|
.attr("stroke-dasharray", null)
|
||||||
|
.attr("stroke-linecap", null)
|
||||||
|
.attr("filter", null);
|
||||||
stateBorders.attr("opacity", 0.8).attr("stroke", "#56566d").attr("stroke-width", 1).attr("stroke-dasharray", "2").attr("stroke-linecap", "butt");
|
stateBorders.attr("opacity", 0.8).attr("stroke", "#56566d").attr("stroke-width", 1).attr("stroke-dasharray", "2").attr("stroke-linecap", "butt");
|
||||||
provinceBorders.attr("opacity", 0.8).attr("stroke", "#56566d").attr("stroke-width", 0.5).attr("stroke-dasharray", "1").attr("stroke-linecap", "butt");
|
provinceBorders.attr("opacity", 0.8).attr("stroke", "#56566d").attr("stroke-width", 0.5).attr("stroke-dasharray", "1").attr("stroke-linecap", "butt");
|
||||||
|
|
||||||
|
|
@ -976,7 +995,7 @@ function parseLoadedData(data) {
|
||||||
},
|
},
|
||||||
"New map": function () {
|
"New map": function () {
|
||||||
$(this).dialog("close");
|
$(this).dialog("close");
|
||||||
regenerateMap();
|
regenerateMap("loading error");
|
||||||
},
|
},
|
||||||
Cancel: function () {
|
Cancel: function () {
|
||||||
$(this).dialog("close");
|
$(this).dialog("close");
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,15 @@ function editHeightmap() {
|
||||||
width: "28em",
|
width: "28em",
|
||||||
buttons: {
|
buttons: {
|
||||||
Erase: function () {
|
Erase: function () {
|
||||||
|
track("edit", "heightmap erase");
|
||||||
enterHeightmapEditMode("erase");
|
enterHeightmapEditMode("erase");
|
||||||
},
|
},
|
||||||
Keep: function () {
|
Keep: function () {
|
||||||
|
track("edit", "heightmap keep");
|
||||||
enterHeightmapEditMode("keep");
|
enterHeightmapEditMode("keep");
|
||||||
},
|
},
|
||||||
Risk: function () {
|
Risk: function () {
|
||||||
|
track("edit", "heightmap risk");
|
||||||
enterHeightmapEditMode("risk");
|
enterHeightmapEditMode("risk");
|
||||||
},
|
},
|
||||||
Cancel: function () {
|
Cancel: function () {
|
||||||
|
|
@ -87,7 +90,16 @@ function editHeightmap() {
|
||||||
exitCustomization.style.bottom = svgHeight / 2 + "px";
|
exitCustomization.style.bottom = svgHeight / 2 + "px";
|
||||||
exitCustomization.style.transform = "scale(2)";
|
exitCustomization.style.transform = "scale(2)";
|
||||||
exitCustomization.style.display = "block";
|
exitCustomization.style.display = "block";
|
||||||
d3.select("#exitCustomization").transition().duration(1000).style("opacity", 1).transition().duration(2000).ease(d3.easeSinInOut).style("right", "10px").style("bottom", "10px").style("transform", "scale(1)");
|
d3.select("#exitCustomization")
|
||||||
|
.transition()
|
||||||
|
.duration(1000)
|
||||||
|
.style("opacity", 1)
|
||||||
|
.transition()
|
||||||
|
.duration(2000)
|
||||||
|
.ease(d3.easeSinInOut)
|
||||||
|
.style("right", "10px")
|
||||||
|
.style("bottom", "10px")
|
||||||
|
.style("transform", "scale(1)");
|
||||||
} else exitCustomization.style.display = "block";
|
} else exitCustomization.style.display = "block";
|
||||||
|
|
||||||
openBrushesPanel();
|
openBrushesPanel();
|
||||||
|
|
@ -130,7 +142,8 @@ function editHeightmap() {
|
||||||
|
|
||||||
// Exit customization mode
|
// Exit customization mode
|
||||||
function finalizeHeightmap() {
|
function finalizeHeightmap() {
|
||||||
if (viewbox.select("#heights").selectAll("*").size() < 200) return tip("Insufficient land area! There should be at least 200 land cells to finalize the heightmap", null, "error");
|
if (viewbox.select("#heights").selectAll("*").size() < 200)
|
||||||
|
return tip("Insufficient land area! There should be at least 200 land cells to finalize the heightmap", null, "error");
|
||||||
if (document.getElementById("imageConverter").offsetParent) return tip("Please exit the Image Conversion mode first", null, "error");
|
if (document.getElementById("imageConverter").offsetParent) return tip("Please exit the Image Conversion mode first", null, "error");
|
||||||
|
|
||||||
delete window.edits; // remove global variable
|
delete window.edits; // remove global variable
|
||||||
|
|
@ -618,7 +631,10 @@ function editHeightmap() {
|
||||||
else if (brush === "brushLower") s.forEach(i => (h[i] = lim(h[i] - power)));
|
else if (brush === "brushLower") s.forEach(i => (h[i] = lim(h[i] - power)));
|
||||||
else if (brush === "brushDepress") s.forEach((i, d) => (h[i] = lim(h[i] - interpolate(d / Math.max(s.length - 1, 1)))));
|
else if (brush === "brushDepress") s.forEach((i, d) => (h[i] = lim(h[i] - interpolate(d / Math.max(s.length - 1, 1)))));
|
||||||
else if (brush === "brushAlign") s.forEach(i => (h[i] = lim(h[start])));
|
else if (brush === "brushAlign") s.forEach(i => (h[i] = lim(h[start])));
|
||||||
else if (brush === "brushSmooth") s.forEach(i => (h[i] = rn((d3.mean(grid.cells.c[i].filter(i => (land ? h[i] >= 20 : 1)).map(c => h[c])) + h[i] * (10 - power) + 0.6) / (11 - power), 1)));
|
else if (brush === "brushSmooth")
|
||||||
|
s.forEach(
|
||||||
|
i => (h[i] = rn((d3.mean(grid.cells.c[i].filter(i => (land ? h[i] >= 20 : 1)).map(c => h[c])) + h[i] * (10 - power) + 0.6) / (11 - power), 1))
|
||||||
|
);
|
||||||
else if (brush === "brushDisrupt") s.forEach(i => (h[i] = h[i] < 15 ? h[i] : lim(h[i] + power / 1.6 - Math.random() * power)));
|
else if (brush === "brushDisrupt") s.forEach(i => (h[i] = h[i] < 15 ? h[i] : lim(h[i] + power / 1.6 - Math.random() * power)));
|
||||||
|
|
||||||
mockHeightmapSelection(s);
|
mockHeightmapSelection(s);
|
||||||
|
|
@ -688,6 +704,7 @@ function editHeightmap() {
|
||||||
|
|
||||||
function openTemplateEditor() {
|
function openTemplateEditor() {
|
||||||
if ($("#templateEditor").is(":visible")) return;
|
if ($("#templateEditor").is(":visible")) return;
|
||||||
|
track("edit", "template editor");
|
||||||
const body = document.getElementById("templateBody");
|
const body = document.getElementById("templateBody");
|
||||||
|
|
||||||
$("#templateEditor").dialog({
|
$("#templateEditor").dialog({
|
||||||
|
|
@ -767,15 +784,29 @@ function editHeightmap() {
|
||||||
|
|
||||||
const TempY = `<span>y:<input class="templateY" data-tip="Placement range percentage along Y axis (minY-maxY)" value=${arg5 || "20-80"}></span>`;
|
const TempY = `<span>y:<input class="templateY" data-tip="Placement range percentage along Y axis (minY-maxY)" value=${arg5 || "20-80"}></span>`;
|
||||||
const TempX = `<span>x:<input class="templateX" data-tip="Placement range percentage along X axis (minX-maxX)" value=${arg4 || "15-85"}></span>`;
|
const TempX = `<span>x:<input class="templateX" data-tip="Placement range percentage along X axis (minX-maxX)" value=${arg4 || "15-85"}></span>`;
|
||||||
const Height = `<span>h:<input class="templateHeight" data-tip="Blob maximum height, use hyphen to get a random number in range" value=${arg3 || "40-50"}></span>`;
|
const Height = `<span>h:<input class="templateHeight" data-tip="Blob maximum height, use hyphen to get a random number in range" value=${
|
||||||
|
arg3 || "40-50"
|
||||||
|
}></span>`;
|
||||||
const Count = `<span>n:<input class="templateCount" data-tip="Blobs to add, use hyphen to get a random number in range" value=${count || "1-2"}></span>`;
|
const Count = `<span>n:<input class="templateCount" data-tip="Blobs to add, use hyphen to get a random number in range" value=${count || "1-2"}></span>`;
|
||||||
const blob = `${common}${TempY}${TempX}${Height}${Count}</div>`;
|
const blob = `${common}${TempY}${TempX}${Height}${Count}</div>`;
|
||||||
|
|
||||||
if (type === "Hill" || type === "Pit" || type === "Range" || type === "Trough") return blob;
|
if (type === "Hill" || type === "Pit" || type === "Range" || type === "Trough") return blob;
|
||||||
if (type === "Strait") return `${common}<span>d:<select class="templateDist" data-tip="Strait direction"><option value="vertical" selected>vertical</option><option value="horizontal">horizontal</option></select></span><span>w:<input class="templateCount" data-tip="Strait width, use hyphen to get a random number in range" value=${count || "2-7"}></span></div>`;
|
if (type === "Strait")
|
||||||
if (type === "Add") return `${common}<span>to:<select class="templateDist" data-tip="Change only land or all cells"><option value="all" selected>all cells</option><option value="land">land only</option><option value="interval">interval</option></select></span><span>v:<input class="templateCount" data-tip="Add value to height of all cells (negative values are allowed)" type="number" value=${count || -10} min=-100 max=100 step=1></span></div>`;
|
return `${common}<span>d:<select class="templateDist" data-tip="Strait direction"><option value="vertical" selected>vertical</option><option value="horizontal">horizontal</option></select></span><span>w:<input class="templateCount" data-tip="Strait width, use hyphen to get a random number in range" value=${
|
||||||
if (type === "Multiply") return `${common}<span>to:<select class="templateDist" data-tip="Change only land or all cells"><option value="all" selected>all cells</option><option value="land">land only</option><option value="interval">interval</option></select></span><span>v:<input class="templateCount" data-tip="Multiply all cells Height by the value" type="number" value=${count || 1.1} min=0 max=10 step=.1></span></div>`;
|
count || "2-7"
|
||||||
if (type === "Smooth") return `${common}<span>f:<input class="templateCount" data-tip="Set smooth fraction. 1 - full smooth, 2 - half-smooth, etc." type="number" min=1 max=10 value=${count || 2}></span></div>`;
|
}></span></div>`;
|
||||||
|
if (type === "Add")
|
||||||
|
return `${common}<span>to:<select class="templateDist" data-tip="Change only land or all cells"><option value="all" selected>all cells</option><option value="land">land only</option><option value="interval">interval</option></select></span><span>v:<input class="templateCount" data-tip="Add value to height of all cells (negative values are allowed)" type="number" value=${
|
||||||
|
count || -10
|
||||||
|
} min=-100 max=100 step=1></span></div>`;
|
||||||
|
if (type === "Multiply")
|
||||||
|
return `${common}<span>to:<select class="templateDist" data-tip="Change only land or all cells"><option value="all" selected>all cells</option><option value="land">land only</option><option value="interval">interval</option></select></span><span>v:<input class="templateCount" data-tip="Multiply all cells Height by the value" type="number" value=${
|
||||||
|
count || 1.1
|
||||||
|
} min=0 max=10 step=.1></span></div>`;
|
||||||
|
if (type === "Smooth")
|
||||||
|
return `${common}<span>f:<input class="templateCount" data-tip="Set smooth fraction. 1 - full smooth, 2 - half-smooth, etc." type="number" min=1 max=10 value=${
|
||||||
|
count || 2
|
||||||
|
}></span></div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setRange(event) {
|
function setRange(event) {
|
||||||
|
|
@ -910,6 +941,7 @@ function editHeightmap() {
|
||||||
|
|
||||||
function openImageConverter() {
|
function openImageConverter() {
|
||||||
if ($("#imageConverter").is(":visible")) return;
|
if ($("#imageConverter").is(":visible")) return;
|
||||||
|
track("edit", "convert image");
|
||||||
imageToLoad.click();
|
imageToLoad.click();
|
||||||
closeDialogs("#imageConverter");
|
closeDialogs("#imageConverter");
|
||||||
|
|
||||||
|
|
@ -1170,10 +1202,14 @@ function editHeightmap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setConvertColorsNumber() {
|
function setConvertColorsNumber() {
|
||||||
prompt(`Please set maximum number of colors. <br>An actual number is usually lower and depends on color scheme`, {default: +convertColors.value, step: 1, min: 3, max: 255}, number => {
|
prompt(
|
||||||
convertColors.value = number;
|
`Please set maximum number of colors. <br>An actual number is usually lower and depends on color scheme`,
|
||||||
heightsFromImage(number);
|
{default: +convertColors.value, step: 1, min: 3, max: 255},
|
||||||
});
|
number => {
|
||||||
|
convertColors.value = number;
|
||||||
|
heightsFromImage(number);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setOverlayOpacity(v) {
|
function setOverlayOpacity(v) {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ function handleKeyup(event) {
|
||||||
const alt = altKey || key === "Alt";
|
const alt = altKey || key === "Alt";
|
||||||
|
|
||||||
if (key === "F1") showInfo();
|
if (key === "F1") showInfo();
|
||||||
else if (key === "F2") regeneratePrompt();
|
else if (key === "F2") regeneratePrompt("hotkey");
|
||||||
else if (key === "F6") quickSave();
|
else if (key === "F6") quickSave();
|
||||||
else if (key === "F9") quickLoad();
|
else if (key === "F9") quickLoad();
|
||||||
else if (key === "TAB") toggleOptions(event);
|
else if (key === "TAB") toggleOptions(event);
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ if (localStorage.getItem("disable_click_arrow_tooltip")) {
|
||||||
|
|
||||||
// Show options pane on trigger click
|
// Show options pane on trigger click
|
||||||
function showOptions(event) {
|
function showOptions(event) {
|
||||||
|
track("click", "show options");
|
||||||
if (!localStorage.getItem("disable_click_arrow_tooltip")) {
|
if (!localStorage.getItem("disable_click_arrow_tooltip")) {
|
||||||
clearMainTip();
|
clearMainTip();
|
||||||
localStorage.setItem("disable_click_arrow_tooltip", true);
|
localStorage.setItem("disable_click_arrow_tooltip", true);
|
||||||
|
|
@ -75,6 +76,7 @@ document
|
||||||
|
|
||||||
// show popup with a list of Patreon supportes (updated manually, to be replaced with API call)
|
// show popup with a list of Patreon supportes (updated manually, to be replaced with API call)
|
||||||
function showSupporters() {
|
function showSupporters() {
|
||||||
|
track("click", "show supporters");
|
||||||
const supporters = `Aaron Meyer,Ahmad Amerih,AstralJacks,aymeric,Billy Dean Goehring,Branndon Edwards,Chase Mayers,Curt Flood,cyninge,Dino Princip,
|
const supporters = `Aaron Meyer,Ahmad Amerih,AstralJacks,aymeric,Billy Dean Goehring,Branndon Edwards,Chase Mayers,Curt Flood,cyninge,Dino Princip,
|
||||||
E.M. White,es,Fondue,Fritjof Olsson,Gatsu,Johan Fröberg,Jonathan Moore,Joseph Miranda,Kate,KC138,Luke Nelson,Markus Finster,Massimo Vella,Mikey,
|
E.M. White,es,Fondue,Fritjof Olsson,Gatsu,Johan Fröberg,Jonathan Moore,Joseph Miranda,Kate,KC138,Luke Nelson,Markus Finster,Massimo Vella,Mikey,
|
||||||
Nathan Mitchell,Paavi1,Pat,Ryan Westcott,Sasquatch,Shawn Spencer,Sizz_TV,Timothée CALLET,UTG community,Vlad Tomash,Wil Sisney,William Merriott,
|
Nathan Mitchell,Paavi1,Pat,Ryan Westcott,Sasquatch,Shawn Spencer,Sizz_TV,Timothée CALLET,UTG community,Vlad Tomash,Wil Sisney,William Merriott,
|
||||||
|
|
@ -160,7 +162,7 @@ optionsContent.addEventListener("change", function (event) {
|
||||||
const value = event.target.value;
|
const value = event.target.value;
|
||||||
|
|
||||||
if (id === "zoomExtentMin" || id === "zoomExtentMax") changeZoomExtent(value);
|
if (id === "zoomExtentMin" || id === "zoomExtentMax") changeZoomExtent(value);
|
||||||
else if (id === "optionsSeed") generateMapWithSeed();
|
else if (id === "optionsSeed") generateMapWithSeed("seed change");
|
||||||
else if (id === "uiSizeInput" || id === "uiSizeOutput") changeUIsize(value);
|
else if (id === "uiSizeInput" || id === "uiSizeOutput") changeUIsize(value);
|
||||||
if (id === "shapeRendering") viewbox.attr("shape-rendering", value);
|
if (id === "shapeRendering") viewbox.attr("shape-rendering", value);
|
||||||
else if (id === "yearInput") changeYear();
|
else if (id === "yearInput") changeYear();
|
||||||
|
|
@ -170,7 +172,6 @@ optionsContent.addEventListener("change", function (event) {
|
||||||
optionsContent.addEventListener("click", function (event) {
|
optionsContent.addEventListener("click", function (event) {
|
||||||
const id = event.target.id;
|
const id = event.target.id;
|
||||||
if (id === "toggleFullscreen") toggleFullscreen();
|
if (id === "toggleFullscreen") toggleFullscreen();
|
||||||
else if (id === "optionsSeedGenerate") generateMapWithSeed();
|
|
||||||
else if (id === "optionsMapHistory") showSeedHistoryDialog();
|
else if (id === "optionsMapHistory") showSeedHistoryDialog();
|
||||||
else if (id === "optionsCopySeed") copyMapURL();
|
else if (id === "optionsCopySeed") copyMapURL();
|
||||||
else if (id === "optionsEraRegenerate") regenerateEra();
|
else if (id === "optionsEraRegenerate") regenerateEra();
|
||||||
|
|
@ -211,8 +212,8 @@ function changeMapSize() {
|
||||||
|
|
||||||
// just apply canvas size that was already set
|
// just apply canvas size that was already set
|
||||||
function applyMapSize() {
|
function applyMapSize() {
|
||||||
const zoomMin = +zoomExtentMin.value,
|
const zoomMin = +zoomExtentMin.value;
|
||||||
zoomMax = +zoomExtentMax.value;
|
const zoomMax = +zoomExtentMax.value;
|
||||||
graphWidth = +mapWidthInput.value;
|
graphWidth = +mapWidthInput.value;
|
||||||
graphHeight = +mapHeightInput.value;
|
graphHeight = +mapHeightInput.value;
|
||||||
svgWidth = Math.min(graphWidth, window.innerWidth);
|
svgWidth = Math.min(graphWidth, window.innerWidth);
|
||||||
|
|
@ -280,12 +281,9 @@ function testSpeaker() {
|
||||||
speechSynthesis.speak(speaker);
|
speechSynthesis.speak(speaker);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateMapWithSeed() {
|
function generateMapWithSeed(source) {
|
||||||
if (optionsSeed.value == seed) {
|
if (optionsSeed.value == seed) return tip("The current map already has this seed", false, "error");
|
||||||
tip("The current map already has this seed", false, "error");
|
regeneratePrompt(source);
|
||||||
return;
|
|
||||||
}
|
|
||||||
regeneratePrompt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showSeedHistoryDialog() {
|
function showSeedHistoryDialog() {
|
||||||
|
|
@ -316,7 +314,7 @@ function restoreSeed(id) {
|
||||||
mapHeightInput.value = mapHistory[id].height;
|
mapHeightInput.value = mapHistory[id].height;
|
||||||
templateInput.value = mapHistory[id].template;
|
templateInput.value = mapHistory[id].template;
|
||||||
if (locked("template")) unlock("template");
|
if (locked("template")) unlock("template");
|
||||||
regeneratePrompt();
|
regeneratePrompt("seed history");
|
||||||
}
|
}
|
||||||
|
|
||||||
function restoreDefaultZoomExtent() {
|
function restoreDefaultZoomExtent() {
|
||||||
|
|
@ -656,23 +654,17 @@ function restoreDefaultOptions() {
|
||||||
// Sticked menu Options listeners
|
// Sticked menu Options listeners
|
||||||
document.getElementById("sticked").addEventListener("click", function (event) {
|
document.getElementById("sticked").addEventListener("click", function (event) {
|
||||||
const id = event.target.id;
|
const id = event.target.id;
|
||||||
if (id === "newMapButton") regeneratePrompt();
|
if (id === "newMapButton") regeneratePrompt("sticky button");
|
||||||
else if (id === "saveButton") showSavePane();
|
else if (id === "saveButton") showSavePane();
|
||||||
else if (id === "exportButton") showExportPane();
|
else if (id === "exportButton") showExportPane();
|
||||||
else if (id === "loadButton") showLoadPane();
|
else if (id === "loadButton") showLoadPane();
|
||||||
else if (id === "zoomReset") resetZoom(1000);
|
else if (id === "zoomReset") resetZoom(1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
function regeneratePrompt() {
|
function regeneratePrompt(source) {
|
||||||
if (customization) {
|
if (customization) return tip("New map cannot be generated when edit mode is active, please exit the mode and retry", false, "error");
|
||||||
tip("New map cannot be generated when edit mode is active, please exit the mode and retry", false, "error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const workingTime = (Date.now() - last(mapHistory).created) / 60000; // minutes
|
const workingTime = (Date.now() - last(mapHistory).created) / 60000; // minutes
|
||||||
if (workingTime < 5) {
|
if (workingTime < 5) return regenerateMap(source);
|
||||||
regenerateMap();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
alertMessage.innerHTML = `Are you sure you want to generate a new map?<br>
|
alertMessage.innerHTML = `Are you sure you want to generate a new map?<br>
|
||||||
All unsaved changes made to the current map will be lost`;
|
All unsaved changes made to the current map will be lost`;
|
||||||
|
|
@ -685,7 +677,7 @@ function regeneratePrompt() {
|
||||||
},
|
},
|
||||||
Generate: function () {
|
Generate: function () {
|
||||||
closeDialogs();
|
closeDialogs();
|
||||||
regenerateMap();
|
regenerateMap(source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -792,6 +784,7 @@ function loadURL() {
|
||||||
|
|
||||||
// load map
|
// load map
|
||||||
document.getElementById("mapToLoad").addEventListener("change", function () {
|
document.getElementById("mapToLoad").addEventListener("change", function () {
|
||||||
|
track("load", `from local file`);
|
||||||
const fileToLoad = this.files[0];
|
const fileToLoad = this.files[0];
|
||||||
this.value = "";
|
this.value = "";
|
||||||
closeDialogs();
|
closeDialogs();
|
||||||
|
|
@ -811,6 +804,7 @@ function openSaveTiles() {
|
||||||
width: "23em",
|
width: "23em",
|
||||||
buttons: {
|
buttons: {
|
||||||
Download: function () {
|
Download: function () {
|
||||||
|
track("export", `tiles`);
|
||||||
status.innerHTML = "Preparing for download...";
|
status.innerHTML = "Preparing for download...";
|
||||||
setTimeout(() => (status.innerHTML = "Downloading. It may take some time."), 1000);
|
setTimeout(() => (status.innerHTML = "Downloading. It may take some time."), 1000);
|
||||||
loading = setInterval(() => (status.innerHTML += "."), 1000);
|
loading = setInterval(() => (status.innerHTML += "."), 1000);
|
||||||
|
|
@ -900,6 +894,7 @@ function enterStandardView() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function enter3dView(type) {
|
async function enter3dView(type) {
|
||||||
|
track("click", `3d mode: ${type}`);
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
canvas.id = "canvas3d";
|
canvas.id = "canvas3d";
|
||||||
canvas.dataset.type = type;
|
canvas.dataset.type = type;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue