markers rework - editor functions

This commit is contained in:
Azgaar 2021-09-20 02:29:50 +03:00
parent def32b7f74
commit 95f9d990d9
8 changed files with 633 additions and 214 deletions

View file

@ -10,6 +10,7 @@ window.Markers = (function () {
TIME && console.time("addMarkers");
const culturesSet = document.getElementById("culturesSet").value;
// TODO: don't put multiple markers to the same cell
addVolcanoes();
addHotSprings();
@ -120,7 +121,9 @@ window.Markers = (function () {
const {cells, burgs} = pack;
const meanFlux = d3.mean(cells.fl.filter(fl => fl));
let bridges = Array.from(cells.i.filter(i => cells.burg[i] && cells.t[i] !== 1 && burgs[cells.burg[i]].population > 20 && cells.r[i] && cells.fl[i] > meanFlux));
let bridges = Array.from(
cells.i.filter(i => cells.burg[i] && cells.t[i] !== 1 && burgs[cells.burg[i]].population > 20 && cells.r[i] && cells.fl[i] > meanFlux)
);
let quantity = getQuantity(bridges, 1, 5);
if (!quantity) return;
@ -143,13 +146,233 @@ window.Markers = (function () {
let quantity = getQuantity(taverns, 1, 100);
if (!quantity) return;
const colors = ["Dark", "Light", "Bright", "Golden", "White", "Black", "Red", "Pink", "Purple", "Blue", "Green", "Yellow", "Amber", "Orange", "Brown", "Grey"];
const animals = ["Antelope", "Ape", "Badger", "Bear", "Beaver", "Bison", "Boar", "Buffalo", "Cat", "Crane", "Crocodile", "Crow", "Deer", "Dog", "Eagle", "Elk", "Fox", "Goat", "Goose", "Hare", "Hawk", "Heron", "Horse", "Hyena", "Ibis", "Jackal", "Jaguar", "Lark", "Leopard", "Lion", "Mantis", "Marten", "Moose", "Mule", "Narwhal", "Owl", "Panther", "Rat", "Raven", "Rook", "Scorpion", "Shark", "Sheep", "Snake", "Spider", "Swan", "Tiger", "Turtle", "Wolf", "Wolverine", "Camel", "Falcon", "Hound", "Ox"];
const adjectives = ["New", "Good", "High", "Old", "Great", "Big", "Major", "Happy", "Main", "Huge", "Far", "Beautiful", "Fair", "Prime", "Ancient", "Golden", "Proud", "Lucky", "Fat", "Honest", "Giant", "Distant", "Friendly", "Loud", "Hungry", "Magical", "Superior", "Peaceful", "Frozen", "Divine", "Favorable", "Brave", "Sunny", "Flying"];
const methods = ["Boiled", "Grilled", "Roasted", "Spit-roasted", "Stewed", "Stuffed", "Jugged", "Mashed", "Baked", "Braised", "Poached", "Marinated", "Pickled", "Smoked", "Dried", "Dry-aged", "Corned", "Fried", "Pan-fried", "Deep-fried", "Dressed", "Steamed", "Cured", "Syrupped", "Flame-Broiled"];
const courses = ["beef", "pork", "bacon", "chicken", "lamb", "chevon", "hare", "rabbit", "hart", "deer", "antlers", "bear", "buffalo", "badger", "beaver", "turkey", "pheasant", "duck", "goose", "teal", "quail", "pigeon", "seal", "carp", "bass", "pike", "catfish", "sturgeon", "escallop", "pie", "cake", "pottage", "pudding", "onions", "carrot", "potato", "beet", "garlic", "cabbage", "eggplant", "eggs", "broccoli", "zucchini", "pepper", "olives", "pumpkin", "spinach", "peas", "chickpea", "beans", "rice", "pasta", "bread", "apples", "peaches", "pears", "melon", "oranges", "mango", "tomatoes", "cheese", "corn", "rat tails", "pig ears"];
const colors = [
"Dark",
"Light",
"Bright",
"Golden",
"White",
"Black",
"Red",
"Pink",
"Purple",
"Blue",
"Green",
"Yellow",
"Amber",
"Orange",
"Brown",
"Grey"
];
const animals = [
"Antelope",
"Ape",
"Badger",
"Bear",
"Beaver",
"Bison",
"Boar",
"Buffalo",
"Cat",
"Crane",
"Crocodile",
"Crow",
"Deer",
"Dog",
"Eagle",
"Elk",
"Fox",
"Goat",
"Goose",
"Hare",
"Hawk",
"Heron",
"Horse",
"Hyena",
"Ibis",
"Jackal",
"Jaguar",
"Lark",
"Leopard",
"Lion",
"Mantis",
"Marten",
"Moose",
"Mule",
"Narwhal",
"Owl",
"Panther",
"Rat",
"Raven",
"Rook",
"Scorpion",
"Shark",
"Sheep",
"Snake",
"Spider",
"Swan",
"Tiger",
"Turtle",
"Wolf",
"Wolverine",
"Camel",
"Falcon",
"Hound",
"Ox"
];
const adjectives = [
"New",
"Good",
"High",
"Old",
"Great",
"Big",
"Major",
"Happy",
"Main",
"Huge",
"Far",
"Beautiful",
"Fair",
"Prime",
"Ancient",
"Golden",
"Proud",
"Lucky",
"Fat",
"Honest",
"Giant",
"Distant",
"Friendly",
"Loud",
"Hungry",
"Magical",
"Superior",
"Peaceful",
"Frozen",
"Divine",
"Favorable",
"Brave",
"Sunny",
"Flying"
];
const methods = [
"Boiled",
"Grilled",
"Roasted",
"Spit-roasted",
"Stewed",
"Stuffed",
"Jugged",
"Mashed",
"Baked",
"Braised",
"Poached",
"Marinated",
"Pickled",
"Smoked",
"Dried",
"Dry-aged",
"Corned",
"Fried",
"Pan-fried",
"Deep-fried",
"Dressed",
"Steamed",
"Cured",
"Syrupped",
"Flame-Broiled"
];
const courses = [
"beef",
"pork",
"bacon",
"chicken",
"lamb",
"chevon",
"hare",
"rabbit",
"hart",
"deer",
"antlers",
"bear",
"buffalo",
"badger",
"beaver",
"turkey",
"pheasant",
"duck",
"goose",
"teal",
"quail",
"pigeon",
"seal",
"carp",
"bass",
"pike",
"catfish",
"sturgeon",
"escallop",
"pie",
"cake",
"pottage",
"pudding",
"onions",
"carrot",
"potato",
"beet",
"garlic",
"cabbage",
"eggplant",
"eggs",
"broccoli",
"zucchini",
"pepper",
"olives",
"pumpkin",
"spinach",
"peas",
"chickpea",
"beans",
"rice",
"pasta",
"bread",
"apples",
"peaches",
"pears",
"melon",
"oranges",
"mango",
"tomatoes",
"cheese",
"corn",
"rat tails",
"pig ears"
];
const types = ["hot", "cold", "fire", "ice", "smoky", "misty", "shiny", "sweet", "bitter", "salty", "sour", "sparkling", "smelly"];
const drinks = ["wine", "brandy", "jinn", "whisky", "rom", "beer", "cider", "mead", "liquor", "spirit", "vodka", "tequila", "absinthe", "nectar", "milk", "kvass", "kumis", "tea", "water", "juice", "sap"];
const drinks = [
"wine",
"brandy",
"jinn",
"whisky",
"rom",
"beer",
"cider",
"mead",
"liquor",
"spirit",
"vodka",
"tequila",
"absinthe",
"nectar",
"milk",
"kvass",
"kumis",
"tea",
"water",
"juice",
"sap"
];
while (quantity) {
const [cell] = extractAnyElement(taverns);
@ -282,7 +505,14 @@ window.Markers = (function () {
const subjects = ["Locals", "Old folks", "Old books", "Tipplers"];
const species = ["Ogre", "Troll", "Cyclops", "Giant", "Monster", "Beast", "Dragon", "Undead", "Ghoul", "Vampire"];
const modusOperandi = ["steals their cattle", "doesn't mind eating children", "doesn't mind of human flesh", "keeps the region at bay", "eats their kids", "abducts young women"];
const modusOperandi = [
"steals their cattle",
"doesn't mind eating children",
"doesn't mind of human flesh",
"keeps the region at bay",
"eats their kids",
"abducts young women"
];
while (quantity) {
const [cell] = extractAnyElement(hills);
@ -376,7 +606,38 @@ window.Markers = (function () {
let quantity = getQuantity(roads, 50, 100);
if (!quantity) return;
const animals = ["Apes", "Badgers", "Bears", "Beavers", "Bisons", "Boars", "Cats", "Crows", "Dogs", "Foxes", "Hares", "Hawks", "Hyenas", "Jackals", "Jaguars", "Leopards", "Lions", "Owls", "Panthers", "Rats", "Ravens", "Rooks", "Scorpions", "Sharks", "Snakes", "Spiders", "Tigers", "Wolfs", "Wolverines", "Falcons"];
const animals = [
"Apes",
"Badgers",
"Bears",
"Beavers",
"Bisons",
"Boars",
"Cats",
"Crows",
"Dogs",
"Foxes",
"Hares",
"Hawks",
"Hyenas",
"Jackals",
"Jaguars",
"Leopards",
"Lions",
"Owls",
"Panthers",
"Rats",
"Ravens",
"Rooks",
"Scorpions",
"Sharks",
"Snakes",
"Spiders",
"Tigers",
"Wolfs",
"Wolverines",
"Falcons"
];
const types = {brigands: 4, bandits: 3, robbers: 1, highwaymen: 1};
while (quantity) {
@ -385,7 +646,18 @@ window.Markers = (function () {
const culture = cells.culture[cell];
const biome = cells.biome[cell];
const height = cells.p[cell];
const locality = height >= 70 ? "highlander" : [1, 2].includes(biome) ? "desert" : [3, 4].includes(biome) ? "mounted" : [5, 6, 7, 8, 9].includes(biome) ? "forest" : biome === 12 ? "swamp" : "angry";
const locality =
height >= 70
? "highlander"
: [1, 2].includes(biome)
? "desert"
: [3, 4].includes(biome)
? "mounted"
: [5, 6, 7, 8, 9].includes(biome)
? "forest"
: biome === 12
? "swamp"
: "angry";
const name = `${Names.getCulture(culture)} ${ra(animals)}`;
const legend = `A gang of ${locality} ${rw(types)}`;
notes.push({id, name, legend});

View file

@ -29,7 +29,7 @@ function clicked() {
else if (grand.id === "burgIcons") editBurg();
else if (parent.id === "ice") editIce();
else if (parent.id === "terrain") editReliefIcon();
else if (grand.id === "markers") editMarker();
else if (grand.id === "markers" || great.id === "markers") editMarker();
else if (grand.id === "coastline") editCoastline();
else if (great.id === "armies") editRegiment();
else if (pack.cells.t[i] === 1) {
@ -332,7 +332,15 @@ function drawLegend(name, data) {
const width = bbox.width + colOffset * 2;
const height = bbox.height + colOffset / 2 + vOffset;
legend.insert("rect", ":first-child").attr("id", "legendBox").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height).attr("fill", backClr).attr("fill-opacity", opacity);
legend
.insert("rect", ":first-child")
.attr("id", "legendBox")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr("fill", backClr)
.attr("fill-opacity", opacity);
fitLegendBox();
}
@ -385,7 +393,15 @@ function createPicker() {
const closePicker = () => contaiter.style("display", "none");
const contaiter = d3.select("body").append("svg").attr("id", "pickerContainer").attr("width", "100%").attr("height", "100%");
contaiter.append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%").attr("opacity", 0.2).on("mousemove", cl).on("click", closePicker);
contaiter
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", "100%")
.attr("height", "100%")
.attr("opacity", 0.2)
.on("mousemove", cl)
.on("click", closePicker);
const picker = contaiter
.append("g")
.attr("id", "picker")
@ -484,9 +500,25 @@ function createPicker() {
const width = bbox.width + 8;
const height = bbox.height + 9;
picker.insert("rect", ":first-child").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height).attr("fill", "#ffffff").attr("stroke", "#5d4651").on("mousemove", pos);
picker
.insert("rect", ":first-child")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr("fill", "#ffffff")
.attr("stroke", "#5d4651")
.on("mousemove", pos);
picker.insert("text", ":first-child").attr("x", 291).attr("y", -10).attr("id", "pickerCloseText").text("✕");
picker.insert("rect", ":first-child").attr("x", 288).attr("y", -21).attr("id", "pickerCloseRect").attr("width", 14).attr("height", 14).on("mousemove", cl).on("click", closePicker);
picker
.insert("rect", ":first-child")
.attr("x", 288)
.attr("y", -21)
.attr("id", "pickerCloseRect")
.attr("width", 14)
.attr("height", 14)
.on("mousemove", cl)
.on("click", closePicker);
picker.insert("text", ":first-child").attr("x", 12).attr("y", -10).attr("id", "pickerLabel").text("Color Picker").on("mousemove", pos);
picker.insert("rect", ":first-child").attr("x", 0).attr("y", -30).attr("width", width).attr("height", 30).attr("id", "pickerHeader").on("mousemove", pos);
picker.attr("transform", `translate(${(svgWidth - width) / 2},${(svgHeight - height) / 2})`);
@ -705,7 +737,14 @@ function highlightElement(element) {
const highlight = debug.append("rect").attr("x", box.x).attr("y", box.y).attr("width", box.width).attr("height", box.height).attr("transform", transform);
highlight.classed("highlighted", 1).transition(enter).style("outline-offset", "0px").transition(exit).style("outline-color", "transparent").delay(1000).remove();
highlight
.classed("highlighted", 1)
.transition(enter)
.style("outline-offset", "0px")
.transition(exit)
.style("outline-color", "transparent")
.delay(1000)
.remove();
const tr = parseTransform(transform);
let x = box.x + box.width / 2;
@ -922,6 +961,7 @@ function selectIcon(initial, callback) {
}
}
input.oninput = e => callback(input.value);
table.onclick = e => {
if (e.target.tagName === "TD") {
input.value = e.target.innerHTML;
@ -948,6 +988,31 @@ function selectIcon(initial, callback) {
});
}
function confirmationDialog(options) {
const {
title = "Confirm action",
message = "Are you sure you want to continue? <br>The action cannot be reverted",
cancel = "Cancel",
confirm = "Continue",
onCancel,
onConfirm
} = options;
const buttons = {
[confirm]: function () {
if (onConfirm) onConfirm();
$(this).dialog("close");
},
[cancel]: function () {
if (onCancel) onCancel();
$(this).dialog("close");
}
};
document.getElementById("alertMessage").innerHTML = message;
$("#alert").dialog({resizable: false, title, buttons});
}
// add and register event listeners to clean up on editor closure
function listen(element, event, handler) {
element.addEventListener(event, handler);

View file

@ -196,7 +196,8 @@ function drawHeightmap() {
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);
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);
}
@ -798,7 +799,10 @@ function drawReligions() {
if (!vArray[r]) vArray[r] = [];
vArray[r].push(points);
body[r] += "M" + points.join("L");
gap[r] += "M" + vertices.p[chain[0][0]] + chain.reduce((r2, v, i, d) => (!i ? r2 : !v[2] ? r2 + "L" + vertices.p[v[0]] : d[i + 1] && !d[i + 1][2] ? r2 + "M" + vertices.p[v[0]] : r2), "");
gap[r] +=
"M" +
vertices.p[chain[0][0]] +
chain.reduce((r2, v, i, d) => (!i ? r2 : !v[2] ? r2 + "L" + vertices.p[v[0]] : d[i + 1] && !d[i + 1][2] ? r2 + "M" + vertices.p[v[0]] : r2), "");
}
const bodyData = body.map((p, i) => [p.length > 10 ? p : null, i, religions[i].color]).filter(d => d[0]);
@ -966,7 +970,12 @@ function drawStates() {
const gapString = gapData.map(d => `<path id="state-gap${d[1]}" d="${d[0]}" fill="none" stroke="${d[2]}"/>`).join("");
const clipString = bodyData.map(d => `<clipPath id="state-clip${d[1]}"><use href="#state${d[1]}"/></clipPath>`).join("");
const haloString = haloData
.map(d => `<path id="state-border${d[1]}" d="${d[0]}" clip-path="url(#state-clip${d[1]})" stroke="${d3.color(d[2]) ? d3.color(d[2]).darker().hex() : "#666666"}"/>`)
.map(
d =>
`<path id="state-border${d[1]}" d="${d[0]}" clip-path="url(#state-clip${d[1]})" stroke="${
d3.color(d[2]) ? d3.color(d[2]).darker().hex() : "#666666"
}"/>`
)
.join("");
statesBody.html(bodyString + gapString);
@ -1219,7 +1228,10 @@ function getProvincesVertices() {
if (!vArray[p]) vArray[p] = [];
vArray[p].push(points);
body[p] += "M" + points.join("L");
gap[p] += "M" + vertices.p[chain[0][0]] + chain.reduce((r, v, i, d) => (!i ? r : !v[2] ? r + "L" + vertices.p[v[0]] : d[i + 1] && !d[i + 1][2] ? r + "M" + vertices.p[v[0]] : r), "");
gap[p] +=
"M" +
vertices.p[chain[0][0]] +
chain.reduce((r, v, i, d) => (!i ? r : !v[2] ? r + "L" + vertices.p[v[0]] : d[i + 1] && !d[i + 1][2] ? r + "M" + vertices.p[v[0]] : r), "");
}
// find province visual center
@ -1300,7 +1312,12 @@ function drawGrid() {
const maxWidth = Math.max(+mapWidthInput.value, graphWidth);
const maxHeight = Math.max(+mapHeightInput.value, graphHeight);
d3.select(pattern).attr("stroke", stroke).attr("stroke-width", width).attr("stroke-dasharray", dasharray).attr("stroke-linecap", linecap).attr("patternTransform", tr);
d3.select(pattern)
.attr("stroke", stroke)
.attr("stroke-width", width)
.attr("stroke-dasharray", dasharray)
.attr("stroke-linecap", linecap)
.attr("patternTransform", tr);
gridOverlay
.append("rect")
.attr("width", maxWidth)
@ -1510,23 +1527,23 @@ function toggleMarkers(event) {
drawMarkers();
if (event && isCtrlClick(event)) editStyle("markers");
} else {
if (event && isCtrlClick(event)) {
editStyle("markers");
return;
}
if (event && isCtrlClick(event)) return editStyle("markers");
markers.selectAll("*").remove();
turnButtonOff("toggleMarkers");
}
}
function drawMarkers() {
const html = pack.markers.map(drawMarker);
const rescale = +markers.attr("rescale");
const html = pack.markers.map(marker => drawMarker(marker, rescale));
markers.html(html.join(""));
}
const getPin = (shape = "bubble", fill = "#fff", stroke = "#000") => {
if (shape === "bubble") return `<path d="M6,19 l9,10 L24,19" fill="${stroke}" stroke="none" /><circle cx="15" cy="15" r="10" fill="${fill}" stroke="${stroke}"/>`;
if (shape === "pin") return `<path d="m 15,3 c -5.5,0 -9.7,4.09 -9.7,9.3 0,6.8 9.7,17 9.7,17 0,0 9.7,-10.2 9.7,-17 C 24.7,7.09 20.5,3 15,3 Z" fill="${fill}" stroke="${stroke}"/>`;
if (shape === "bubble")
return `<path d="M6,19 l9,10 L24,19" fill="${stroke}" stroke="none" /><circle cx="15" cy="15" r="10" fill="${fill}" stroke="${stroke}"/>`;
if (shape === "pin")
return `<path d="m 15,3 c -5.5,0 -9.7,4.09 -9.7,9.3 0,6.8 9.7,17 9.7,17 0,0 9.7,-10.2 9.7,-17 C 24.7,7.09 20.5,3 15,3 Z" fill="${fill}" stroke="${stroke}"/>`;
if (shape === "square") return `<path d="m 20,25 -5,4 -5,-4 z" fill="${stroke}"/><path d="M 5,5 H 25 V 25 H 5 Z" fill="${fill}" stroke="${stroke}"/>`;
if (shape === "squarish") return `<path d="m 5,5 h 20 v 20 h -6 l -4,4 -4,-4 H 5 Z" fill="${fill}" stroke="${stroke}" />`;
if (shape === "diamond") return `<path d="M 2,15 15,1 28,15 15,29 Z" fill="${fill}" stroke="${stroke}" />`;
@ -1540,14 +1557,14 @@ const getPin = (shape = "bubble", fill = "#fff", stroke = "#000") => {
if (shape === "no") return "";
};
function drawMarker(marker) {
function drawMarker(marker, rescale = 1) {
const {i, icon, x, y, dx = 50, dy = 50, px = 12, size = 30} = marker;
const id = `marker${i}`;
const zoomSize = Math.max(rn(size / 5 + 24 / scale, 2), 1);
const zoomSize = rescale ? Math.max(rn(size / 5 + 24 / scale, 2), 1) : 1;
const viewX = rn(x - zoomSize / 2, 1);
const viewY = rn(y - zoomSize, 1);
return `<svg id="${id}" viewbox="0 0 30 30" width="${zoomSize}" height="${zoomSize}" x="${viewX}" y="${viewY}">${getPin()}<text x="${dx}%" y="${dy}%" font-size="${px}px" >${icon}</text></svg>`;
return `<svg id="${id}" viewbox="0 0 30 30" width="${zoomSize}" height="${zoomSize}" x="${viewX}" y="${viewY}"><g>${getPin()}</g><text x="${dx}%" y="${dy}%" font-size="${px}px" >${icon}</text></svg>`;
}
function toggleLabels(event) {
@ -1717,15 +1734,21 @@ function drawEmblems() {
}
const burgNodes = nodes.filter(node => node.type === "burg");
const burgString = burgNodes.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.shift)}" y="${rn(d.y - d.shift)}" width="${d.size}em" height="${d.size}em"/>`).join("");
const burgString = burgNodes
.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.shift)}" y="${rn(d.y - d.shift)}" width="${d.size}em" height="${d.size}em"/>`)
.join("");
emblems.select("#burgEmblems").attr("font-size", sizeBurgs).html(burgString);
const provinceNodes = nodes.filter(node => node.type === "province");
const provinceString = provinceNodes.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.shift)}" y="${rn(d.y - d.shift)}" width="${d.size}em" height="${d.size}em"/>`).join("");
const provinceString = provinceNodes
.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.shift)}" y="${rn(d.y - d.shift)}" width="${d.size}em" height="${d.size}em"/>`)
.join("");
emblems.select("#provinceEmblems").attr("font-size", sizeProvinces).html(provinceString);
const stateNodes = nodes.filter(node => node.type === "state");
const stateString = stateNodes.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.shift)}" y="${rn(d.y - d.shift)}" width="${d.size}em" height="${d.size}em"/>`).join("");
const stateString = stateNodes
.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.shift)}" y="${rn(d.y - d.shift)}" width="${d.size}em" height="${d.size}em"/>`)
.join("");
emblems.select("#stateEmblems").attr("font-size", sizeStates).html(stateString);
invokeActiveZooming();

View file

@ -3,23 +3,28 @@ function editMarker() {
if (customization) return;
closeDialogs(".stable");
const element = d3.event.target.parentElement;
elSelected = d3.select(element).call(d3.drag().on("start", dragMarker)).classed("draggable", true);
const marker = pack.markers.find(({i}) => Number(elSelected.attr("id").slice(6)) === i);
const element = d3.event.target.closest("svg");
const marker = pack.markers.find(({i}) => Number(element.id.slice(6)) === i);
if (!marker) return;
elSelected = d3.select(element).raise().call(d3.drag().on("start", dragMarker)).classed("draggable", true);
// dom elements
const markerSelectGroup = document.getElementById("markerSelectGroup");
const markerType = document.getElementById("markerType");
const markerIcon = document.getElementById("markerIcon");
const markerIconSelect = document.getElementById("markerIconSelect");
const markerIconSize = document.getElementById("markerIconSize");
const markerIconShiftX = document.getElementById("markerIconShiftX");
const markerIconShiftY = document.getElementById("markerIconShiftY");
const markerSize = document.getElementById("markerSize");
const markerBaseStroke = document.getElementById("markerBaseStroke");
const markerBaseFill = document.getElementById("markerBaseFill");
const markerPin = document.getElementById("markerPin");
const markerFill = document.getElementById("markerFill");
const markerStroke = document.getElementById("markerStroke");
const markerToggleBubble = document.getElementById("markerToggleBubble");
const markerIconSelect = document.getElementById("markerIconSelect");
const markerNotes = document.getElementById("markerNotes");
const addMarker = document.getElementById("addMarker");
const markerAdd = document.getElementById("markerAdd");
const markerRemove = document.getElementById("markerRemove");
updateInputs();
@ -31,22 +36,27 @@ function editMarker() {
});
const listeners = [
listen(markerSelectGroup, "change", changeGroup),
listen(document.getElementById("markerIcon"), "click", toggleIconSection),
listen(markerType, "change", changeMarkerType),
listen(markerIcon, "input", changeMarkerIcon),
listen(markerIconSelect, "click", selectMarkerIcon),
listen(markerIconSize, "input", changeIconSize),
listen(markerIconShiftX, "input", changeIconShiftX),
listen(markerIconShiftY, "input", changeIconShiftY),
listen(document.getElementById("markerIconSelect"), "click", selectMarkerIcon),
listen(document.getElementById("markerStyle"), "click", toggleStyleSection),
listen(markerSize, "input", changeMarkerSize),
listen(markerBaseStroke, "input", changePinStroke),
listen(markerBaseFill, "input", changePinFill),
listen(markerToggleBubble, "click", togglePinVisibility),
listen(document.getElementById("markerLegendButton"), "click", editMarkerLegend),
listen(document.getElementById("markerAdd"), "click", toggleAddMarker),
listen(document.getElementById("markerRemove"), "click", removeMarker)
listen(markerPin, "change", changeMarkerPin),
listen(markerFill, "input", changePinFill),
listen(markerStroke, "input", changePinStroke),
listen(markerNotes, "click", editMarkerLegend),
listen(markerAdd, "click", toggleAddMarker),
listen(markerRemove, "click", confirmMarkerDeletion)
];
function getSameTypeMarkers() {
const currentType = marker.type;
if (!currentType) return [marker];
return pack.markers.filter(({type}) => type === currentType);
}
function dragMarker() {
const dx = +this.getAttribute("x") - d3.event.x;
const dy = +this.getAttribute("y") - d3.event.y;
@ -70,173 +80,147 @@ function editMarker() {
}
function updateInputs() {
const {icon, type = "", size = 30, dx = 50, dy = 50, px = 12, stroke = "#000", fill = "#fff", pin = "bubble"} = marker;
const {icon, type = "", size = 30, dx = 50, dy = 50, px = 12, stroke = "#000000", fill = "#ffffff", pin = "bubble"} = marker;
markerSelectGroup.value = type;
markerType.value = type;
markerIcon.value = icon;
markerIconSize.value = px;
markerIconShiftX.value = dx;
markerIconShiftY.value = dy;
markerSize.value = size;
markerBaseStroke.value = stroke;
markerBaseFill.value = fill;
markerToggleBubble.className = pin;
markerIconSelect.innerHTML = icon;
markerPin.value = pin;
markerFill.value = fill;
markerStroke.value = stroke;
}
function toggleGroupSection() {
if (markerGroupSection.style.display === "inline-block") {
markerEditor.querySelectorAll("button:not(#markerGroup)").forEach(b => (b.style.display = "inline-block"));
markerGroupSection.style.display = "none";
} else {
markerEditor.querySelectorAll("button:not(#markerGroup)").forEach(b => (b.style.display = "none"));
markerGroupSection.style.display = "inline-block";
}
function changeMarkerType() {
marker.type = this.value;
}
function changeGroup() {
elSelected.attr("xlink:href", "#" + this.value);
elSelected.attr("data-id", "#" + this.value);
}
function toggleIconSection() {
console.log(marker);
if (markerIconSection.style.display === "inline-block") {
markerEditor.querySelectorAll("button:not(#markerIcon)").forEach(b => (b.style.display = "inline-block"));
markerIconSection.style.display = "none";
markerIconSelect.style.display = "none";
} else {
markerEditor.querySelectorAll("button:not(#markerIcon)").forEach(b => (b.style.display = "none"));
markerIconSection.style.display = "inline-block";
markerIconSelect.style.display = "inline-block";
}
function changeMarkerIcon() {
const icon = this.value;
getSameTypeMarkers().forEach(marker => {
marker.icon = icon;
redrawIcon(marker);
});
}
function selectMarkerIcon() {
selectIcon(this.innerHTML, v => {
this.innerHTML = v;
const id = elSelected.attr("data-id");
d3.select("#defs-markers").select(id).select("text").text(v);
selectIcon(marker.icon, icon => {
markerIcon.value = icon;
getSameTypeMarkers().forEach(marker => {
marker.icon = icon;
redrawIcon(marker);
});
});
}
function changeIconSize() {
const id = elSelected.attr("data-id");
d3.select("#defs-markers")
.select(id)
.select("text")
.attr("font-size", this.value + "px");
const px = +this.value;
getSameTypeMarkers().forEach(marker => {
marker.px = px;
redrawIcon(marker);
});
}
function changeIconShiftX() {
const id = elSelected.attr("data-id");
d3.select("#defs-markers")
.select(id)
.select("text")
.attr("x", this.value + "%");
const dx = +this.value;
getSameTypeMarkers().forEach(marker => {
marker.dx = dx;
redrawIcon(marker);
});
}
function changeIconShiftY() {
const id = elSelected.attr("data-id");
d3.select("#defs-markers")
.select(id)
.select("text")
.attr("y", this.value + "%");
}
function toggleStyleSection() {
if (markerStyleSection.style.display === "inline-block") {
markerEditor.querySelectorAll("button:not(#markerStyle)").forEach(b => (b.style.display = "inline-block"));
markerStyleSection.style.display = "none";
} else {
markerEditor.querySelectorAll("button:not(#markerStyle)").forEach(b => (b.style.display = "none"));
markerStyleSection.style.display = "inline-block";
}
const dy = +this.value;
getSameTypeMarkers().forEach(marker => {
marker.dy = dy;
redrawIcon(marker);
});
}
function changeMarkerSize() {
const id = elSelected.attr("data-id");
document.querySelectorAll("use[data-id='" + id + "']").forEach(e => {
const x = +e.dataset.x,
y = +e.dataset.y;
const desired = (e.dataset.size = +markerSize.value);
const size = Math.max(desired * 5 + 25 / scale, 1);
const size = +this.value;
const rescale = +markers.attr("rescale");
e.setAttribute("x", x - size / 2);
e.setAttribute("y", y - size / 2);
e.setAttribute("width", size);
e.setAttribute("height", size);
getSameTypeMarkers().forEach(marker => {
marker.size = size;
const {i, x, y, hidden} = marker;
const el = !hidden && document.getElementById(`marker${i}`);
if (!el) return;
const zoomedSize = rescale ? Math.max(rn(size / 5 + 24 / scale, 2), 1) : size;
el.setAttribute("width", zoomedSize);
el.setAttribute("height", zoomedSize);
el.setAttribute("x", rn(x - zoomedSize / 2, 1));
el.setAttribute("y", rn(y - zoomedSize, 1));
});
invokeActiveZooming();
}
function changePinStroke() {
const id = elSelected.attr("data-id");
d3.select(id).select("path").attr("fill", this.value);
d3.select(id).select("circle").attr("stroke", this.value);
function changeMarkerPin() {
const pin = this.value;
getSameTypeMarkers().forEach(marker => {
marker.pin = pin;
redrawPin(marker);
});
}
function changePinFill() {
const id = elSelected.attr("data-id");
d3.select(id).select("circle").attr("fill", this.value);
const fill = this.value;
getSameTypeMarkers().forEach(marker => {
marker.fill = fill;
redrawPin(marker);
});
}
function changeIconStrokeWidth() {
const id = elSelected.attr("data-id");
d3.select("#defs-markers").select(id).select("text").attr("stroke-width", this.value);
function changePinStroke() {
const stroke = this.value;
getSameTypeMarkers().forEach(marker => {
marker.stroke = stroke;
redrawPin(marker);
});
}
function changeIconStroke() {
const id = elSelected.attr("data-id");
d3.select("#defs-markers").select(id).select("text").attr("stroke", this.value);
function redrawIcon({i, hidden, icon, dx = 50, dy = 50, px = 12}) {
const iconElement = !hidden && document.querySelector(`#marker${i} > text`);
if (iconElement) {
iconElement.innerHTML = icon;
iconElement.setAttribute("x", dx + "%");
iconElement.setAttribute("y", dy + "%");
iconElement.setAttribute("font-size", px + "px");
}
}
function changeIconFill() {
const id = elSelected.attr("data-id");
d3.select("#defs-markers").select(id).select("text").attr("fill", this.value);
}
function togglePinVisibility() {
const id = elSelected.attr("data-id");
let show = 1;
if (this.className === "icon-info-circled") {
this.className = "icon-info";
show = 0;
} else this.className = "icon-info-circled";
d3.select(id).select("circle").attr("opacity", show);
d3.select(id).select("path").attr("opacity", show);
function redrawPin({i, hidden, pin = "bubble", fill = "#fff", stroke = "#000"}) {
const pinGroup = !hidden && document.querySelector(`#marker${i} > g`);
if (pinGroup) pinGroup.innerHTML = getPin(pin, fill, stroke);
}
function editMarkerLegend() {
const id = elSelected.attr("id");
const id = element.id;
editNotes(id, id);
}
function toggleAddMarker() {
document.getElementById("addMarker").click();
addMarker.click();
}
function removeMarker() {
alertMessage.innerHTML = "Are you sure you want to remove the marker?";
$("#alert").dialog({
resizable: false,
function confirmMarkerDeletion() {
confirmationDialog({
title: "Remove marker",
buttons: {
Remove: function () {
$(this).dialog("close");
const index = notes.findIndex(n => n.id === elSelected.attr("id"));
if (index != -1) notes.splice(index, 1);
elSelected.remove();
$("#markerEditor").dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
message: "Are you sure you want to remove this marker? The action cannot be reverted",
confirm: "Remove",
onConfirm: deleteMarker
});
}
function deleteMarker() {
notes = notes.filter(note => note.id !== element.id);
pack.markers = pack.markers.filter(m => m.i !== marker.i);
element.remove();
$("#markerEditor").dialog("close");
}
function closeMarkerEditor() {
listeners.forEach(removeListener => removeListener());

View file

@ -49,7 +49,9 @@ toolsContent.addEventListener("click", function (event) {
},
open: function () {
const pane = $(this).dialog("widget").find(".ui-dialog-buttonpane");
$('<span><input id="dontAsk" class="checkbox" type="checkbox"><label for="dontAsk" class="checkbox-label dontAsk"><i>do not ask again</i></label><span>').prependTo(pane);
$(
'<span><input id="dontAsk" class="checkbox" type="checkbox"><label for="dontAsk" class="checkbox-label dontAsk"><i>do not ask again</i></label><span>'
).prependTo(pane);
},
close: function () {
const box = $(this).dialog("widget").find(".checkbox")[0];
@ -262,7 +264,8 @@ 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 burgsCount = manorsInput.value == 1000 ? rn(sorted.length / 5 / (grid.points.length / 10000) ** 0.8) + states.length : +manorsInput.value + states.length;
const burgsCount =
manorsInput.value == 1000 ? rn(sorted.length / 5 / (grid.points.length / 10000) ** 0.8) + states.length : +manorsInput.value + states.length;
const spacing = (graphWidth + graphHeight) / 150 / (burgsCount ** 0.7 / 66); // base min distance between towns
//clear locked list since ids will change
@ -414,6 +417,7 @@ function regenerateIce() {
}
function regenerateMarkers(event) {
// TODO: rework for new markers system
if (isCtrlClick(event)) prompt("Please provide markers number multiplier", {default: 1, step: 0.01, min: 0, max: 100}, v => addNumberOfMarkers(v));
else addNumberOfMarkers(gauss(1, 0.5, 0.3, 5, 2));
@ -475,7 +479,18 @@ function addLabelOnClick() {
const id = getNextId("label");
let group = labels.select("#addedLabels");
if (!group.size()) group = labels.append("g").attr("id", "addedLabels").attr("fill", "#3e3e4b").attr("opacity", 1).attr("stroke", "#3a3a3a").attr("stroke-width", 0).attr("font-family", "Almendra SC").attr("font-size", 18).attr("data-size", 18).attr("filter", null);
if (!group.size())
group = labels
.append("g")
.attr("id", "addedLabels")
.attr("fill", "#3e3e4b")
.attr("opacity", 1)
.attr("stroke", "#3a3a3a")
.attr("stroke-width", 0)
.attr("font-family", "Almendra SC")
.attr("font-size", 18)
.attr("data-size", 18)
.attr("filter", null);
const example = group.append("text").attr("x", 0).attr("x", 0).text(name);
const width = example.node().getBBox().width;