From 42cd291c6823a7a11b6db083ea38013ad5e8dec7 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sat, 28 Jul 2018 18:29:24 +0300 Subject: [PATCH 01/25] v. 0.58.00b Cultures editor Namesbase editor Reworked lakes Options preservation Non-island maps Bug fixes --- README.md | 8 +- index.css | 82 +- index.html | 227 +++- names.js | 10 - script.js | 3027 ++++++++++++++++++++++++++++++++++++---------------- 5 files changed, 2343 insertions(+), 1011 deletions(-) delete mode 100644 names.js diff --git a/README.md b/README.md index f662ac3c..f1226922 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ # Fantasy Map Generator -Azgaar's _Fantasy Map Generator_. Based on [D3](https://d3js.org) Voronoi diagram rendered in svg. +Azgaar's _Fantasy Map Generator_. Online tool generating maps based on [D3](https://d3js.org) Voronoi diagram rendered in svg. -Project goal is a procedurally generated map for my *Medieval Dynasty* simulator. Map should be interactive, scalable, fast and plausible. Initial intend was to place at least 500 burgs within 7 cultural areas and imagined land area about 1 million km2. As of now all these parameters are customizable. +Project goal is a procedurally generated map for my *Medieval Dynasty* simulator. Map should be interactive, scalable, fast and plausible. Initial intend was to place at least 500 burgs within 7 cultural areas and imagined land area about 1 million km2. As of now all these parameters are customizable and Generator is mostly used for a homebrew DnD campaign maps. [![alt tag](https://i0.wp.com/azgaar.files.wordpress.com/2017/03/80k-part.png)](https://azgaar.wordpress.com) -Project is under development, check out the demo [here](https://azgaar.github.io/Fantasy-Map-Generator). Refer to [the project wiki](https://github.com/Azgaar/Fantasy-Map-Generator/wiki) for a quick guidance. The the previous versions see the [changelog](https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog). If you find the Demo performance low, open the page in a smaller window and use the graph size = 1. +Project is under development, check out the work is progress version [here](https://azgaar.github.io/Fantasy-Map-Generator). Changelog is [here](https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog). Refer to [the project wiki](https://github.com/Azgaar/Fantasy-Map-Generator/wiki) for a quick guidance. Some details are covered in my blog [_Fantasy Maps for fun and glory_](https://azgaar.wordpress.com), you may also keep an eye on my [Trello devboard](https://trello.com/b/7x832DG4/fantasy-map-generator). If you find the Demo performance low, open the page in a smaller window and use the default graph size only. -Some details are covered in my blog [_Fantasy Maps for fun and glory_](https://azgaar.wordpress.com), you may also keep an eye on my [devboard](https://trello.com/b/7x832DG4/fantasy-map-generator). Comments and ideas are *highly* welcomed, kindly contact me via [email](mailto:maxganiev@yandex.ru). I would also like to see your completed or work in progress maps. For bug reports and change requests please use the project [issues page](https://github.com/Azgaar/Fantasy-Map-Generator/issues). + Join our [Reddit community](https://www.reddit.com/r/FantasyMapGenerator) to share the created maps, discuss the Generator, suggest ideas and get a most recent updates. You may also contact me directly via [email](mailto:maxganiev@yandex.com). For bug reports please use the project [issues page](https://github.com/Azgaar/Fantasy-Map-Generator/issues). _Inspiration:_ diff --git a/index.css b/index.css index 7ee38d92..6404fb9e 100644 --- a/index.css +++ b/index.css @@ -48,7 +48,6 @@ button, select, a { #cults { stroke-width: 0.7; - stroke-linejoin: round; mask: url(#shape); mask-mode: alpha; pointer-events: none; @@ -269,7 +268,7 @@ input[type="number"].editNumber { } circle.drag { - stroke: white; + stroke: #9f3237; } text.drag { @@ -512,6 +511,10 @@ p { width: 35%; } +#customizeOptions { + margin: 2px 0; +} + #tooltip { position: fixed; display: none; @@ -519,7 +522,7 @@ p { top: calc(98vh - (10px + 0.5vw)); width: 100%; cursor: default; - text-shadow: 1px 0px 1px #1d0e0f; + text-shadow: 1px 1px 2px #1d0e0f; color: #ffffff; font-size: calc(10px + 0.5vw); pointer-events: none; @@ -666,8 +669,8 @@ body button.noicon { line-height: 6px; } +#styleInputs #styleOcean, #styleInputs #styleOpacity, -#styleInputs #styleFill, #styleInputs #styleFilter { display: block; } @@ -950,6 +953,13 @@ div.states>[class^="icon-"] { padding: 0 1px 0 7px; } +div.states>[class="icon-arrows-cw"] { + color: #67575c; + padding: 0 2px 0 0; + font-size: 9px; + cursor: pointer; +} + div.states>.before { color: #6e5e66; padding: 0 1px 0 0; @@ -959,6 +969,24 @@ div.states>.small { font-size: 9px; } +div.states>.cultureName { + width: 50px; +} + +div.states>.culturePopulation { + width: 40px; +} + +div.states>.cultureBase { + width: 46px; + cursor: pointer; + border: 0; + background-color: transparent; + -webkit-appearance: textfield; + -moz-appearance: textfield; + appearance: textfield; +} + #burgsBody, #countriesBody { overflow: auto; @@ -1273,3 +1301,49 @@ input[type="checkbox"] { #capital-anchors, #town-anchors { transform: translate(-0.47em, -0.47em); } + +#cultureCenters circle:hover { + stroke: #000000b3; + cursor: pointer; +} + +#namesbaseEditor select, +#namesbaseEditor textarea { + font-size: 10px; + font-family: Copperplate, monospace; + outline: none; +} + +#namesbaseEditor input { + font-size: 10px; + font-family: Copperplate, monospace; + outline: none; + height: 12px; +} + +#namesbaseEditor fieldset { + margin: 3px 3px 5px 0; + border-style: dashed; +} + +#namesbaseEditor span, #namesbaseEditor legend { + font-size: 9px; + font-weight: bold; +} + +#namesbaseExamples { + font-family: Copperplate, monospace; + cursor: pointer; +} + +#namesbaseName { + width: 80px; +} + +#namesbaseMin, #namesbaseMax { + width: 33px; +} + +#namesbaseDouble { + width: 40px; +} diff --git a/index.html b/index.html index 25cd3920..75433fbd 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@ gtag('js', new Date()); gtag('config', 'UA-116735150-1'); - Azgaar's Fantasy Map Generator Demo + Azgaar's Fantasy Map Generator @@ -26,14 +26,13 @@ - - - + + @@ -51,6 +50,17 @@ + + + + + + + + + + + @@ -59,17 +69,25 @@ + + + + + + + + - + - + - + - + @@ -140,7 +158,7 @@
Azgaar's
Fantasy Map Generator
-
v. 0.57b
+
v. 0.58b

LOADING...

@@ -192,26 +210,26 @@

Select element:

@@ -225,6 +243,15 @@
Size: 5
+
+
Elements: + + + +
+ Background: #000000
+ Foreground: #53679f +
Fill: #5E4FA2 @@ -233,7 +260,6 @@ Stroke: #5E4FA2
-
Colors:

Stroke width: 1 @@ -267,7 +293,11 @@ + + + +
@@ -288,7 +318,7 @@
-

Generation options (new map to apply):

+

Generation options (new map to apply):

@@ -378,6 +408,18 @@ 200 + + + + + + @@ -425,7 +467,7 @@ - +
+ + Cultures count + + + 7 +
@@ -406,14 +448,14 @@ Ocean layers - + + + + + + + PNG resolution - + 5x @@ -433,7 +475,7 @@
Zoom extentZoom extent o: @@ -445,12 +487,14 @@
+

Customize:

+
+
+ + + + +

@@ -496,19 +546,19 @@
-

Fantasy Map Generator is an open source tool which procedurally generates fantasy maps. You may either use an auto-generated maps or create your own map manually or with a help of templates or image converter. Check out the quick start tutorial and project wiki for guidance.

-

This is a Demo version, the Generator is still under development. For older versions see the changelog. Some details are covered in my blog. To track the current progress see the devboard.

-

Please report bugs and suggest new features here. You may also send me an email.

+

Fantasy Map Generator is an open source tool which procedurally generates fantasy maps. You may use auto-generated maps as they are, edit them or even create a map from scratch. Check out the quick start tutorial and project wiki for guidance. Join our Reddit Community if you have questions, need any help, have a suggestion or just want to share a created map.

+

The project is under active development. For older versions see the changelog. Some details are covered in my blog. To track the current progress see the devboard.

+

Please report bugs here. You may also send me an email.

- +
.map
@@ -516,7 +566,7 @@
.png
- +
@@ -527,7 +577,7 @@ - + @@ -737,8 +787,9 @@ - + + @@ -865,6 +916,7 @@ + @@ -891,12 +943,84 @@
- +
+ + + + @@ -1107,5 +1111,5 @@ - + diff --git a/script.js b/script.js index c8bfe368..385b5b2f 100644 --- a/script.js +++ b/script.js @@ -3,7 +3,7 @@ fantasyMap(); function fantasyMap() { // Version control - var version = "0.58b"; + const version = "0.58b"; document.title += " v. " + version; // Declare variables @@ -11,11 +11,11 @@ function fantasyMap() { defs = svg.select("#deftemp"), viewbox = svg.append("g").attr("id", "viewbox"), ocean = viewbox.append("g").attr("id", "ocean"), + lakes = viewbox.append("g").attr("id", "lakes"), oceanLayers = ocean.append("g").attr("id", "oceanLayers"), oceanPattern = ocean.append("g").attr("id", "oceanPattern"), landmass = viewbox.append("g").attr("id", "landmass"), terrs = viewbox.append("g").attr("id", "terrs"), - lakes = viewbox.append("g").attr("id", "lakes"), grid = viewbox.append("g").attr("id", "grid"), overlay = viewbox.append("g").attr("id", "overlay"), routes = viewbox.append("g").attr("id", "routes"), @@ -414,14 +414,19 @@ function fantasyMap() { infoX.innerHTML = rn(point[0]); infoY.innerHTML = rn(point[1]); infoCell.innerHTML = i; + infoArea.innerHTML = ifDefined(p.area, "n/a", 2); infoHeight.innerHTML = ifDefined(p.height, "n/a", 2); infoFlux.innerHTML = ifDefined(p.flux, "n/a", 2); - infoFeature.innerHTML = ifDefined(p.f) + "" + ifDefined(p.fn); let country = p.region === undefined ? "n/a" : p.region === "neutral" ? "neutral" : states[p.region].name + " (" + p.region + ")"; infoCountry.innerHTML = country; let culture = ifDefined(p.culture) !== "no" ? cultures[p.culture].name + " (" + p.culture + ")" : "n/a"; infoCulture.innerHTML = culture; + infoPopulation.innerHTML = ifDefined(p.pop, "n/a", 2); infoBurg.innerHTML = ifDefined(p.manor) !== "no" ? manors[p.manor].name + " (" + p.manor + ")" : "no"; + const feature = features[p.fn]; + if (feature === undefined) return; + const fType = feature.land ? "Island" : feature.border ? "Ocean" : "Lake"; + infoFeature.innerHTML = fType + " (" + p.fn + ")"; } // update tooltip @@ -474,8 +479,8 @@ function fantasyMap() { // return value (v) if defined with specified number of decimals (d) // else return "no" or attribute (r) function ifDefined(v, r, d) { - if (v == undefined) {return r || "no";} - if (d) {return v.toFixed(d);} + if (v === undefined) return r || "no"; + if (d) return v.toFixed(d); return v; } @@ -1264,7 +1269,6 @@ function fantasyMap() { calculateVoronoi(newPoints); // recalculate Voronoi diagram using new points let gridPath = ""; // store grid as huge single path string cells.map(function(i, d) { - if (!polygons[d]) debugger; if (i.height >= 0.2) { // calc cell area i.area = rn(Math.abs(d3.polygonArea(polygons[d])), 2); @@ -1408,14 +1412,14 @@ function fantasyMap() { // Detect and draw the coasline function drawCoastline() { console.time('drawCoastline'); - var oceanCoastline = "", lakeCoastline = ""; + const shape = d3.select("#shape"); $("#landmass").empty(); let minX = graphWidth, maxX = 0; // extreme points let minXedge, maxXedge; // extreme edges for (let f = 0; f < features.length; f++) { if (!features[f].land) continue; const coastal = $.grep(land, function(e) {return ((e.ctype === 1 || e.ctype === 99) && e.fn === f);}); - const oceanEdges = [], lakeEdges = []; + let oceanEdges = [], lakeEdges = []; for (let i = 0; i < coastal.length; i++) { const id = coastal[i].index, cell = diagram.cells[id]; cell.halfedges.forEach(function(e) { @@ -1425,15 +1429,15 @@ function fantasyMap() { if (edge.left && edge.right) { const ea = edge.left.index === id ? edge.right.index : edge.left.index; if (cells[ea].height < 0.2) { - if (!features[cells[ea].fn].border) { - lakeEdges.push({start, end}); - } else { + if (features[cells[ea].fn].border) { oceanEdges.push({start, end}); // island extreme points if (edge[0][0] < minX) {minX = edge[0][0]; minXedge = edge[0]} if (edge[1][0] < minX) {minX = edge[1][0]; minXedge = edge[1]} if (edge[0][0] > maxX) {maxX = edge[0][0]; maxXedge = edge[0]} if (edge[1][0] > maxX) {maxX = edge[1][0]; maxXedge = edge[1]} + } else { + lakeEdges.push({start, end}); } } } else { @@ -1441,17 +1445,21 @@ function fantasyMap() { } }) } + if (coastal.length && lakeEdges.length && oceanEdges.length < 3) { + console.error("Feature " + f + " is an on-lake island. This can cause defects!"); + oceanEdges = lakeEdges; + lakeEdges = []; + } lineGen.curve(d3.curveCatmullRomClosed.alpha(0.1)); - oceanCoastline += getContinuousLine(oceanEdges, 3, 0); + const oceanCoastline = getContinuousLine(oceanEdges, 3, 0); lineGen.curve(d3.curveBasisClosed); - if (lakeEdges.length > 0) {lakeCoastline += getContinuousLine(lakeEdges, 1.5, 0);} + const lakeCoastline = getContinuousLine(lakeEdges, 1.5, 0); + shape.append("path").attr("d", oceanCoastline).attr("fill", "white"); + if (lakeCoastline) shape.append("path").attr("d", lakeCoastline).attr("fill", "black"); + coastline.append("path").attr("d", oceanCoastline); // draw the coastline + if (lakeCoastline) lakes.append("path").attr("d", lakeCoastline); // draw the lakes } - const shape = d3.select("#shape"); - shape.append("path").attr("d", oceanCoastline).attr("fill", "white"); // add clippath - shape.append("path").attr("d", lakeCoastline).attr("fill", "black"); // add clippath - landmass.append("path").attr("d", oceanCoastline + lakeCoastline); // draw the landmass - coastline.append("path").attr("d", oceanCoastline); // draw the coastline - lakes.append("path").attr("d", lakeCoastline); // draw the lakes + landmass.append("rect").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight); // draw the landmass drawDefaultRuler(minXedge, maxXedge); console.timeEnd('drawCoastline'); } @@ -1658,6 +1666,7 @@ function fantasyMap() { function getContinuousLine(edges, indention, relax) { let line = ""; + if (edges.length < 3) return ""; while (edges.length > 2) { let edgesOrdered = []; // to store points in a correct order let start = edges[0].start; @@ -1706,14 +1715,17 @@ function fantasyMap() { // temporary elevate lakes to min neighbors heights to correctly flux the water function elevateLakes() { - for (let i=0; i < cells.length; i++) { - if (cells[i].height >= 0.2) continue; - if (features[cells[i].fn].border) continue; - const heights = cells[i].neighbors.map(function(n) {if (cells[n].height >= 0.2) return cells[n].height}); - if (heights.length) cells[i].height = d3.mean(heights) - 0.02; - if (cells[i].height < 0.2) cells[i].height = 0.2; - cells[i].lake = true; + console.time('elevateLakes'); + const lakes = $.grep(cells, function(e) {return e.height < 0.2 && !features[e.fn].border;}); + lakes.sort(function(a, b) {return b.height - a.height;}); + for (let i=0; i < lakes.length; i++) { + const heights = []; + lakes[i].neighbors.forEach(function(n) {if (cells[n].height >= 0.2) heights.push(cells[n].height)}); + if (heights.length) lakes[i].height = d3.min(heights) - 0.01; + if (cells[i].height < 0.2) lakes[i].height = 0.2; + lakes[i].lake = true; } + console.timeEnd('elevateLakes'); } // Depression filling algorithm (for a correct water flux modeling; phase1) @@ -1835,7 +1847,7 @@ function fantasyMap() { } } } - cells[min].flux += land[i].flux; + if (cells[min].flux) cells[min].flux += land[i].flux; if (land[i].river !== undefined) { const px = cells[min].data[0]; const py = cells[min].data[1]; @@ -2025,12 +2037,12 @@ function fantasyMap() { } if (land[i].lake === 2) { if (land[i].river !== undefined) { - addLakeAtCell(i); + addLakeAtCell(land[i].index); } else { - //land[i].lake = undefined; + delete land[i].lake; land[i].neighbors.forEach(function(n) { if (cells[n].river !== undefined) { - addLakeAtCell(i); + addLakeAtCell(n); return; } }); @@ -2039,18 +2051,18 @@ function fantasyMap() { } function addLakeAtCell(i) { - land[i].height = 0.19; - land[i].ctype = -1; + cells[i].lake = 2; + cells[i].height = 0.19; + cells[i].ctype = -1; let fn = features.length; - land[i].neighbors.forEach(function(e) { + cells[i].neighbors.forEach(function(e) { if (cells[e].height >= 0.2) cells[e].ctype = 1; // change fn to neighboring lake - if (cells[e].lake) fn = cells[e].fn; + if (cells[e].lake === 2 && cells[e].river !== undefined) fn = cells[e].fn; + else if (cells[e].lake === 1) fn = cells[e].fn; }); - land[i].fn = fn; - if (fn === features.length) { - features.push({i: features.length, land: false, border: false}); - } + cells[i].fn = fn; + if (fn === features.length) features.push({i: fn, land: false, border: false}); } land = $.grep(cells, function(e) {return e.height >= 0.2;}); @@ -3303,7 +3315,7 @@ function fantasyMap() { // calculate population for manors, cells and states function calculatePopulation() { // neutral population factors < 1 as neutral lands are usually pretty wild - var ruralFactor = 0.5, urbanFactor = 0.9; + const ruralFactor = 0.5, urbanFactor = 0.9; // calculate population for each burg (based on trade/people attractors) manors.map(function(m) { @@ -3986,7 +3998,6 @@ function fantasyMap() { let dist = 100000, manor = null; if (manors.length) { const c = manorTree.find(x, y); - if (!c) debugger; dist = Math.hypot(c[0] - x, c[1] - y); manor = getManorId(c); } @@ -4233,7 +4244,7 @@ function fantasyMap() { console.time("recalculateCultures"); // For each capital find closest culture and assign it to capital states.forEach(function(s) { - if (s.capital === "neutral") return; + if (s.capital === "neutral" || s.capital === "select") return; const capital = manors[s.capital]; const c = cultureTree.find(capital.x, capital.y); capital.culture = getCultureId(c); @@ -4389,7 +4400,7 @@ function fantasyMap() { delete c.coastY; if (c.ctype === undefined) {delete c.ctype;} c.height = rn(c.height, 2); - c.flux = rn(c.flux, 2); + if (c.height >= 0.2) c.flux = rn(c.flux, 2); }); // restore layers if they was turned on if (!$("#toggleHeight").hasClass("buttonoff") && !terrs.selectAll("path").size()) toggleHeight(); @@ -5715,6 +5726,20 @@ function fantasyMap() { if(data[8]) nameBase = JSON.parse(data[8]); if(data[8]) nameBases = JSON.parse(data[9]); + // calculate areas / population for old maps + const graphSizeAdj = 90 / Math.sqrt(cells.length, 2); // adjust to different graphSize + land.forEach(function(i) { + const p = i.index; + i.area = rn(Math.abs(d3.polygonArea(polygons[p])), 2); + if (i.pop === undefined) { + let population = 0; + const elevationFactor = Math.pow(1 - i.height, 3); + population = elevationFactor * i.area * graphSizeAdj; + if (i.region === "neutral") population *= 0.5; + i.pop = rn(population, 1); + } + }); + // restore Heightmap customization mode if (customization === 1) { optionsTrigger.click(); @@ -5845,6 +5870,9 @@ function fantasyMap() { case 83: // "S" to log states data console.table(states); break; + case 70: // "F" to log features data + console.table(features); + break; case 37: // Left to scroll map left zoom.translateBy(svg, 10, 0); break; @@ -5960,8 +5988,7 @@ function fantasyMap() { $("#countriesManuallyButtons").show(); // highlight capital cells as it's not allowed to change capital's state that way states.map(function(s) { - if (s.color === "neutral") {return;} - if (s.capital === "select") {return;} + if (s.capital === "neutral" || s.capital === "select") return; const capital = s.capital; const index = manors[capital].cell; temp.append("path") @@ -6549,30 +6576,28 @@ function fantasyMap() { function editHeightmap(type) { closeDialogs(); - var heights = [], regionData = [], cultureData = []; - for (var i = 0; i < points.length; i++) { - var cell = diagram.find(points[i][0], points[i][1]).index; + const heights = [], regionData = [], cultureData = []; + for (let i = 0; i < points.length; i++) { + const cell = diagram.find(points[i][0], points[i][1]).index; heights.push(cells[cell].height); - var region = cells[cell].region; - if (region === undefined) {region = -1;} + let region = cells[cell].region; + if (region === undefined) region = -1; regionData.push(region); - var culture = cells[cell].culture; - if (culture === undefined) {culture = -1;} + let culture = cells[cell].culture; + if (culture === undefined) culture = -1; cultureData.push(culture); } - if (type === "clean") {undraw();} + if (type === "clean") undraw(); calculateVoronoi(points); detectNeighbors("grid"); drawScaleBar(); - for (var i = 0; i < points.length; i++) { - cells[i].height = heights[i]; - } + for (let i = 0; i < points.length; i++) {cells[i].height = heights[i];} if (type === "keep") { svg.selectAll("#shape, #lakes, #coastline, #terrain, #rivers, #grid, #terrs, #landmass, #ocean, #regions") .selectAll("path, circle, line").remove(); - for (var i = 0; i < points.length; i++) { - if (regionData[i] !== -1) {cells[i].region = regionData[i];} - if (cultureData[i] !== -1) {cells[i].culture = cultureData[i];} + for (let i = 0; i < points.length; i++) { + if (regionData[i] !== -1) cells[i].region = regionData[i]; + if (cultureData[i] !== -1) cells[i].culture = cultureData[i]; } } mockHeightmap(); @@ -8468,7 +8493,7 @@ function fantasyMap() { neutralBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", .3).attr("stroke-dasharray", "1 1.5").attr("stroke-linecap", "butt"); cults.attr("opacity", .6); rivers.attr("opacity", 1).attr("fill", "#5d97bb"); - lakes.attr("opacity", .5).attr("fill", "#a6c1fd").attr("stroke", "#5f799d").attr("stroke-width", .25); + lakes.attr("opacity", .5).attr("fill", "#a6c1fd").attr("stroke", "#5f799d").attr("stroke-width", .7); icons.selectAll("g").attr("opacity", 1).attr("fill", "#ffffff").attr("stroke", "#3e3e4b"); roads.attr("opacity", .9).attr("stroke", "#d06324").attr("stroke-width", .35).attr("stroke-dasharray", "1.5").attr("stroke-linecap", "butt"); trails.attr("opacity", .9).attr("stroke", "#d06324").attr("stroke-width", .15).attr("stroke-dasharray", ".8 1.6").attr("stroke-linecap", "butt"); From cf360133e8f2f6c365e949b860b217a6cc49380c Mon Sep 17 00:00:00 2001 From: Azgaar Date: Fri, 3 Aug 2018 01:53:57 +0300 Subject: [PATCH 04/25] v. 0.58.03b --- index.css | 4 -- index.html | 16 ++++--- script.js | 121 +++++++++++++++++++++++++---------------------------- 3 files changed, 63 insertions(+), 78 deletions(-) diff --git a/index.css b/index.css index ff5cec57..a83b9dc0 100644 --- a/index.css +++ b/index.css @@ -1297,10 +1297,6 @@ input[type="checkbox"] { height: 100%; } -#capital-anchors, #town-anchors { - transform: translate(-0.47em, -0.47em); -} - #cultureCenters circle:hover { stroke: #000000b3; cursor: pointer; diff --git a/index.html b/index.html index b35af224..5e2f46cd 100644 --- a/index.html +++ b/index.html @@ -31,8 +31,8 @@ - - + + @@ -91,12 +91,10 @@
- - - + - Anchor + Port @@ -747,8 +745,8 @@ - + diff --git a/script.js b/script.js index 385b5b2f..54a10c8f 100644 --- a/script.js +++ b/script.js @@ -1185,10 +1185,8 @@ function fantasyMap() { const edges = []; const lim = +limits[l]; for (let i = 0; i < cells.length; i++) { - //debug.append("text").attr("x", cells[i].data[0]).attr("y", cells[i].data[1]).attr("font-size", 3).text(cells[i].ctype); if (cells[i].ctype < lim || cells[i].ctype === undefined) continue; if (cells[i].ctype > lim && cells[i].type !== "border") continue; - //debug.append("circle").attr("cx", cells[i].data[0]).attr("cy", cells[i].data[1]).attr("r", 1).attr("fill", "red"); const cell = diagram.cells[i]; cell.halfedges.forEach(function(e) { const edge = diagram.edges[e]; @@ -1412,7 +1410,8 @@ function fantasyMap() { // Detect and draw the coasline function drawCoastline() { console.time('drawCoastline'); - const shape = d3.select("#shape"); + const shape = defs.append("mask").attr("id", "shape").attr("fill", "black") + .attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%"); $("#landmass").empty(); let minX = graphWidth, maxX = 0; // extreme points let minXedge, maxXedge; // extreme edges @@ -2638,7 +2637,7 @@ function fantasyMap() { iconGroup.value = group.attr("id"); iconFillColor.value = group.attr("fill"); iconStrokeColor.value = group.attr("stroke"); - iconSize.value = group.attr("font-size"); + iconSize.value = group.attr("size"); iconStrokeWidth.value = group.attr("stroke-width"); $("#iconEditor").dialog({ @@ -2735,7 +2734,9 @@ function fantasyMap() { $("#iconSize").change(function() { const group = d3.select(elSelected.node().parentNode); - group.attr("font-size", this.value); + const size = +this.value + group.attr("size", size); + group.selectAll("*").each(function() {d3.select(this).attr("width", size).attr("height", size)}); }); $("#iconStrokeWidth").change(function() { @@ -2879,7 +2880,7 @@ function fantasyMap() { const rotation = matrix ? matrix.split('(')[1].split(')')[0].split(' ')[0] : 0; burgLabelAngle.value = rotation; burgLabelAngleOutput.innerHTML = rotation + "°"; - burgIconSize.value = iconGroup.attr("font-size"); + burgIconSize.value = iconGroup.attr("size"); burgIconFillOpacity.value = iconGroup.attr("fill-opacity") === undefined ? 1 : +iconGroup.attr("fill-opacity"); burgIconFillColor.value = iconGroup.attr("fill"); burgIconStrokeWidth.value = iconGroup.attr("stroke-width"); @@ -2894,14 +2895,7 @@ function fantasyMap() { burgToggleCapital.disabled = true; d3.select("#burgToggleCapital").classed("pressed", false); } - if (cell.ctype === 1 || cell.river !== undefined) { - burgTogglePort.disabled = false; - const port = cell.port !== undefined ? 1 : 0; - d3.select("#burgTogglePort").classed("pressed", port); - } else { - burgTogglePort.disabled = true; - d3.select("#burgTogglePort").classed("pressed", false); - } + d3.select("#burgTogglePort").classed("pressed", cell.port !== undefined); burgPopulation.value = manors[id].population; burgPopulationFriendly.value = rn(manors[id].population * urbanization.value * populationRate.value * 1000); @@ -3116,7 +3110,9 @@ function fantasyMap() { $("#burgIconSize").on("input", function() { const type = elSelected.node().parentNode.id; const group = burgIcons.select("#"+type); - group.attr("font-size", +this.value); + const size = +this.value + group.attr("size", size); + group.selectAll("*").each(function() {d3.select(this).attr("r", size)}); }); $("#burgIconFillOpacity").on("input", function() { @@ -3175,14 +3171,19 @@ function fantasyMap() { $("#burgTogglePort").click(function() { const id = +elSelected.attr("data-id"); - const port = cells[manors[id].cell].port === undefined; - //cells[manors[id].cell].port = port; - d3.select("#burgTogglePort").classed("pressed", port); - if (port) { + const cell = cells[manors[id].cell]; + const markAsPort = cell.port === undefined ? true : undefined; + cell.port = markAsPort; + d3.select("#burgTogglePort").classed("pressed", markAsPort); + if (markAsPort) { const type = elSelected.node().parentNode.id; const ag = type === "capitals" ? "#capital-anchors" : "#town-anchors"; - icons.select(ag).append("use").attr("xlink:href", "#icon-anchor").attr("data-id", id) - .attr("x", manors[id].x).attr("y", manors[id].y).attr("width", "1em").attr("height", "1em") + const group = icons.select(ag); + const size = +group.attr("size"); + const x = rn(manors[id].x - size * 0.47, 2); + const y = rn(manors[id].y - size * 0.47, 2); + group.append("use").attr("xlink:href", "#icon-anchor").attr("data-id", id) + .attr("x", x).attr("y", y).attr("width", size).attr("height", size) .on("click", editIcon); } else { $("#icons g[id*='anchors'] [data-id=" + id + "]").remove(); @@ -3606,6 +3607,8 @@ function fantasyMap() { lineGen.curve(d3.curveBasis); const cAnchors = icons.selectAll("#capital-anchors"); const tAnchors = icons.selectAll("#town-anchors"); + const cSize = cAnchors.attr("size") || 2; + const tSize = tAnchors.attr("size") || 1; const ports = []; // groups all ports on water feature @@ -3617,11 +3620,12 @@ function fantasyMap() { ports[port].push(cell); // draw anchor icon - const x = cells[cell].data[0]; - const y = cells[cell].data[1]; const group = m < states.length ? cAnchors : tAnchors; + const size = m < states.length ? cSize : tSize; + const x = rn(cells[cell].data[0] - size * 0.47, 2); + const y = rn(cells[cell].data[1] - size * 0.47, 2); group.append("use").attr("xlink:href", "#icon-anchor").attr("data-id", m) - .attr("x", x).attr("y", y).attr("width", "1em").attr("height", "1em"); + .attr("x", x).attr("y", y).attr("width", size).attr("height", size); icons.selectAll("use").on("click", editIcon); } @@ -3867,6 +3871,8 @@ function fantasyMap() { const capitalLabels = burgLabels.select("#capitals"); const townIcons = burgIcons.select("#towns"); const townLabels = burgLabels.select("#towns"); + const capitalSize = capitalIcons.attr("size") || 1; + const townSize = townIcons.attr("size") || 0.5; capitalIcons.selectAll("*").remove(); capitalLabels.selectAll("*").remove(); townIcons.selectAll("*").remove(); @@ -3878,7 +3884,8 @@ function fantasyMap() { const name = manors[i].name; const ic = i < states.length ? capitalIcons : townIcons; const lb = i < states.length ? capitalLabels : townLabels; - ic.append("circle").attr("data-id", i).attr("cx", x).attr("cy", y).attr("r", "1em").on("click", editBurg); + const size = i < states.length ? capitalSize : townSize; + ic.append("circle").attr("data-id", i).attr("cx", x).attr("cy", y).attr("r", size).on("click", editBurg); lb.append("text").attr("data-id", i).attr("x", x).attr("y", y).attr("dy", "-0.35em").text(name).on("click", editBurg); } console.timeEnd('drawManors'); @@ -4724,7 +4731,8 @@ function fantasyMap() { return; } var i = manors.length; - burgIcons.select("#towns").append("circle").attr("data-id", i).attr("cx", x).attr("cy", y).attr("r", "1em").on("click", editBurg); + const size = burgIcons.select("#towns").attr("size"); + burgIcons.select("#towns").append("circle").attr("data-id", i).attr("cx", x).attr("cy", y).attr("r", size).on("click", editBurg); burgLabels.select("#towns").append("text").attr("data-id", i).attr("x", x).attr("y", y).attr("dy", "-0.35em").text(name).on("click", editBurg); invokeActiveZooming(); @@ -5329,7 +5337,7 @@ function fantasyMap() { // to fix use elements sizing clone.selectAll("use").each(function() { - const size = this.parentNode.getAttribute("font-size") || 1; + const size = this.parentNode.getAttribute("size") || 1; this.setAttribute("width", size + "px"); this.setAttribute("height", size + "px"); }); @@ -5669,20 +5677,26 @@ function fantasyMap() { this.removeAttribute("id"); this.setAttribute("data-id", +id.replace("manorLabel", "")); }); - icons.select("#burgIcons").select("#capitals").attr("font-size", 1).attr("fill-opacity", .7).attr("stroke-opacity", 1); - icons.select("#burgIcons").select("#towns").attr("font-size", .5).attr("fill-opacity", .7).attr("stroke-opacity", 1); + icons.select("#burgIcons").select("#capitals").attr("size", 1).attr("fill-opacity", .7).attr("stroke-opacity", 1); + icons.select("#burgIcons").select("#towns").attr("size", .5).attr("fill-opacity", .7).attr("stroke-opacity", 1); icons.select("#burgIcons").selectAll("circle").each(function() { let id = this.getAttribute("id"); if (!id) return; this.removeAttribute("id"); + this.setAttribute("r", this.parentNode.getAttribute("size")); this.setAttribute("data-id", +id.replace("manorIcon", "")); }); - icons.select("#capital-anchors").raise().attr("font-size", 2).attr("size", null); - icons.select("#town-anchorss").raise().attr("font-size", 1).attr("size", null); - icons.selectAll("use").each(function() { - this.setAttribute("width", "1em"); - this.setAttribute("hieght", "1em"); + icons.select("#capital-anchors").raise().attr("size", 2).attr("size", null); + icons.select("#capital-anchors").selectAll("use").each(function() { + this.setAttribute("width", "2"); + this.setAttribute("height", "2"); }); + icons.select("#town-anchors").raise().attr("size", 1).attr("size", null); + icons.select("#town-anchors").selectAll("use").each(function() { + this.setAttribute("width", "1"); + this.setAttribute("height", "1"); + }); + } if (labels.select("#countries").size() === 0) { labels.append("g").attr("id", "countries") @@ -6464,30 +6478,6 @@ function fantasyMap() { invokeActiveZooming(); return; } - if (id === "styleFillPlus" || id === "styleFillMinus") { - var el = viewbox.select("#"+styleElementSelect.value); - var mod = id === "styleFillPlus" ? 1.1 : 0.9; - el.selectAll("g").each(function() { - var el = d3.select(this); - if (el.attr("id") === "burgIcons") return; - var size = rn(el.attr("font-size") * mod, 2); - if (size < 0.1) {size = 0.1;} - el.attr("font-size", size); - }); - return; - } - if (id === "styleStrokePlus" || id === "styleStrokeMinus") { - var el = viewbox.select("#"+styleElementSelect.value); - var mod = id === "styleStrokePlus" ? 1.1 : 0.9; - el.selectAll("*").each(function() { - var el = d3.select(this); - if (el.attr("id") === "burgIcons") return; - var size = rn(el.attr("stroke-width") * mod, 2); - if (size < 0.1) {size = 0.1;} - el.attr("stroke-width", size); - }); - return; - } if (id === "brushClear") { if (customization === 1) { var message = "Are you sure you want to clear the map?"; @@ -6593,8 +6583,9 @@ function fantasyMap() { drawScaleBar(); for (let i = 0; i < points.length; i++) {cells[i].height = heights[i];} if (type === "keep") { - svg.selectAll("#shape, #lakes, #coastline, #terrain, #rivers, #grid, #terrs, #landmass, #ocean, #regions") + svg.selectAll("#lakes, #coastline, #terrain, #rivers, #grid, #terrs, #landmass, #ocean, #regions") .selectAll("path, circle, line").remove(); + svg.select("#shape").remove(); for (let i = 0; i < points.length; i++) { if (regionData[i] !== -1) cells[i].region = regionData[i]; if (cultureData[i] !== -1) cells[i].culture = cultureData[i]; @@ -7141,7 +7132,7 @@ function fantasyMap() { // Clear the map function undraw() { viewbox.selectAll("path, circle, line, text, use, #ruler > g").remove(); - defs.selectAll("path").remove(); + svg.select("#shape").remove(); cells = [], land = [], riversData = [], manors = [], states = [], features = [], queue = []; } @@ -7375,7 +7366,7 @@ function fantasyMap() { if (cells[index].port !== undefined) {score *= 3;} // port-capital var population = rn(score, 1); manors.push({i, cell:index, x, y, region: state, culture, name, population}); - burgIcons.select("#capitals").append("circle").attr("data-id", i).attr("cx", x).attr("cy", y).attr("r", "1em").on("click", editBurg); + burgIcons.select("#capitals").append("circle").attr("data-id", i).attr("cx", x).attr("cy", y).attr("r", 1).on("click", editBurg); burgLabels.select("#capitals").append("text").attr("data-id", i).attr("x", x).attr("y", y).attr("dy", "-0.35em").text(name).on("click", editBurg); } cells[index].region = state; @@ -8517,13 +8508,13 @@ function fantasyMap() { if (size < 3) size = 3; burgLabels.select("#capitals").attr("fill", "#3e3e4b").attr("opacity", 1).attr("font-family", "Almendra SC").attr("data-font", "Almendra+SC").attr("font-size", size).attr("data-size", size); burgLabels.select("#towns").attr("fill", "#3e3e4b").attr("opacity", 1).attr("font-family", "Almendra SC").attr("data-font", "Almendra+SC").attr("font-size", 3).attr("data-size", 4); - burgIcons.select("#capitals").attr("font-size", 1).attr("stroke-width", .24).attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("fill-opacity", .7).attr("stroke-opacity", 1).attr("opacity", 1); - burgIcons.select("#towns").attr("font-size", .5).attr("stroke-width", .12).attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("fill-opacity", .7).attr("stroke-opacity", 1).attr("opacity", 1); + burgIcons.select("#capitals").attr("size", 1).attr("stroke-width", .24).attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("fill-opacity", .7).attr("stroke-opacity", 1).attr("opacity", 1); + burgIcons.select("#towns").attr("size", .5).attr("stroke-width", .12).attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("fill-opacity", .7).attr("stroke-opacity", 1).attr("opacity", 1); size = rn(16 - regionsInput.value / 6); if (size < 6) size = 6; labels.select("#countries").attr("fill", "#3e3e4b").attr("opacity", 1).attr("font-family", "Almendra SC").attr("data-font", "Almendra+SC").attr("font-size", size).attr("data-size", size); - icons.select("#capital-anchors").attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("stroke-width", 1.2).attr("font-size", 2); - icons.select("#town-anchors").attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("stroke-width", 1.2).attr("font-size", 1); + icons.select("#capital-anchors").attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("stroke-width", 1.2).attr("size", 2); + icons.select("#town-anchors").attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("stroke-width", 1.2).attr("size", 1); } // Options handlers From cdc5cf8c7cc012c895006ee5a1a2300bf5706f88 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sat, 4 Aug 2018 20:40:12 +0300 Subject: [PATCH 05/25] v. 0.58.04b --- index.html | 8 ++++---- script.js | 21 ++++++++++++++++----- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/index.html b/index.html index 5e2f46cd..1a724c9c 100644 --- a/index.html +++ b/index.html @@ -31,8 +31,8 @@ - - + + @@ -414,7 +414,7 @@ Cultures count - + 7 @@ -1109,5 +1109,5 @@ - + diff --git a/script.js b/script.js index 54a10c8f..0ccafc83 100644 --- a/script.js +++ b/script.js @@ -324,11 +324,15 @@ function fantasyMap() { {name:"Luari", color:"#99acfb", base:2}, {name:"Tallian", color:"#a6d854", base:3}, {name:"Toledi", color:"#ffd92f", base:4}, - {name:"Sclavian", color:"#e5c494", base:5}, + {name:"Slovian", color:"#e5c494", base:5}, {name:"Norse", color:"#e8c2ed", base:6}, {name:"Elladian", color:"#96d6be", base:7}, {name:"Latian", color:"#ff7174", base:8}, - {name:"Finnic", color:"#aedff7", base:9}]; + {name:"Somi", color:"#aedff7", base:9}, + {name:"Koryo", color:"#f8baf7", base:10}, + {name:"Hantzu", color:"#fdface", base:11}, + {name:"Yamoto", color:"#ffd9da", base:12} + ]; } // apply default names data @@ -343,7 +347,11 @@ function fantasyMap() { {name: "Nordic", method: "let-to-syl", min: 5, max: 9, d: "kln"}, // real: 3; 12; 7.5; 6 {name: "Greek", method: "let-to-syl", min: 4, max: 10, d: "ls"}, // real: 3; 14; 7.1; 6 {name: "Roman", method: "let-to-syl", min: 5, max: 10, d: ""}, // real: 3; 15; 8.0; 7 - {name: "Finnic", method: "let-to-syl", min: 3, max: 10, d: "aktu"}]; // real: 3; 13; 7.5; 6 + {name: "Finnic", method: "let-to-syl", min: 3, max: 10, d: "aktu"}, // real: 3; 13; 7.5; 6 + {name: "Korean", method: "let-to-syl", min: 5, max: 10, d: ""}, // real: 3; 13; 6.8; 7 + {name: "Chinese", method: "let-to-syl", min: 5, max: 9, d: ""}, // real: 4; 11; 6.9; 6 + {name: "Japanese", method: "let-to-syl", min: 3, max: 9, d: ""} // real: 2; 15; 6.8; 6 + ]; nameBase = [ ["Achern","Aichhalden","Aitern","Albbruck","Alpirsbach","Altensteig","Althengstett","Appenweier","Auggen","Wildbad","Badenen","Badenweiler","Baiersbronn","Ballrechten","Bellingen","Berghaupten","Bernau","Biberach","Biederbach","Binzen","Birkendorf","Birkenfeld","Bischweier","Blumberg","Bollen","Bollschweil","Bonndorf","Bosingen","Braunlingen","Breisach","Breisgau","Breitnau","Brigachtal","Buchenbach","Buggingen","Buhl","Buhlertal","Calw","Dachsberg","Dobel","Donaueschingen","Dornhan","Dornstetten","Dottingen","Dunningen","Durbach","Durrheim","Ebhausen","Ebringen","Efringen","Egenhausen","Ehrenkirchen","Ehrsberg","Eimeldingen","Eisenbach","Elzach","Elztal","Emmendingen","Endingen","Engelsbrand","Enz","Enzklosterle","Eschbronn","Ettenheim","Ettlingen","Feldberg","Fischerbach","Fischingen","Fluorn","Forbach","Freiamt","Freiburg","Freudenstadt","Friedenweiler","Friesenheim","Frohnd","Furtwangen","Gaggenau","Geisingen","Gengenbach","Gernsbach","Glatt","Glatten","Glottertal","Gorwihl","Gottenheim","Grafenhausen","Grenzach","Griesbach","Gutach","Gutenbach","Hag","Haiterbach","Hardt","Harmersbach","Hasel","Haslach","Hausach","Hausen","Hausern","Heitersheim","Herbolzheim","Herrenalb","Herrischried","Hinterzarten","Hochenschwand","Hofen","Hofstetten","Hohberg","Horb","Horben","Hornberg","Hufingen","Ibach","Ihringen","Inzlingen","Kandern","Kappel","Kappelrodeck","Karlsbad","Karlsruhe","Kehl","Keltern","Kippenheim","Kirchzarten","Konigsfeld","Krozingen","Kuppenheim","Kussaberg","Lahr","Lauchringen","Lauf","Laufenburg","Lautenbach","Lauterbach","Lenzkirch","Liebenzell","Loffenau","Loffingen","Lorrach","Lossburg","Mahlberg","Malsburg","Malsch","March","Marxzell","Marzell","Maulburg","Monchweiler","Muhlenbach","Mullheim","Munstertal","Murg","Nagold","Neubulach","Neuenburg","Neuhausen","Neuried","Neuweiler","Niedereschach","Nordrach","Oberharmersbach","Oberkirch","Oberndorf","Oberbach","Oberried","Oberwolfach","Offenburg","Ohlsbach","Oppenau","Ortenberg","otigheim","Ottenhofen","Ottersweier","Peterstal","Pfaffenweiler","Pfalzgrafenweiler","Pforzheim","Rastatt","Renchen","Rheinau","Rheinfelden","Rheinmunster","Rickenbach","Rippoldsau","Rohrdorf","Rottweil","Rummingen","Rust","Sackingen","Sasbach","Sasbachwalden","Schallbach","Schallstadt","Schapbach","Schenkenzell","Schiltach","Schliengen","Schluchsee","Schomberg","Schonach","Schonau","Schonenberg","Schonwald","Schopfheim","Schopfloch","Schramberg","Schuttertal","Schwenningen","Schworstadt","Seebach","Seelbach","Seewald","Sexau","Simmersfeld","Simonswald","Sinzheim","Solden","Staufen","Stegen","Steinach","Steinen","Steinmauern","Straubenhardt","Stuhlingen","Sulz","Sulzburg","Teinach","Tiefenbronn","Tiengen","Titisee","Todtmoos","Todtnau","Todtnauberg","Triberg","Tunau","Tuningen","uhlingen","Unterkirnach","Reichenbach","Utzenfeld","Villingen","Villingendorf","Vogtsburg","Vohrenbach","Waldachtal","Waldbronn","Waldkirch","Waldshut","Wehr","Weil","Weilheim","Weisenbach","Wembach","Wieden","Wiesental","Wildberg","Winzeln","Wittlingen","Wittnau","Wolfach","Wutach","Wutoschingen","Wyhlen","Zavelstein"], ["Abingdon","Albrighton","Alcester","Almondbury","Altrincham","Amersham","Andover","Appleby","Ashboume","Atherstone","Aveton","Axbridge","Aylesbury","Baldock","Bamburgh","Barton","Basingstoke","Berden","Bere","Berkeley","Berwick","Betley","Bideford","Bingley","Birmingham","Blandford","Blechingley","Bodmin","Bolton","Bootham","Boroughbridge","Boscastle","Bossinney","Bramber","Brampton","Brasted","Bretford","Bridgetown","Bridlington","Bromyard","Bruton","Buckingham","Bungay","Burton","Calne","Cambridge","Canterbury","Carlisle","Castleton","Caus","Charmouth","Chawleigh","Chichester","Chillington","Chinnor","Chipping","Chisbury","Cleobury","Clifford","Clifton","Clitheroe","Cockermouth","Coleshill","Combe","Congleton","Crafthole","Crediton","Cuddenbeck","Dalton","Darlington","Dodbrooke","Drax","Dudley","Dunstable","Dunster","Dunwich","Durham","Dymock","Exeter","Exning","Faringdon","Felton","Fenny","Finedon","Flookburgh","Fowey","Frampton","Gateshead","Gatton","Godmanchester","Grampound","Grantham","Guildford","Halesowen","Halton","Harbottle","Harlow","Hatfield","Hatherleigh","Haydon","Helston","Henley","Hertford","Heytesbury","Hinckley","Hitchin","Holme","Hornby","Horsham","Kendal","Kenilworth","Kilkhampton","Kineton","Kington","Kinver","Kirby","Knaresborough","Knutsford","Launceston","Leighton","Lewes","Linton","Louth","Luton","Lyme","Lympstone","Macclesfield","Madeley","Malborough","Maldon","Manchester","Manningtree","Marazion","Marlborough","Marshfield","Mere","Merryfield","Middlewich","Midhurst","Milborne","Mitford","Modbury","Montacute","Mousehole","Newbiggin","Newborough","Newbury","Newenden","Newent","Norham","Northleach","Noss","Oakham","Olney","Orford","Ormskirk","Oswestry","Padstow","Paignton","Penkneth","Penrith","Penzance","Pershore","Petersfield","Pevensey","Pickering","Pilton","Pontefract","Portsmouth","Preston","Quatford","Reading","Redcliff","Retford","Rockingham","Romney","Rothbury","Rothwell","Salisbury","Saltash","Seaford","Seasalter","Sherston","Shifnal","Shoreham","Sidmouth","Skipsea","Skipton","Solihull","Somerton","Southam","Southwark","Standon","Stansted","Stapleton","Stottesdon","Sudbury","Swavesey","Tamerton","Tarporley","Tetbury","Thatcham","Thaxted","Thetford","Thornbury","Tintagel","Tiverton","Torksey","Totnes","Towcester","Tregoney","Trematon","Tutbury","Uxbridge","Wallingford","Wareham","Warenmouth","Wargrave","Warton","Watchet","Watford","Wendover","Westbury","Westcheap","Weymouth","Whitford","Wickwar","Wigan","Wigmore","Winchelsea","Winkleigh","Wiscombe","Witham","Witheridge","Wiveliscombe","Woodbury","Yeovil"], @@ -352,9 +360,12 @@ function fantasyMap() { ["Abanades","Ablanque","Adobes","Ajofrin","Alameda","Alaminos","Alarilla","Albalate","Albares","Albarreal","Albendiego","Alcabon","Alcanizo","Alcaudete","Alcocer","Alcolea","Alcoroches","Aldea","Aldeanueva","Algar","Algora","Alhondiga","Alique","Almadrones","Almendral","Almoguera","Almonacid","Almorox","Alocen","Alovera","Alustante","Angon","Anguita","Anover","Anquela","Arbancon","Arbeteta","Arcicollar","Argecilla","Arges","Armallones","Armuna","Arroyo","Atanzon","Atienza","Aunon","Azuqueca","Azutan","Baides","Banos","Banuelos","Barcience","Bargas","Barriopedro","Belvis","Berninches","Borox","Brihuega","Budia","Buenaventura","Bujalaro","Burguillos","Burujon","Bustares","Cabanas","Cabanillas","Calera","Caleruela","Calzada","Camarena","Campillo","Camunas","Canizar","Canredondo","Cantalojas","Cardiel","Carmena","Carranque","Carriches","Casa","Casarrubios","Casas","Casasbuenas","Caspuenas","Castejon","Castellar","Castilforte","Castillo","Castilnuevo","Cazalegas","Cebolla","Cedillo","Cendejas","Centenera","Cervera","Checa","Chequilla","Chillaron","Chiloeches","Chozas","Chueca","Cifuentes","Cincovillas","Ciruelas","Ciruelos","Cobeja","Cobeta","Cobisa","Cogollor","Cogolludo","Condemios","Congostrina","Consuegra","Copernal","Corduente","Corral","Cuerva","Domingo","Dosbarrios","Driebes","Duron","El","Embid","Erustes","Escalona","Escalonilla","Escamilla","Escariche","Escopete","Espinosa","Espinoso","Esplegares","Esquivias","Estables","Estriegana","Fontanar","Fuembellida","Fuensalida","Fuentelsaz","Gajanejos","Galve","Galvez","Garciotum","Gascuena","Gerindote","Guadamur","Henche","Heras","Herreria","Herreruela","Hijes","Hinojosa","Hita","Hombrados","Hontanar","Hontoba","Horche","Hormigos","Huecas","Huermeces","Huerta","Hueva","Humanes","Illan","Illana","Illescas","Iniestola","Irueste","Jadraque","Jirueque","Lagartera","Las","Layos","Ledanca","Lillo","Lominchar","Loranca","Los","Lucillos","Lupiana","Luzaga","Luzon","Madridejos","Magan","Majaelrayo","Malaga","Malaguilla","Malpica","Mandayona","Mantiel","Manzaneque","Maqueda","Maranchon","Marchamalo","Marjaliza","Marrupe","Mascaraque","Masegoso","Matarrubia","Matillas","Mazarete","Mazuecos","Medranda","Megina","Mejorada","Mentrida","Mesegar","Miedes","Miguel","Millana","Milmarcos","Mirabueno","Miralrio","Mocejon","Mochales","Mohedas","Molina","Monasterio","Mondejar","Montarron","Mora","Moratilla","Morenilla","Muduex","Nambroca","Navalcan","Negredo","Noblejas","Noez","Nombela","Noves","Numancia","Nuno","Ocana","Ocentejo","Olias","Olmeda","Ontigola","Orea","Orgaz","Oropesa","Otero","Palmaces","Palomeque","Pantoja","Pardos","Paredes","Pareja","Parrillas","Pastrana","Pelahustan","Penalen","Penalver","Pepino","Peralejos","Peralveche","Pinilla","Pioz","Piqueras","Polan","Portillo","Poveda","Pozo","Pradena","Prados","Puebla","Puerto","Pulgar","Quer","Quero","Quintanar","Quismondo","Rebollosa","Recas","Renera","Retamoso","Retiendas","Riba","Rielves","Rillo","Riofrio","Robledillo","Robledo","Romanillos","Romanones","Rueda","Sacecorbo","Sacedon","Saelices","Salmeron","San","Santa","Santiuste","Santo","Sartajada","Sauca","Sayaton","Segurilla","Selas","Semillas","Sesena","Setiles","Sevilleja","Sienes","Siguenza","Solanillos","Somolinos","Sonseca","Sotillo","Sotodosos","Talavera","Tamajon","Taragudo","Taravilla","Tartanedo","Tembleque","Tendilla","Terzaga","Tierzo","Tordellego","Tordelrabano","Tordesilos","Torija","Torralba","Torre","Torrecilla","Torrecuadrada","Torrejon","Torremocha","Torrico","Torrijos","Torrubia","Tortola","Tortuera","Tortuero","Totanes","Traid","Trijueque","Trillo","Turleque","Uceda","Ugena","Ujados","Urda","Utande","Valdarachas","Valdesotos","Valhermoso","Valtablado","Valverde","Velada","Viana","Vinuelas","Yebes","Yebra","Yelamos","Yeles","Yepes","Yuncler","Yunclillos","Yuncos","Yunquera","Zaorejas","Zarzuela","Zorita"], ["Belgorod","Beloberezhye","Belyi","Belz","Berestiy","Berezhets","Berezovets","Berezutsk","Bobruisk","Bolonets","Borisov","Borovsk","Bozhesk","Bratslav","Bryansk","Brynsk","Buryn","Byhov","Chechersk","Chemesov","Cheremosh","Cherlen","Chern","Chernigov","Chernitsa","Chernobyl","Chernogorod","Chertoryesk","Chetvertnia","Demyansk","Derevesk","Devyagoresk","Dichin","Dmitrov","Dorogobuch","Dorogobuzh","Drestvin","Drokov","Drutsk","Dubechin","Dubichi","Dubki","Dubkov","Dveren","Galich","Glebovo","Glinsk","Goloty","Gomiy","Gorodets","Gorodische","Gorodno","Gorohovets","Goroshin","Gorval","Goryshon","Holm","Horobor","Hoten","Hotin","Hotmyzhsk","Ilovech","Ivan","Izborsk","Izheslavl","Kamenets","Kanev","Karachev","Karna","Kavarna","Klechesk","Klyapech","Kolomyya","Kolyvan","Kopyl","Korec","Kornik","Korochunov","Korshev","Korsun","Koshkin","Kotelno","Kovyla","Kozelsk","Kozelsk","Kremenets","Krichev","Krylatsk","Ksniatin","Kulatsk","Kursk","Kursk","Lebedev","Lida","Logosko","Lomihvost","Loshesk","Loshichi","Lubech","Lubno","Lubutsk","Lutsk","Luchin","Luki","Lukoml","Luzha","Lvov","Mtsensk","Mdin","Medniki","Melecha","Merech","Meretsk","Mescherskoe","Meshkovsk","Metlitsk","Mezetsk","Mglin","Mihailov","Mikitin","Mikulino","Miloslavichi","Mogilev","Mologa","Moreva","Mosalsk","Moschiny","Mozyr","Mstislav","Mstislavets","Muravin","Nemech","Nemiza","Nerinsk","Nichan","Novgorod","Novogorodok","Obolichi","Obolensk","Obolensk","Oleshsk","Olgov","Omelnik","Opoka","Opoki","Oreshek","Orlets","Osechen","Oster","Ostrog","Ostrov","Perelai","Peremil","Peremyshl","Pererov","Peresechen","Perevitsk","Pereyaslav","Pinsk","Ples","Polotsk","Pronsk","Proposhesk","Punia","Putivl","Rechitsa","Rodno","Rogachev","Romanov","Romny","Roslavl","Rostislavl","Rostovets","Rsha","Ruza","Rybchesk","Rylsk","Rzhavesk","Rzhev","Rzhischev","Sambor","Serensk","Serensk","Serpeysk","Shilov","Shuya","Sinech","Sizhka","Skala","Slovensk","Slutsk","Smedin","Sneporod","Snitin","Snovsk","Sochevo","Sokolec","Starica","Starodub","Stepan","Sterzh","Streshin","Sutesk","Svinetsk","Svisloch","Terebovl","Ternov","Teshilov","Teterin","Tiversk","Torchevsk","Toropets","Torzhok","Tripolye","Trubchevsk","Tur","Turov","Usvyaty","Uteshkov","Vasilkov","Velil","Velye","Venev","Venicha","Verderev","Vereya","Veveresk","Viazma","Vidbesk","Vidychev","Voino","Volodimer","Volok","Volyn","Vorobesk","Voronich","Voronok","Vorotynsk","Vrev","Vruchiy","Vselug","Vyatichsk","Vyatka","Vyshegorod","Vyshgorod","Vysokoe","Yagniatin","Yaropolch","Yasenets","Yuryev","Yuryevets","Zaraysk","Zhitomel","Zholvazh","Zizhech","Zubkov","Zudechev","Zvenigorod"], ["Akureyri","Aldra","Alftanes","Andenes","Austbo","Auvog","Bakkafjordur","Ballangen","Bardal","Beisfjord","Bifrost","Bildudalur","Bjerka","Bjerkvik","Bjorkosen","Bliksvaer","Blokken","Blonduos","Bolga","Bolungarvik","Borg","Borgarnes","Bosmoen","Bostad","Bostrand","Botsvika","Brautarholt","Breiddalsvik","Bringsli","Brunahlid","Budardalur","Byggdakjarni","Dalvik","Djupivogur","Donnes","Drageid","Drangsnes","Egilsstadir","Eiteroga","Elvenes","Engavogen","Ertenvog","Eskifjordur","Evenes","Eyrarbakki","Fagernes","Fallmoen","Fellabaer","Fenes","Finnoya","Fjaer","Fjelldal","Flakstad","Flateyri","Flostrand","Fludir","Gardabær","Gardur","Gimstad","Givaer","Gjeroy","Gladstad","Godoya","Godoynes","Granmoen","Gravdal","Grenivik","Grimsey","Grindavik","Grytting","Hafnir","Halsa","Hauganes","Haugland","Hauknes","Hella","Helland","Hellissandur","Hestad","Higrav","Hnifsdalur","Hofn","Hofsos","Holand","Holar","Holen","Holkestad","Holmavik","Hopen","Hovden","Hrafnagil","Hrisey","Husavik","Husvik","Hvammstangi","Hvanneyri","Hveragerdi","Hvolsvollur","Igeroy","Indre","Inndyr","Innhavet","Innes","Isafjordur","Jarklaustur","Jarnsreykir","Junkerdal","Kaldvog","Kanstad","Karlsoy","Kavosen","Keflavik","Kjelde","Kjerstad","Klakk","Kopasker","Kopavogur","Korgen","Kristnes","Krutoga","Krystad","Kvina","Lande","Laugar","Laugaras","Laugarbakki","Laugarvatn","Laupstad","Leines","Leira","Leiren","Leland","Lenvika","Loding","Lodingen","Lonsbakki","Lopsmarka","Lovund","Luroy","Maela","Melahverfi","Meloy","Mevik","Misvaer","Mornes","Mosfellsbær","Moskenes","Myken","Naurstad","Nesberg","Nesjahverfi","Nesset","Nevernes","Obygda","Ofoten","Ogskardet","Okervika","Oknes","Olafsfjordur","Oldervika","Olstad","Onstad","Oppeid","Oresvika","Orsnes","Orsvog","Osmyra","Overdal","Prestoya","Raudalaekur","Raufarhofn","Reipo","Reykholar","Reykholt","Reykjahlid","Rif","Rinoya","Rodoy","Rognan","Rosvika","Rovika","Salhus","Sanden","Sandgerdi","Sandoker","Sandset","Sandvika","Saudarkrokur","Selfoss","Selsoya","Sennesvik","Setso","Siglufjordur","Silvalen","Skagastrond","Skjerstad","Skonland","Skorvogen","Skrova","Sleneset","Snubba","Softing","Solheim","Solheimar","Sorarnoy","Sorfugloy","Sorland","Sormela","Sorvaer","Sovika","Stamsund","Stamsvika","Stave","Stokka","Stokkseyri","Storjord","Storo","Storvika","Strand","Straumen","Strendene","Sudavik","Sudureyri","Sundoya","Sydalen","Thingeyri","Thorlakshofn","Thorshofn","Tjarnabyggd","Tjotta","Tosbotn","Traelnes","Trofors","Trones","Tverro","Ulvsvog","Unnstad","Utskor","Valla","Vandved","Varmahlid","Vassos","Vevelstad","Vidrek","Vik","Vikholmen","Vogar","Vogehamn","Vopnafjordur"], - ["Abdera","Abila","Abydos","Acanthus","Acharnae","Actium","Adramyttium","Aegae","Aegina","Aegium","Aenus","Agrinion","Aigosthena","Akragas","Akrai","Akrillai","Akroinon","Akrotiri","Alalia","Alexandreia","Alexandretta","Alexandria","Alinda","Amarynthos","Amaseia","Ambracia","Amida","Amisos","Amnisos","Amphicaea","Amphigeneia","Amphipolis","Amphissa","Ankon","Antigona","Antipatrea","Antioch","Antioch","Antiochia","Andros","Apamea","Aphidnae","Apollonia","Argos","Arsuf","Artanes","Artemita","Argyroupoli","Asine","Asklepios","Aspendos","Assus","Astacus","Athenai","Athmonia","Aytos","Ancient","Baris","Bhrytos","Borysthenes","Berge","Boura","Bouthroton","Brauron","Byblos","Byllis","Byzantium","Bythinion","Callipolis","Cebrene","Chalcedon","Calydon","Carystus","Chamaizi","Chalcis","Chersonesos","Chios","Chytri","Clazomenae","Cleonae","Cnidus","Colosse","Corcyra","Croton","Cyme","Cyrene","Cythera","Decelea","Delos","Delphi","Demetrias","Dicaearchia","Dimale","Didyma","Dion","Dioscurias","Dodona","Dorylaion","Dyme","Edessa","Elateia","Eleusis","Eleutherna","Emporion","Ephesus","Ephyra","Epidamnos","Epidauros","Eresos","Eretria","Erythrae","Eubea","Gangra","Gaza","Gela","Golgi","Gonnos","Gorgippia","Gournia","Gortyn","Gythium","Hagios","Hagia","Halicarnassus","Halieis","Helike","Heliopolis","Hellespontos","Helorus","Hemeroskopeion","Heraclea","Hermione","Hermonassa","Hierapetra","Hierapolis","Himera","Histria","Hubla","Hyele","Ialysos","Iasus","Idalium","Imbros","Iolcus","Itanos","Ithaca","Juktas","Kallipolis","Kamares","Kameiros","Kannia","Kamarina","Kasmenai","Katane","Kerkinitida","Kepoi","Kimmerikon","Kios","Klazomenai","Knidos","Knossos","Korinthos","Kos","Kourion","Kume","Kydonia","Kynos","Kyrenia","Lamia","Lampsacus","Laodicea","Lapithos","Larissa","Lato","Laüs","Lebena","Lefkada","Lekhaion","Leibethra","Leontinoi","Lepreum","Lessa","Lilaea","Lindus","Lissus","Epizephyrian","Madytos","Magnesia","Mallia","Mantineia","Marathon","Marmara","Maroneia","Masis","Massalia","Megalopolis","Megara","Mesembria","Messene","Metapontum","Methana","Methone","Methumna","Miletos","Misenum","Mochlos","Monastiraki","Morgantina","Mulai","Mukenai","Mylasa","Myndus","Myonia","Myra","Myrmekion","Mutilene","Myos","Nauplíos","Naucratis","Naupactus","Naxos","Neapoli","Neapolis","Nemea","Nicaea","Nicopolis","Nirou","Nymphaion","Nysa","Oenoe","Oenus","Odessos","Olbia","Olous","Olympia","Olynthus","Opus","Orchomenus","Oricos","Orestias","Oreus","Oropus","Onchesmos","Pactye","Pagasae","Palaikastro","Pandosia","Panticapaeum","Paphos","Parium","Paros","Parthenope","Patrae","Pavlopetri","Pegai","Pelion","Peiraieús","Pella","Percote","Pergamum","Petsofa","Phaistos","Phaleron","Phanagoria","Pharae","Pharnacia","Pharos","Phaselis","Philippi","Pithekussa","Philippopolis","Platanos","Phlius","Pherae","Phocaea","Pinara","Pisa","Pitane","Pitiunt","Pixous","Plataea","Poseidonia","Potidaea","Priapus","Priene","Prousa","Pseira","Psychro","Pteleum","Pydna","Pylos","Pyrgos","Rhamnus","Rhegion","Rhithymna","Rhodes","Rhypes","Rizinia","Salamis","Same","Samos","Scyllaeum","Selinus","Seleucia","Semasus","Sestos","Scidrus","Sicyon","Side","Sidon","Siteia","Sinope","Siris","Sklavokampos","Smyrna","Soli","Sozopolis","Sparta","Stagirus","Stratos","Stymphalos","Sybaris","Surakousai","Taras","Tanagra","Tanais","Tauromenion","Tegea","Temnos","Tenedos","Tenea","Teos","Thapsos","Thassos","Thebai","Theodosia","Therma","Thespiae","Thronion","Thoricus","Thurii","Thyreum","Thyria","Tiruns","Tithoraea","Tomis","Tragurion","Trapeze","Trapezus","Tripolis","Troizen","Troliton","Troy","Tylissos","Tyras","Tyros","Tyritake","Vasiliki","Vathypetros","Zakynthos","Zakros","Zankle"], + ["Abdera","Abila","Abydos","Acanthus","Acharnae","Actium","Adramyttium","Aegae","Aegina","Aegium","Aenus","Agrinion","Aigosthena","Akragas","Akrai","Akrillai","Akroinon","Akrotiri","Alalia","Alexandreia","Alexandretta","Alexandria","Alinda","Amarynthos","Amaseia","Ambracia","Amida","Amisos","Amnisos","Amphicaea","Amphigeneia","Amphipolis","Amphissa","Ankon","Antigona","Antipatrea","Antioch","Antioch","Antiochia","Andros","Apamea","Aphidnae","Apollonia","Argos","Arsuf","Artanes","Artemita","Argyroupoli","Asine","Asklepios","Aspendos","Assus","Astacus","Athenai","Athmonia","Aytos","Ancient","Baris","Bhrytos","Borysthenes","Berge","Boura","Bouthroton","Brauron","Byblos","Byllis","Byzantium","Bythinion","Callipolis","Cebrene","Chalcedon","Calydon","Carystus","Chamaizi","Chalcis","Chersonesos","Chios","Chytri","Clazomenae","Cleonae","Cnidus","Colosse","Corcyra","Croton","Cyme","Cyrene","Cythera","Decelea","Delos","Delphi","Demetrias","Dicaearchia","Dimale","Didyma","Dion","Dioscurias","Dodona","Dorylaion","Dyme","Edessa","Elateia","Eleusis","Eleutherna","Emporion","Ephesus","Ephyra","Epidamnos","Epidauros","Eresos","Eretria","Erythrae","Eubea","Gangra","Gaza","Gela","Golgi","Gonnos","Gorgippia","Gournia","Gortyn","Gythium","Hagios","Hagia","Halicarnassus","Halieis","Helike","Heliopolis","Hellespontos","Helorus","Hemeroskopeion","Heraclea","Hermione","Hermonassa","Hierapetra","Hierapolis","Himera","Histria","Hubla","Hyele","Ialysos","Iasus","Idalium","Imbros","Iolcus","Itanos","Ithaca","Juktas","Kallipolis","Kamares","Kameiros","Kannia","Kamarina","Kasmenai","Katane","Kerkinitida","Kepoi","Kimmerikon","Kios","Klazomenai","Knidos","Knossos","Korinthos","Kos","Kourion","Kume","Kydonia","Kynos","Kyrenia","Lamia","Lampsacus","Laodicea","Lapithos","Larissa","Lato","Laus","Lebena","Lefkada","Lekhaion","Leibethra","Leontinoi","Lepreum","Lessa","Lilaea","Lindus","Lissus","Epizephyrian","Madytos","Magnesia","Mallia","Mantineia","Marathon","Marmara","Maroneia","Masis","Massalia","Megalopolis","Megara","Mesembria","Messene","Metapontum","Methana","Methone","Methumna","Miletos","Misenum","Mochlos","Monastiraki","Morgantina","Mulai","Mukenai","Mylasa","Myndus","Myonia","Myra","Myrmekion","Mutilene","Myos","Nauplíos","Naucratis","Naupactus","Naxos","Neapoli","Neapolis","Nemea","Nicaea","Nicopolis","Nirou","Nymphaion","Nysa","Oenoe","Oenus","Odessos","Olbia","Olous","Olympia","Olynthus","Opus","Orchomenus","Oricos","Orestias","Oreus","Oropus","Onchesmos","Pactye","Pagasae","Palaikastro","Pandosia","Panticapaeum","Paphos","Parium","Paros","Parthenope","Patrae","Pavlopetri","Pegai","Pelion","Peiraieús","Pella","Percote","Pergamum","Petsofa","Phaistos","Phaleron","Phanagoria","Pharae","Pharnacia","Pharos","Phaselis","Philippi","Pithekussa","Philippopolis","Platanos","Phlius","Pherae","Phocaea","Pinara","Pisa","Pitane","Pitiunt","Pixous","Plataea","Poseidonia","Potidaea","Priapus","Priene","Prousa","Pseira","Psychro","Pteleum","Pydna","Pylos","Pyrgos","Rhamnus","Rhegion","Rhithymna","Rhodes","Rhypes","Rizinia","Salamis","Same","Samos","Scyllaeum","Selinus","Seleucia","Semasus","Sestos","Scidrus","Sicyon","Side","Sidon","Siteia","Sinope","Siris","Sklavokampos","Smyrna","Soli","Sozopolis","Sparta","Stagirus","Stratos","Stymphalos","Sybaris","Surakousai","Taras","Tanagra","Tanais","Tauromenion","Tegea","Temnos","Tenedos","Tenea","Teos","Thapsos","Thassos","Thebai","Theodosia","Therma","Thespiae","Thronion","Thoricus","Thurii","Thyreum","Thyria","Tiruns","Tithoraea","Tomis","Tragurion","Trapeze","Trapezus","Tripolis","Troizen","Troliton","Troy","Tylissos","Tyras","Tyros","Tyritake","Vasiliki","Vathypetros","Zakynthos","Zakros","Zankle"], ["Abila","Adflexum","Adnicrem","Aelia","Aelius","Aeminium","Aequum","Agrippina","Agrippinae","Ala","Albanianis","Ambianum","Andautonia","Apulum","Aquae","Aquaegranni","Aquensis","Aquileia","Aquincum","Arae","Argentoratum","Ariminum","Ascrivium","Atrebatum","Atuatuca","Augusta","Aurelia","Aurelianorum","Batavar","Batavorum","Belum","Biriciana","Blestium","Bonames","Bonna","Bononia","Borbetomagus","Bovium","Bracara","Brigantium","Burgodunum","Caesaraugusta","Caesarea","Caesaromagus","Calleva","Camulodunum","Cannstatt","Cantiacorum","Capitolina","Castellum","Castra","Castrum","Cibalae","Clausentum","Colonia","Concangis","Condate","Confluentes","Conimbriga","Corduba","Coria","Corieltauvorum","Corinium","Coriovallum","Cornoviorum","Danum","Deva","Divodurum","Dobunnorum","Drusi","Dubris","Dumnoniorum","Durnovaria","Durocobrivis","Durocornovium","Duroliponte","Durovernum","Durovigutum","Eboracum","Edetanorum","Emerita","Emona","Euracini","Faventia","Flaviae","Florentia","Forum","Gerulata","Gerunda","Glevensium","Hadriani","Herculanea","Isca","Italica","Iulia","Iuliobrigensium","Iuvavum","Lactodurum","Lagentium","Lauri","Legionis","Lemanis","Lentia","Lepidi","Letocetum","Lindinis","Lindum","Londinium","Lopodunum","Lousonna","Lucus","Lugdunum","Luguvalium","Lutetia","Mancunium","Marsonia","Martius","Massa","Matilo","Mattiacorum","Mediolanum","Mod","Mogontiacum","Moridunum","Mursa","Naissus","Nervia","Nida","Nigrum","Novaesium","Noviomagus","Olicana","Ovilava","Parisiorum","Partiscum","Paterna","Pistoria","Placentia","Pollentia","Pomaria","Pons","Portus","Praetoria","Praetorium","Pullum","Ragusium","Ratae","Raurica","Regina","Regium","Regulbium","Rigomagus","Roma","Romula","Rutupiae","Salassorum","Salernum","Salona","Scalabis","Segovia","Silurum","Sirmium","Siscia","Sorviodurum","Sumelocenna","Tarraco","Taurinorum","Theranda","Traiectum","Treverorum","Tungrorum","Turicum","Ulpia","Valentia","Venetiae","Venta","Verulamium","Vesontio","Vetera","Victoriae","Victrix","Villa","Viminacium","Vindelicorum","Vindobona","Vinovia","Viroconium"], - ["Aanekoski","Abjapaluoja","Ahlainen","Aholanvaara","Ahtari","Aijala","Aimala","Akaa","Alajarvi","Alatornio","Alavus","Antsla","Aspo","Bennas","Bjorkoby","Elva","Emasalo","Espoo","Esse","Evitskog","Forssa","Haapajarvi","Haapamaki","Haapavesi","Haapsalu","Haavisto","Hameenlinna","Hameenmaki","Hamina","Hanko","Harjavalta","Hattuvaara","Haukipudas","Hautajarvi","Havumaki","Heinola","Hetta","Hinkabole","Hirmula","Hossa","Huittinen","Husula","Hyryla","Hyvinkaa","Iisalmi","Ikaalinen","Ilmola","Imatra","Inari","Iskmo","Itakoski","Jamsa","Jarvenpaa","Jeppo","Jioesuu","Jiogeva","Joensuu","Jokela","Jokikyla","Jokisuu","Jormua","Juankoski","Jungsund","Jyvaskyla","Kaamasmukka","Kaarina","Kajaani","Kalajoki","Kallaste","Kankaanpaa","Kannus","Kardla","Karesuvanto","Karigasniemi","Karkkila","Karkku","Karksinuia","Karpankyla","Kaskinen","Kasnas","Kauhajoki","Kauhava","Kauniainen","Kauvatsa","Kehra","Keila","Kellokoski","Kelottijarvi","Kemi","Kemijarvi","Kerava","Keuruu","Kiikka","Kiipu","Kilinginiomme","Kiljava","Kilpisjarvi","Kitee","Kiuruvesi","Kivesjarvi","Kiviioli","Kivisuo","Klaukkala","Klovskog","Kohtlajarve","Kokemaki","Kokkola","Kolho","Koria","Koskue","Kotka","Kouva","Kouvola","Kristiina","Kaupunki","Kuhmo","Kunda","Kuopio","Kuressaare","Kurikka","Kusans","Kuusamo","Kylmalankyla","Lahti","Laitila","Lankipohja","Lansikyla","Lappeenranta","Lapua","Laurila","Lautiosaari","Lepsama","Liedakkala","Lieksa","Lihula","Littoinen","Lohja","Loimaa","Loksa","Loviisa","Luohuanylipaa","Lusi","Maardu","Maarianhamina","Malmi","Mantta","Masaby","Masala","Matasvaara","Maula","Miiluranta","Mikkeli","Mioisakula","Munapirtti","Mustvee","Muurahainen","Naantali","Nappa","Narpio","Nickby","Niinimaa","Niinisalo","Nikkila","Nilsia","Nivala","Nokia","Nummela","Nuorgam","Nurmes","Nuvvus","Obbnas","Oitti","Ojakkala","Ollola","onningeby","Orimattila","Orivesi","Otanmaki","Otava","Otepaa","Oulainen","Oulu","Outokumpu","Paavola","Paide","Paimio","Pakankyla","Paldiski","Parainen","Parkano","Parkumaki","Parola","Perttula","Pieksamaki","Pietarsaari","Pioltsamaa","Piolva","Pohjavaara","Porhola","Pori","Porrasa","Porvoo","Pudasjarvi","Purmo","Pussi","Pyhajarvi","Raahe","Raasepori","Raisio","Rajamaki","Rakvere","Rapina","Rapla","Rauma","Rautio","Reposaari","Riihimaki","Rovaniemi","Roykka","Ruonala","Ruottala","Rutalahti","Saarijarvi","Salo","Sastamala","Saue","Savonlinna","Seinajoki","Sillamae","Sindi","Siuntio","Somero","Sompujarvi","Suonenjoki","Suurejaani","Syrjantaka","Tampere","Tamsalu","Tapa","Temmes","Tiorva","Tormasenvaara","Tornio","Tottijarvi","Tulppio","Turenki","Turi","Tuukkala","Tuurala","Tuuri","Tuuski","Ulvila","Unari","Upinniemi","Utti","Uusikaarlepyy","Uusikaupunki","Vaaksy","Vaalimaa","Vaarinmaja","Vaasa","Vainikkala","Valga","Valkeakoski","Vantaa","Varkaus","Vehkapera","Vehmasmaki","Vieki","Vierumaki","Viitasaari","Viljandi","Vilppula","Viohma","Vioru","Virrat","Ylike","Ylivieska","Ylojarvi"] + ["Aanekoski","Abjapaluoja","Ahlainen","Aholanvaara","Ahtari","Aijala","Aimala","Akaa","Alajarvi","Alatornio","Alavus","Antsla","Aspo","Bennas","Bjorkoby","Elva","Emasalo","Espoo","Esse","Evitskog","Forssa","Haapajarvi","Haapamaki","Haapavesi","Haapsalu","Haavisto","Hameenlinna","Hameenmaki","Hamina","Hanko","Harjavalta","Hattuvaara","Haukipudas","Hautajarvi","Havumaki","Heinola","Hetta","Hinkabole","Hirmula","Hossa","Huittinen","Husula","Hyryla","Hyvinkaa","Iisalmi","Ikaalinen","Ilmola","Imatra","Inari","Iskmo","Itakoski","Jamsa","Jarvenpaa","Jeppo","Jioesuu","Jiogeva","Joensuu","Jokela","Jokikyla","Jokisuu","Jormua","Juankoski","Jungsund","Jyvaskyla","Kaamasmukka","Kaarina","Kajaani","Kalajoki","Kallaste","Kankaanpaa","Kannus","Kardla","Karesuvanto","Karigasniemi","Karkkila","Karkku","Karksinuia","Karpankyla","Kaskinen","Kasnas","Kauhajoki","Kauhava","Kauniainen","Kauvatsa","Kehra","Keila","Kellokoski","Kelottijarvi","Kemi","Kemijarvi","Kerava","Keuruu","Kiikka","Kiipu","Kilinginiomme","Kiljava","Kilpisjarvi","Kitee","Kiuruvesi","Kivesjarvi","Kiviioli","Kivisuo","Klaukkala","Klovskog","Kohtlajarve","Kokemaki","Kokkola","Kolho","Koria","Koskue","Kotka","Kouva","Kouvola","Kristiina","Kaupunki","Kuhmo","Kunda","Kuopio","Kuressaare","Kurikka","Kusans","Kuusamo","Kylmalankyla","Lahti","Laitila","Lankipohja","Lansikyla","Lappeenranta","Lapua","Laurila","Lautiosaari","Lepsama","Liedakkala","Lieksa","Lihula","Littoinen","Lohja","Loimaa","Loksa","Loviisa","Luohuanylipaa","Lusi","Maardu","Maarianhamina","Malmi","Mantta","Masaby","Masala","Matasvaara","Maula","Miiluranta","Mikkeli","Mioisakula","Munapirtti","Mustvee","Muurahainen","Naantali","Nappa","Narpio","Nickby","Niinimaa","Niinisalo","Nikkila","Nilsia","Nivala","Nokia","Nummela","Nuorgam","Nurmes","Nuvvus","Obbnas","Oitti","Ojakkala","Ollola","onningeby","Orimattila","Orivesi","Otanmaki","Otava","Otepaa","Oulainen","Oulu","Outokumpu","Paavola","Paide","Paimio","Pakankyla","Paldiski","Parainen","Parkano","Parkumaki","Parola","Perttula","Pieksamaki","Pietarsaari","Pioltsamaa","Piolva","Pohjavaara","Porhola","Pori","Porrasa","Porvoo","Pudasjarvi","Purmo","Pussi","Pyhajarvi","Raahe","Raasepori","Raisio","Rajamaki","Rakvere","Rapina","Rapla","Rauma","Rautio","Reposaari","Riihimaki","Rovaniemi","Roykka","Ruonala","Ruottala","Rutalahti","Saarijarvi","Salo","Sastamala","Saue","Savonlinna","Seinajoki","Sillamae","Sindi","Siuntio","Somero","Sompujarvi","Suonenjoki","Suurejaani","Syrjantaka","Tampere","Tamsalu","Tapa","Temmes","Tiorva","Tormasenvaara","Tornio","Tottijarvi","Tulppio","Turenki","Turi","Tuukkala","Tuurala","Tuuri","Tuuski","Ulvila","Unari","Upinniemi","Utti","Uusikaarlepyy","Uusikaupunki","Vaaksy","Vaalimaa","Vaarinmaja","Vaasa","Vainikkala","Valga","Valkeakoski","Vantaa","Varkaus","Vehkapera","Vehmasmaki","Vieki","Vierumaki","Viitasaari","Viljandi","Vilppula","Viohma","Vioru","Virrat","Ylike","Ylivieska","Ylojarvi"], + ["Sabi","Wiryeseong","Hwando","Gungnae","Ungjin","Wanggeomseong","Ganggyeong","Jochiwon","Cheorwon","Beolgyo","Gangjin","Gampo","Yecheon","Geochang","Janghang","Hadong","Goseong","Yeongdong","Yesan","Sintaein","Geumsan","Boseong","Jangheung","Uiseong","Jumunjin","Janghowon","Hongseong","Gimhwa","Gwangcheon","Guryongpo","Jinyeong","Buan","Damyang","Jangseong","Wando","Angang","Okcheon","Jeungpyeong","Waegwan","Cheongdo","Gwangyang","Gochang","Haenam","Yeonggwang","Hanam","Eumseong","Daejeong","Hanrim","Samrye","Yongjin","Hamyang","Buyeo","Changnyeong","Yeongwol","Yeonmu","Gurye","Hwasun","Hampyeong","Namji","Samnangjin","Dogye","Hongcheon","Munsan","Gapyeong","Ganghwa","Geojin","Sangdong","Jeongseon","Sabuk","Seonghwan","Heunghae","Hapdeok","Sapgyo","Taean","Boeun","Geumwang","Jincheon","Bongdong","Doyang","Geoncheon","Pungsan","Punggi","Geumho","Wonju","Gaun","Hayang","Yeoju","Paengseong","Yeoncheon","Yangpyeong","Ganseong","Yanggu","Yangyang","Inje","Galmal","Pyeongchang","Hwacheon","Hoengseong","Seocheon","Cheongyang","Goesan","Danyang","Hamyeol","Muju","Sunchang","Imsil","Jangsu","Jinan","Goheung","Gokseong","Muan","Yeongam","Jindo","Seonsan","Daegaya","Gunwi","Bonghwa","Seongju","Yeongdeok","Yeongyang","Ulleung","Uljin","Cheongsong","wayang","Namhae","Sancheong","Uiryeong","Gaya","Hapcheon","Wabu","Dongsong","Sindong","Wondeok","Maepo","Anmyeon","Okgu","Sariwon","Dolsan","Daedeok","Gwansan","Geumil","Nohwa","Baeksu","Illo","Jido","Oedong","Ocheon","Yeonil","Hamchang","Pyeonghae","Gijang","Jeonggwan","Aewor","Gujwa","Seongsan","Jeongok","Seonggeo","Seungju","Hongnong","Jangan","Jocheon","Gohan","Jinjeop","Bubal","Beobwon","Yeomchi","Hwado","Daesan","Hwawon","Apo","Nampyeong","Munsan","Sinbuk","Munmak","Judeok","Bongyang","Ungcheon","Yugu","Unbong","Mangyeong","Dong","Naeseo","Sanyang","Soheul","Onsan","Eonyang","Nongong","Dasa","Goa","Jillyang","Bongdam","Naesu","Beomseo","Opo","Gongdo","Jingeon","Onam","Baekseok","Jiksan","Mokcheon","Jori","Anjung","Samho","Ujeong","Buksam","Tongjin","Chowol","Gonjiam","Pogok","Seokjeok","Poseung","Ochang","Hyangnam","Baebang","Gochon","Songak","Samhyang","Yangchon","Osong","Aphae","Ganam","Namyang","Chirwon","Andong","Ansan","Anseong","Anyang","Asan","Boryeong","Bucheon","Busan","Changwon","Cheonan","Cheongju","Chuncheon","Chungju","Daegu","Daejeon","Dangjin","Dongducheon","Donghae","Gangneung","Geoje","Gimcheon","Gimhae","Gimje","Gimpo","Gongju","Goyang","Gumi","Gunpo","Gunsan","Guri","Gwacheon","Gwangju","Gwangju","Gwangmyeong","Gyeongju","Gyeongsan","Gyeryong","Hwaseong","Icheon","Iksan","Incheon","Jecheon","Jeongeup","Jeonju","Jeju","Jinju","Naju","Namyangju","Namwon","Nonsan","Miryang","Mokpo","Mungyeong","Osan","Paju","Pocheon","Pohang","Pyeongtaek","Sacheon","Sangju","Samcheok","Sejong","Seogwipo","Seongnam","Seosan","Seoul","Siheung","Sokcho","Suncheon","Suwon","Taebaek","Tongyeong","Uijeongbu","Uiwang","Ulsan","Yangju","Yangsan","Yeongcheon","Yeongju","Yeosu","Yongin","Chungmu","Daecheon","Donggwangyang","Geumseong","Gyeongseong","Iri","Jangseungpo","Jeomchon","Jeongju","Migeum","Onyang","Samcheonpo","Busan","Busan","Cheongju","Chuncheon","Daegu","Daegu","Daejeon","Daejeon","Gunsan","Gwangju","Gwangju","Gyeongseong","Incheon","Incheon","Iri","Jeonju","Jinhae","Jinju","Masan","Masan","Mokpo","Songjeong","Songtan","Ulsan","Yeocheon","Cheongjin","Gaeseong","Haeju","Hamheung","Heungnam","Jinnampo","Najin","Pyeongyang","Seongjin","Sineuiju","Songnim","Wonsan"], + ["Anding","Anlu","Anqing","Anshun","Baan","Baixing","Banyang","Baoding","Baoqing","Binzhou","Caozhou","Changbai","Changchun","Changde","Changling","Changsha","Changtu","Changzhou","Chaozhou","Cheli","Chengde","Chengdu","Chenzhou","Chizhou","Chongqing","Chuxiong","Chuzhou","Dading","Dali","Daming","Datong","Daxing","Dean","Dengke","Dengzhou","Deqing","Dexing","Dihua","Dingli","Dongan","Dongchang","Dongchuan","Dongping","Duyun","Fengtian","Fengxiang","Fengyang","Fenzhou","Funing","Fuzhou","Ganzhou","Gaoyao","Gaozhou","Gongchang","Guangnan","Guangning","Guangping","Guangxin","Guangzhou","Guide","Guilin","Guiyang","Hailong","Hailun","Hangzhou","Hanyang","Hanzhong","Heihe","Hejian","Henan","Hengzhou","Hezhong","Huaian","Huaide","Huaiqing","Huanglong","Huangzhou","Huining","Huizhou","Hulan","Huzhou","Jiading","Jian","Jianchang","Jiande","Jiangning","Jiankang","Jianning","Jiaxing","Jiayang","Jilin","Jinan","Jingjiang","Jingzhao","Jingzhou","Jinhua","Jinzhou","Jiujiang","Kaifeng","Kaihua","Kangding","Kuizhou","Laizhou","Lanzhou","Leizhou","Liangzhou","Lianzhou","Liaoyang","Lijiang","Linan","Linhuang","Linjiang","Lintao","Liping","Liuzhou","Longan","Longjiang","Longqing","Longxing","Luan","Lubin","Lubin","Luzhou","Mishan","Nanan","Nanchang","Nandian","Nankang","Nanning","Nanyang","Nenjiang","Ningan","Ningbo","Ningguo","Ninguo","Ningwu","Ningxia","Ningyuan","Pingjiang","Pingle","Pingliang","Pingyang","Puer","Puzhou","Qianzhou","Qingyang","Qingyuan","Qingzhou","Qiongzhou","Qujing","Quzhou","Raozhou","Rende","Ruian","Ruizhou","Runing","Shafeng","Shajing","Shaoqing","Shaowu","Shaoxing","Shaozhou","Shinan","Shiqian","Shouchun","Shuangcheng","Shulei","Shunde","Shunqing","Shuntian","Shuoping","Sicheng","Sien","Sinan","Sizhou","Songjiang","Suiding","Suihua","Suining","Suzhou","Taian","Taibei","Tainan","Taiping","Taiwan","Taiyuan","Taizhou","Taonan","Tengchong","Tieli","Tingzhou","Tongchuan","Tongqing","Tongren","Tongzhou","Weihui","Wensu","Wenzhou","Wuchang","Wuding","Wuzhou","Xian","Xianchun","Xianping","Xijin","Xiliang","Xincheng","Xingan","Xingde","Xinghua","Xingjing","Xingqing","Xingyi","Xingyuan","Xingzhong","Xining","Xinmen","Xiping","Xuanhua","Xunzhou","Xuzhou","Yanan","Yangzhou","Yanji","Yanping","Yanqi","Yanzhou","Yazhou","Yichang","Yidu","Yilan","Yili","Yingchang","Yingde","Yingtian","Yingzhou","Yizhou","Yongchang","Yongping","Yongshun","Yongzhou","Yuanzhou","Yuezhou","Yulin","Yunnan","Yunyang","Zezhou","Zhangde","Zhangzhou","Zhaoqing","Zhaotong","Zhenan","Zhending","Zhengding","Zhenhai","Zhenjiang","Zhenxi","Zhenyun","Zhongshan","Zunyi"], + ["Nanporo","Naie","Kamisunagawa","Yuni","Naganuma","Kuriyama","Tsukigata","Urausu","Shintotsukawa","Moseushi","Chippubetsu","Uryu","Hokuryu","Numata","Tobetsu","Suttsu","Kuromatsunai","Rankoshi","Niseko","Kimobetsu","Kyogoku","Kutchan","Kyowa","Iwanai","Shakotan","Furubira","Niki","Yoichi","Toyoura","Toyako","Sobetsu","Shiraoi","Atsuma","Abira","Mukawa","Hidaka","Biratori","Niikappu","Urakawa","Samani","Erimo","Shinhidaka","Matsumae","Fukushima","Shiriuchi","Kikonai","Nanae","Shikabe","Mori","Yakumo","Oshamambe","Esashi","Kaminokuni","Assabu","Otobe","Okushiri","Imakane","Setana","Takasu","Higashikagura","Toma","Pippu","Aibetsu","Kamikawa","Higashikawa","Biei","Kamifurano","Nakafurano","Minamifurano","Horokanai","Wassamu","Kenbuchi","Shimokawa","Bifuka","Nakagawa","Mashike","Obira","Tomamae","Haboro","Enbetsu","Teshio","Hamatonbetsu","Nakatonbetsu","Esashi","Toyotomi","Horonobe","Rebun","Rishiri","Rishirifuji","Bihoro","Tsubetsu","Ozora","Shari","Kiyosato","Koshimizu","Kunneppu","Oketo","Saroma","Engaru","Yubetsu","Takinoue","Okoppe","Omu","Otofuke","Shihoro","Kamishihoro","Shikaoi","Shintoku","Shimizu","Memuro","Taiki","Hiroo","Makubetsu","Ikeda","Toyokoro","Honbetsu","Ashoro","Rikubetsu","Urahoro","Kushiro","Akkeshi","Hamanaka","Shibecha","Teshikaga","Shiranuka","Betsukai","Nakashibetsu","Shibetsu","Rausu","Hiranai","Imabetsu","Sotogahama","Ajigasawa","Fukaura","Fujisaki","Owani","Itayanagi","Tsuruta","Nakadomari","Noheji","Shichinohe","Rokunohe","Yokohama","Tohoku","Oirase","Oma","Sannohe","Gonohe","Takko","Nanbu","Hashikami","Shizukuishi","Kuzumaki","Iwate","Shiwa","Yahaba","Nishiwaga","Kanegasaki","Hiraizumi","Sumita","Otsuchi","Yamada","Iwaizumi","Karumai","Hirono","Ichinohe","Zao","Shichikashuku","Ogawara","Murata","Shibata","Kawasaki","Marumori","Watari","Yamamoto","Matsushima","Shichigahama","Rifu","Taiwa","Osato","Shikama","Kami","Wakuya","Misato","Onagawa","Minamisanriku","Kosaka","Fujisato","Mitane","Happo","Gojome","Hachirogata","Ikawa","Misato","Ugo","Yamanobe","Nakayama","Kahoku","Nishikawa","Asahi","Oe","Oishida","Kaneyama","Mogami","Funagata","Mamurogawa","Takahata","Kawanishi","Oguni","Shirataka","Iide","Mikawa","Shonai","Yuza","Koori","Kunimi","Kawamata","Kagamiishi","Shimogo","Tadami","Minamiaizu","Nishiaizu","Bandai","Inawashiro","Aizubange","Yanaizu","Mishima","Kaneyama","Aizumisato","Yabuki","Tanagura","Yamatsuri","Hanawa","Ishikawa","Asakawa","Furudono","Miharu","Ono","Hirono","Naraha","Tomioka","Okuma","Futaba","Namie","Shinchi","Ibaraki","Oarai","Shirosato","Daigo","Ami","Kawachi","Yachiyo","Goka","Sakai","Tone","Kaminokawa","Mashiko","Motegi","Ichikai","Haga","Mibu","Nogi","Shioya","Takanezawa","Nasu","Nakagawa","Yoshioka","Kanna","Shimonita","Kanra","Nakanojo","Naganohara","Kusatsu","Higashiagatsuma","Minakami","Tamamura","Itakura","Meiwa","Chiyoda","Oizumi","Ora","Ina","Miyoshi","Moroyama","Ogose","Namegawa","Ranzan","Ogawa","Kawajima","Yoshimi","Hatoyama","Tokigawa","Yokoze","Minano","Nagatoro","Ogano","Misato","Kamikawa","Kamisato","Yorii","Miyashiro","Sugito","Matsubushi","Shisui","Sakae","Kozaki","Tako","Tonosho","Kujukuri","Shibayama","Yokoshibahikari","Ichinomiya","Mutsuzawa","Shirako","Nagara","Chonan","Otaki","Onjuku","Kyonan","Mizuho","Hinode","Okutama","Oshima","Hachijo","Aikawa","Hayama","Samukawa","Oiso","Ninomiya","Nakai","Oi","Matsuda","Yamakita","Kaisei","Hakone","Manazuru","Yugawara","Seiro","Tagami","Aga","Izumozaki","Yuzawa","Tsunan","Kamiichi","Tateyama","Nyuzen","Asahi","Kawakita","Tsubata","Uchinada","Shika","Hodatsushimizu","Nakanoto","Anamizu","Noto","Eiheiji","Ikeda","Minamiechizen","Echizen","Mihama","Takahama","Oi","Wakasa","Ichikawamisato","Hayakawa","Minobu","Nanbu","Fujikawa","Showa","Nishikatsura","Fujikawaguchiko","Koumi","Sakuho","Karuizawa","Miyota","Tateshina","Nagawa","Shimosuwa","Fujimi","Tatsuno","Minowa","Iijima","Matsukawa","Takamori","Anan","Agematsu","Nagiso","Kiso","Ikeda","Sakaki","Obuse","Yamanouchi","Shinano","Iizuna","Ginan","Kasamatsu","Yoro","Tarui","Sekigahara","Godo","Wanouchi","Anpachi","Ibigawa","Ono","Ikeda","Kitagata","Sakahogi","Tomika","Kawabe","Hichiso","Yaotsu","Shirakawa","Mitake","Higashiizu","Kawazu","Minamiizu","Matsuzaki","Nishiizu","Kannami","Shimizu","Nagaizumi","Oyama","Yoshida","Kawanehon","Mori","Togo","Toyoyama","Oguchi","Fuso","Oharu","Kanie","Agui","Higashiura","Minamichita","Mihama","Taketoyo","Mihama","Kota","Shitara","Toei","Kisosaki","Toin","Komono","Asahi","Kawagoe","Taki","Meiwa","Odai","Tamaki","Watarai","Taiki","Minamiise","Kihoku","Mihama","Kiho","Hino","Ryuo","Aisho","Toyosato","Kora","Taga","Oyamazaki","Kumiyama","Ide","Ujitawara","Kasagi","Wazuka","Seika","Kyotamba","Ine","Yosano","Shimamoto","Toyono","Nose","Tadaoka","Kumatori","Tajiri","Misaki","Taishi","Kanan","Inagawa","Taka","Inami","Harima","Ichikawa","Fukusaki","Kamikawa","Taishi","Kamigori","Sayo","Kami","Shin'onsen","Heguri","Sango","Ikaruga","Ando","Kawanishi","Miyake","Tawaramoto","Takatori","Kanmaki","Oji","Koryo","Kawai","Yoshino","Oyodo","Shimoichi","Kushimoto","Kimino","Katsuragi","Kudoyama","Koya","Yuasa","Hirogawa","Aridagawa","Mihama","Hidaka","Yura","Inami","Minabe","Hidakagawa","Shirahama","Kamitonda","Susami","Nachikatsuura","Taiji","Kozagawa","Iwami","Wakasa","Chizu","Yazu","Misasa","Yurihama","Kotoura","Hokuei","Daisen","Nanbu","Hoki","Nichinan","Hino","Kofu","Okuizumo","Iinan","Kawamoto","Misato","Onan","Tsuwano","Yoshika","Ama","Nishinoshima","Okinoshima","Wake","Hayashima","Satosho","Yakage","Kagamino","Shoo","Nagi","Kumenan","Misaki","Kibichuo","Fuchu","Kaita","Kumano","Saka","Kitahiroshima","Akiota","Osakikamijima","Sera","Jinsekikogen","Suooshima","Waki","Kaminoseki","Tabuse","Hirao","Abu","Katsuura","Kamikatsu","Ishii","Kamiyama","Naka","Mugi","Minami","Kaiyo","Matsushige","Kitajima","Aizumi","Itano","Kamiita","Tsurugi","Higashimiyoshi","Tonosho","Shodoshima","Miki","Naoshima","Utazu","Ayagawa","Kotohira","Tadotsu","Manno","Kamijima","Kumakogen","Masaki","Tobe","Uchiko","Ikata","Kihoku","Matsuno","Ainan","Toyo","Nahari","Tano","Yasuda","Motoyama","Otoyo","Tosa","Ino","Niyodogawa","Nakatosa","Sakawa","Ochi","Yusuhara","Tsuno","Shimanto","Otsuki","Kuroshio","Nakagawa","Umi","Sasaguri","Shime","Sue","Shingu","Hisayama","Kasuya","Ashiya","Mizumaki","Okagaki","Onga","Kotake","Kurate","Keisen","Chikuzen","Tachiarai","Oki","Hirokawa","Kawara","Soeda","Itoda","Kawasaki","Oto","Fukuchi","Kanda","Miyako","Yoshitomi","Koge","Chikujo","Yoshinogari","Kiyama","Kamimine","Miyaki","Genkai","Arita","Omachi","Kohoku","Shiroishi","Tara","Nagayo","Togitsu","Higashisonogi","Kawatana","Hasami","Ojika","Saza","Shinkamigoto","Misato","Gyokuto","Nankan","Nagasu","Nagomi","Ozu","Kikuyo","Minamioguni","Oguni","Takamori","Mifune","Kashima","Mashiki","Kosa","Yamato","Hikawa","Ashikita","Tsunagi","Nishiki","Taragi","Yunomae","Asagiri","Reihoku","Hiji","Kusu","Kokonoe","Mimata","Takaharu","Kunitomi","Aya","Takanabe","Shintomi","Kijo","Kawaminami","Tsuno","Kadogawa","Misato","Takachiho","Hinokage","Gokase","Satsuma","Nagashima","Yusui","Osaki","Higashikushira","Kinko","Minamiosumi","Kimotsuki","Nakatane","Minamitane","Yakushima","Setouchi","Tatsugo","Kikai","Tokunoshima","Amagi","Isen","Wadomari","China","Yoron","Motobu","Kin","Kadena","Chatan","Nishihara","Yonabaru","Haebaru","Kumejima","Yaese","Taketomi","Yonaguni"] ]; } From 731eec4686f8ba01be1379c10f9e5222bb193161 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sun, 5 Aug 2018 00:31:45 +0300 Subject: [PATCH 06/25] v. 0.58.05b --- index.html | 6 +++--- script.js | 57 +++++++++++++++++++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/index.html b/index.html index 1a724c9c..40f4a4b5 100644 --- a/index.html +++ b/index.html @@ -31,8 +31,8 @@ - - + + @@ -1109,5 +1109,5 @@ - + diff --git a/script.js b/script.js index 0ccafc83..ab5f68c6 100644 --- a/script.js +++ b/script.js @@ -325,11 +325,11 @@ function fantasyMap() { {name:"Tallian", color:"#a6d854", base:3}, {name:"Toledi", color:"#ffd92f", base:4}, {name:"Slovian", color:"#e5c494", base:5}, - {name:"Norse", color:"#e8c2ed", base:6}, + {name:"Norse", color:"#dca3e4", base:6}, {name:"Elladian", color:"#96d6be", base:7}, {name:"Latian", color:"#ff7174", base:8}, {name:"Somi", color:"#aedff7", base:9}, - {name:"Koryo", color:"#f8baf7", base:10}, + {name:"Koryo", color:"#578880", base:10}, {name:"Hantzu", color:"#fdface", base:11}, {name:"Yamoto", color:"#ffd9da", base:12} ]; @@ -337,20 +337,20 @@ function fantasyMap() { // apply default names data function applyDefaultNamesData() { - nameBases = [ // min; max; mean; common - {name: "German", method: "let-to-syl", min: 4, max: 11, d: "lt"}, // real: 3; 17; 8.6; 8 - {name: "English", method: "let-to-syl", min: 5, max: 10, d: ""}, // real: 4; 13; 7.9; 8 - {name: "French", method: "let-to-syl", min: 4, max: 10, d: "lns"}, // real: 3; 15; 7.6; 6 - {name: "Italian", method: "let-to-syl", min: 4, max: 11, d: "clrt"}, // real: 4; 14; 7.7; 7 - {name: "Castillian", method: "let-to-syl", min: 4, max: 10, d: "lr"}, // real: 2; 13; 7.5; 8 - {name: "Ruthenian", method: "let-to-syl", min: 4, max: 9, d: ""}, // real: 3; 12; 7.1; 7 - {name: "Nordic", method: "let-to-syl", min: 5, max: 9, d: "kln"}, // real: 3; 12; 7.5; 6 - {name: "Greek", method: "let-to-syl", min: 4, max: 10, d: "ls"}, // real: 3; 14; 7.1; 6 - {name: "Roman", method: "let-to-syl", min: 5, max: 10, d: ""}, // real: 3; 15; 8.0; 7 - {name: "Finnic", method: "let-to-syl", min: 3, max: 10, d: "aktu"}, // real: 3; 13; 7.5; 6 - {name: "Korean", method: "let-to-syl", min: 5, max: 10, d: ""}, // real: 3; 13; 6.8; 7 - {name: "Chinese", method: "let-to-syl", min: 5, max: 9, d: ""}, // real: 4; 11; 6.9; 6 - {name: "Japanese", method: "let-to-syl", min: 3, max: 9, d: ""} // real: 2; 15; 6.8; 6 + nameBases = [ // min; max; mean; common + {name: "German", method: "let-to-syl", min: 4, max: 11, d: "lt", m: 0.1}, // real: 3; 17; 8.6; 8 + {name: "English", method: "let-to-syl", min: 5, max: 10, d: "", m: 0.3}, // real: 4; 13; 7.9; 8 + {name: "French", method: "let-to-syl", min: 4, max: 10, d: "lns", m: 0.3}, // real: 3; 15; 7.6; 6 + {name: "Italian", method: "let-to-syl", min: 4, max: 11, d: "clrt", m: 0.2}, // real: 4; 14; 7.7; 7 + {name: "Castillian", method: "let-to-syl", min: 4, max: 10, d: "lr", m: 0}, // real: 2; 13; 7.5; 8 + {name: "Ruthenian", method: "let-to-syl", min: 4, max: 9, d: "", m: 0}, // real: 3; 12; 7.1; 7 + {name: "Nordic", method: "let-to-syl", min: 5, max: 9, d: "kln", m: 0.1}, // real: 3; 12; 7.5; 6 + {name: "Greek", method: "let-to-syl", min: 4, max: 10, d: "ls", m: 0.2}, // real: 3; 14; 7.1; 6 + {name: "Roman", method: "let-to-syl", min: 5, max: 10, d: "", m: 1}, // real: 3; 15; 8.0; 7 + {name: "Finnic", method: "let-to-syl", min: 3, max: 10, d: "aktu", m: 0}, // real: 3; 13; 7.5; 6 + {name: "Korean", method: "let-to-syl", min: 5, max: 10, d: "", m: 0}, // real: 3; 13; 6.8; 7 + {name: "Chinese", method: "let-to-syl", min: 5, max: 9, d: "", m: 0}, // real: 4; 11; 6.9; 6 + {name: "Japanese", method: "let-to-syl", min: 3, max: 9, d: "", m: 0} // real: 2; 15; 6.8; 6 ]; nameBase = [ ["Achern","Aichhalden","Aitern","Albbruck","Alpirsbach","Altensteig","Althengstett","Appenweier","Auggen","Wildbad","Badenen","Badenweiler","Baiersbronn","Ballrechten","Bellingen","Berghaupten","Bernau","Biberach","Biederbach","Binzen","Birkendorf","Birkenfeld","Bischweier","Blumberg","Bollen","Bollschweil","Bonndorf","Bosingen","Braunlingen","Breisach","Breisgau","Breitnau","Brigachtal","Buchenbach","Buggingen","Buhl","Buhlertal","Calw","Dachsberg","Dobel","Donaueschingen","Dornhan","Dornstetten","Dottingen","Dunningen","Durbach","Durrheim","Ebhausen","Ebringen","Efringen","Egenhausen","Ehrenkirchen","Ehrsberg","Eimeldingen","Eisenbach","Elzach","Elztal","Emmendingen","Endingen","Engelsbrand","Enz","Enzklosterle","Eschbronn","Ettenheim","Ettlingen","Feldberg","Fischerbach","Fischingen","Fluorn","Forbach","Freiamt","Freiburg","Freudenstadt","Friedenweiler","Friesenheim","Frohnd","Furtwangen","Gaggenau","Geisingen","Gengenbach","Gernsbach","Glatt","Glatten","Glottertal","Gorwihl","Gottenheim","Grafenhausen","Grenzach","Griesbach","Gutach","Gutenbach","Hag","Haiterbach","Hardt","Harmersbach","Hasel","Haslach","Hausach","Hausen","Hausern","Heitersheim","Herbolzheim","Herrenalb","Herrischried","Hinterzarten","Hochenschwand","Hofen","Hofstetten","Hohberg","Horb","Horben","Hornberg","Hufingen","Ibach","Ihringen","Inzlingen","Kandern","Kappel","Kappelrodeck","Karlsbad","Karlsruhe","Kehl","Keltern","Kippenheim","Kirchzarten","Konigsfeld","Krozingen","Kuppenheim","Kussaberg","Lahr","Lauchringen","Lauf","Laufenburg","Lautenbach","Lauterbach","Lenzkirch","Liebenzell","Loffenau","Loffingen","Lorrach","Lossburg","Mahlberg","Malsburg","Malsch","March","Marxzell","Marzell","Maulburg","Monchweiler","Muhlenbach","Mullheim","Munstertal","Murg","Nagold","Neubulach","Neuenburg","Neuhausen","Neuried","Neuweiler","Niedereschach","Nordrach","Oberharmersbach","Oberkirch","Oberndorf","Oberbach","Oberried","Oberwolfach","Offenburg","Ohlsbach","Oppenau","Ortenberg","otigheim","Ottenhofen","Ottersweier","Peterstal","Pfaffenweiler","Pfalzgrafenweiler","Pforzheim","Rastatt","Renchen","Rheinau","Rheinfelden","Rheinmunster","Rickenbach","Rippoldsau","Rohrdorf","Rottweil","Rummingen","Rust","Sackingen","Sasbach","Sasbachwalden","Schallbach","Schallstadt","Schapbach","Schenkenzell","Schiltach","Schliengen","Schluchsee","Schomberg","Schonach","Schonau","Schonenberg","Schonwald","Schopfheim","Schopfloch","Schramberg","Schuttertal","Schwenningen","Schworstadt","Seebach","Seelbach","Seewald","Sexau","Simmersfeld","Simonswald","Sinzheim","Solden","Staufen","Stegen","Steinach","Steinen","Steinmauern","Straubenhardt","Stuhlingen","Sulz","Sulzburg","Teinach","Tiefenbronn","Tiengen","Titisee","Todtmoos","Todtnau","Todtnauberg","Triberg","Tunau","Tuningen","uhlingen","Unterkirnach","Reichenbach","Utzenfeld","Villingen","Villingendorf","Vogtsburg","Vohrenbach","Waldachtal","Waldbronn","Waldkirch","Waldshut","Wehr","Weil","Weilheim","Weisenbach","Wembach","Wieden","Wiesental","Wildberg","Winzeln","Wittlingen","Wittnau","Wolfach","Wutach","Wutoschingen","Wyhlen","Zavelstein"], @@ -3942,19 +3942,19 @@ function fantasyMap() { if (base === undefined) base = cultures[culture].base; const method = nameBases[base].method; const error = function(base) { - const er = "Names data for base " + nameBases[base].name + " is incorrect. Please fix in Namesbase Editor"; - tip(er); + tip("Names data for base " + nameBases[base].name + " is incorrect. Please fix in Namesbase Editor"); editNamesbase(); } if (method === "selection") { + if (nameBase[base].length < 1) {error; return;} const rnd = rand(nameBase[base].length - 1); const name = nameBase[base][rnd]; - if (name === undefined) {error; return;} return name; } const data = chain[base]; + if (data[" "] === undefined) {error; return;} const max = nameBases[base].max; const min = nameBases[base].min; const d = nameBases[base].d; @@ -3981,6 +3981,23 @@ function fantasyMap() { // very rare case, let's just select a random name if (word.length < 2) word = nameBase[base][rand(nameBase[base].length - 1)]; + // do not allow multi-word name if word is foo short or not allowed for culture + if (word.includes(" ")) { + let words = word.split(" "), parsed; + if (Math.random() > nameBases[base].m) {word = words.join("");} + else { + for (let i=0; i < words.length; i++) { + if (words[i].length < 2) { + if (!i) words[1] = words[0] + words[1]; + if (i) words[i-1] = words[i-1] + words[i]; + words.splice(i, 1); + i--; + } + } + word = words.join(" "); + } + } + // parse word to get a final name const name = [...word].reduce(function(r, c, i, data) { if (c === " ") { @@ -8156,7 +8173,7 @@ function fantasyMap() { const select = document.getElementById("namesbaseSelect"); select.options.add(new Option(name, base)); select.value = base; - nameBases.push({name, method, min: 4, max: 10, d: ""}); + nameBases.push({name, method, min: 4, max: 10, d: "", m: 1}); nameBase.push([]); document.getElementById("namesbaseName").value = name; const textarea = document.getElementById("namesbaseTextarea"); From b89add69f9f165aa125eb026356c2b93d203bb56 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sun, 5 Aug 2018 13:21:17 +0300 Subject: [PATCH 07/25] v. 0.58.06b --- index.html | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/index.html b/index.html index 40f4a4b5..f4e14421 100644 --- a/index.html +++ b/index.html @@ -10,6 +10,35 @@ gtag('js', new Date()); gtag('config', 'UA-116735150-1'); + + + + Azgaar's Fantasy Map Generator From 4f9ee7e597afb294a41f7966edece8fea38eab21 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sun, 5 Aug 2018 23:15:06 +0300 Subject: [PATCH 08/25] v. 0.58.07b --- index.html | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/index.html b/index.html index f4e14421..40f4a4b5 100644 --- a/index.html +++ b/index.html @@ -10,35 +10,6 @@ gtag('js', new Date()); gtag('config', 'UA-116735150-1'); - - - - Azgaar's Fantasy Map Generator From e4e4cdfb07c9ef1fec73e0c93152b2e68b0e4220 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Mon, 6 Aug 2018 00:03:48 +0300 Subject: [PATCH 09/25] v. 0.58.08b --- index.css | 2 +- script.js | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/index.css b/index.css index a83b9dc0..62c496ca 100644 --- a/index.css +++ b/index.css @@ -47,7 +47,7 @@ button, select, a { } #cults { - stroke-width: 0.7; + stroke-width: 2; mask: url(#shape); mask-mode: alpha; pointer-events: none; diff --git a/script.js b/script.js index ab5f68c6..7941b10a 100644 --- a/script.js +++ b/script.js @@ -4183,7 +4183,7 @@ function fantasyMap() { path += lineGen(edgesOrdered); } var color = states[region].color; - regions.append("path").attr("d", round(path, 1)).attr("fill", "none").attr("stroke", color).attr("stroke-width", 1.5).attr("class", "region"+region); + regions.append("path").attr("d", round(path, 1)).attr("fill", "none").attr("stroke", color).attr("stroke-width", 3).attr("class", "region"+region); } function drawBorders(edges, type) { @@ -7161,6 +7161,7 @@ function fantasyMap() { function undraw() { viewbox.selectAll("path, circle, line, text, use, #ruler > g").remove(); svg.select("#shape").remove(); + landmass.select("rect").remove(); cells = [], land = [], riversData = [], manors = [], states = [], features = [], queue = []; } @@ -8507,9 +8508,9 @@ function fantasyMap() { viewbox.on("touchmove mousemove", moved); landmass.attr("opacity", 1).attr("fill", "#eef6fb"); coastline.attr("opacity", .5).attr("stroke", "#1f3846").attr("stroke-width", .7).attr("filter", "url(#dropShadow)"); - regions.attr("opacity", .6).attr("filter", "url(#splotch)"); - stateBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", .5).attr("stroke-dasharray", "1.2 1.5").attr("stroke-linecap", "butt"); - neutralBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", .3).attr("stroke-dasharray", "1 1.5").attr("stroke-linecap", "butt"); + regions.attr("opacity", .4); + stateBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", .7).attr("stroke-dasharray", "1.2 1.5").attr("stroke-linecap", "butt"); + neutralBorders.attr("opacity", .8).attr("stroke", "#56566d").attr("stroke-width", .5).attr("stroke-dasharray", "1 1.5").attr("stroke-linecap", "butt"); cults.attr("opacity", .6); rivers.attr("opacity", 1).attr("fill", "#5d97bb"); lakes.attr("opacity", .5).attr("fill", "#a6c1fd").attr("stroke", "#5f799d").attr("stroke-width", .7); From 6d83ee8bafd68d71155f1ab9e9df177dfd566cc9 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Mon, 6 Aug 2018 22:33:35 +0300 Subject: [PATCH 10/25] v. 0.59.09b --- index.css | 1 + 1 file changed, 1 insertion(+) diff --git a/index.css b/index.css index 62c496ca..d5f470ea 100644 --- a/index.css +++ b/index.css @@ -60,6 +60,7 @@ button, select, a { #landmass { mask: url(#shape); + mask-clip: no-clip; } #lakes, From dc6015c4061a2bcfcf66767f0c184407cb2edf30 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Wed, 8 Aug 2018 22:42:06 +0300 Subject: [PATCH 11/25] v. 0.58.10b --- index.css | 6 +- script.js | 334 +++++++++++++++++++++++++++++++----------------------- 2 files changed, 198 insertions(+), 142 deletions(-) diff --git a/index.css b/index.css index d5f470ea..15891f96 100644 --- a/index.css +++ b/index.css @@ -258,13 +258,17 @@ input[type="number"].editNumber { } .line { - stroke: #666666; + stroke: #373737; stroke-width: 1px; + stroke-dasharray: 6; + stroke-linecap: butt; } .circle { stroke-width: 1px; fill: none; + stroke-dasharray: 6; + stroke-linecap: butt; } circle.drag { diff --git a/script.js b/script.js index 7941b10a..c311b2d8 100644 --- a/script.js +++ b/script.js @@ -222,8 +222,8 @@ function fantasyMap() { resolveDepressionsSecondary(); flux(); addLakes(); - drawRelief(); drawCoastline(); + drawRelief(); generateCultures(); manorsAndRegions(); cleanData(); @@ -416,8 +416,8 @@ function fantasyMap() { // Get cell info on mouse move (useful for debugging) function moved() { - var point = d3.mouse(this); - var i = diagram.find(point[0], point[1]).index; + const point = d3.mouse(this); + const i = diagram.find(point[0], point[1]).index; // update cellInfo if (i) { @@ -435,9 +435,10 @@ function fantasyMap() { infoPopulation.innerHTML = ifDefined(p.pop, "n/a", 2); infoBurg.innerHTML = ifDefined(p.manor) !== "no" ? manors[p.manor].name + " (" + p.manor + ")" : "no"; const feature = features[p.fn]; - if (feature === undefined) return; - const fType = feature.land ? "Island" : feature.border ? "Ocean" : "Lake"; - infoFeature.innerHTML = fType + " (" + p.fn + ")"; + if (feature !== undefined) { + const fType = feature.land ? "Island" : feature.border ? "Ocean" : "Lake"; + infoFeature.innerHTML = fType + " (" + p.fn + ")"; + } } // update tooltip @@ -454,37 +455,48 @@ function fantasyMap() { if (subgroup === "burgLabels") tip("Click to open Burg Editor"); } - // draw line for Customization range placing - icons.selectAll(".line").remove(); + // draw line for ranges placing for heightmap Customization if (customization === 1) { - if (icons.selectAll(".tag").size() === 1) { - const x = +icons.select(".tag").attr("cx"); - const y = +icons.select(".tag").attr("cy"); - icons.insert("line", ":first-child").attr("class", "line") - .attr("x1", x).attr("y1", y).attr("x2", point[0]).attr("y2", point[1]); + const line = debug.selectAll(".line"); + if (debug.selectAll(".tag").size() === 1) { + const x = +debug.select(".tag").attr("cx"); + const y = +debug.select(".tag").attr("cy"); + if (line.size()) {line.attr("x1", x).attr("y1", y).attr("x2", point[0]).attr("y2", point[1]);} + else {debug.insert("line", ":first-child").attr("class", "line") + .attr("x1", x).attr("y1", y).attr("x2", point[0]).attr("y2", point[1]);} + } else { + line.remove(); } } + // change radius circle for Customization if (customization > 0) { const brush = $("#brushesButtons > .pressed"); - if ((!brush.length || brush.hasClass("feature")) && !$("div.selected").length) { - icons.selectAll(".circle").remove(); - return; + const brushId = brush.attr("id"); + if (brushId === "brushRange" || brushId === "brushTrough") return; + if (!brush.length && !$("div.selected").length) return; + let radius = 0; + if (customization === 1) { + radius = brushRadius.value; + if (brushId === "brushHill" || brushId === "brushPit") { + radius = Math.pow(brushPower.value * 400, .5); + } } - const radius = customization === 1 ? brushRadius.value : customization === 2 - ? countriesManuallyBrush.value : culturesManuallyBrush.value; + else if (customization === 2) radius = countriesManuallyBrush.value; + else if (customization === 4) radius = culturesManuallyBrush.value; + const r = rn(6 / graphSize * radius, 1); - let clr = "#666666;" + let clr = "#373737"; if (customization === 2) { const state = +$("div.selected").attr("id").slice(5); - clr = states[state].color === "neutral" ? "white" :states[state].color; + clr = states[state].color === "neutral" ? "white" : states[state].color; } if (customization === 4) { const culture = +$("div.selected").attr("id").slice(7); clr = cultures[culture].color; } moveCircle(point[0], point[1], r, clr); - } else {icons.selectAll(".circle").remove();} + } } // return value (v) if defined with specified number of decimals (d) @@ -497,8 +509,8 @@ function fantasyMap() { // move brush radius circle function moveCircle(x, y, r, c) { - let circle = icons.selectAll(".circle"); - if (!circle.size()) circle = icons.insert("circle", ":first-child").attr("class", "circle"); + let circle = debug.selectAll(".circle"); + if (!circle.size()) circle = debug.insert("circle", ":first-child").attr("class", "circle"); circle.attr("cx", x).attr("cy", y); if (r) circle.attr("r", r); if (c) circle.attr("stroke", c); @@ -541,11 +553,9 @@ function fantasyMap() { const power = +brushPower.value; if (id === "brushHill") {add(c2, "hill", power); updateHeightmap();} if (id === "brushPit") {addPit(1, power, c2); updateHeightmap();} - if (!brush.hasClass("feature")) { + if (id !== "brushRange" || id !== "brushTrough") { // move a circle to show approximate change radius - const radius = +brushRadius.value; - const r = rn(6 / graphSize * radius, 1); - moveCircle(x1, y1, r); + moveCircle(x1, y1); updateCellsInRadius(c2, c0); } } @@ -737,13 +747,13 @@ function fantasyMap() { function placeLinearFeature() { const point = d3.mouse(this); const index = getIndex(point); - let tag = icons.selectAll(".tag"); - if (tag.size() === 0) { - tag = icons.append("circle").attr("data-cell", index).attr("class", "tag") + let tag = debug.selectAll(".tag"); + if (!tag.size()) { + tag = debug.append("circle").attr("data-cell", index).attr("class", "tag") .attr("r", 3).attr("cx", point[0]).attr("cy", point[1]); } else { const from = +tag.attr("data-cell"); - icons.selectAll(".tag, .line").remove(); + debug.selectAll(".tag, .line").remove(); const power = +brushPower.value; const mod = $("#brushesButtons > .pressed").attr("id") === "brushRange" ? 1 : -1; const selection = addRange(mod, power, from, index); @@ -1228,13 +1238,19 @@ function fantasyMap() { const avPrec = precInput.value / 5000; const evaporation = 2; cells.map(function(i) { - const height = Math.trunc(i.height * 100) / 100; + let height = Math.trunc(i.height * 100) / 100; const ctype = i.ctype; - if (ctype !== -1 && ctype !== -2 && height < 0.2) return; + if (ctype !== -1 && ctype !== -2 && height < 0.2) return; // exclude all depp ocean points const x = rn(i.data[0], 1), y = rn(i.data[1], 1); const fn = i.fn; const harbor = i.harbor; - const lake = i.lake ? 1 : i.pit > evaporation ? 2 : undefined; + let lake = i.lake; + if (!lake && i.pit > evaporation && ctype !== 2) { + lake = 2; + height = Math.trunc(height * 100 - i.pit) / 100; + } + if (height > 1) height = 1; + if (height < 0) height = 0; const region = i.region; // handle value for edit heightmap mode only const culture = i.culture; // handle value for edit heightmap mode only let copy = $.grep(newPoints, function(e) {return (e[0] == x && e[1] == y);}); @@ -1245,6 +1261,7 @@ function fantasyMap() { // add additional points for cells along coast if (ctype === 2 || ctype === -1) { if (i.type === "border") return; + if (!features[fn].land && !features[fn].border) return; i.neighbors.forEach(function(e) { if (cells[e].ctype === ctype) { let x1 = (x * 2 + cells[e].data[0]) / 3; @@ -1257,14 +1274,14 @@ function fantasyMap() { }; }); } - if (lake === 2) { // small lake - //debug.append("circle").attr("r", 0.6).attr("cx", x).attr("cy", y).attr("fill", "blue"); - if (i.height >= 0.3) i.height -= 0.1; + if (lake === 2) { // add potential small lakes + //debug.append("circle").attr("r", 0.3).attr("cx", x).attr("cy", y).attr("fill", "blue"); + height = Math.trunc(height * 100 + 1) / 100; polygons[i.index].forEach(function(e) { - if (Math.random() > 0.9) return; - let rnd = Math.random() * 1.2 + 0.2; + if (Math.random() > 0.8) return; + let rnd = Math.random() * 0.6 + 0.8; const x1 = rn((e[0] * rnd + i.data[0]) / (1 + rnd), 2); - rnd = Math.random() * 1.2 + 0.2; + rnd = Math.random() * 0.6 + 0.8; const y1 = rn((e[1] * rnd + i.data[1]) / (1 + rnd), 2); copy = $.grep(newPoints, function(c) {return x1 === c[0] && y1 === c[1];}); if (copy.length) return; @@ -1282,7 +1299,7 @@ function fantasyMap() { // calc cell area i.area = rn(Math.abs(d3.polygonArea(polygons[d])), 2); const prec = rn(avPrec * i.area, 2); - i.flux = i.lake ? prec * 3 : prec; + i.flux = i.lake ? prec * 10 : prec; } const neighbors = []; // re-detect neighbors diagram.cells[d].halfedges.forEach(function(e) { @@ -1296,22 +1313,8 @@ function fantasyMap() { if (d < ea && i.height >= 0.2 && i.lake !== 1 && cells[ea].height >= 0.2 && cells[ea].lake !== 1) { gridPath += "M" + edge[0][0] + "," + edge[0][1] + "L" + edge[1][0] + "," + edge[1][1]; } - if (i.height >= 0.2 && !i.lake && (cells[ea].height < 0.2 || cells[ea].lake)) { - if (i.ctype === 1) return; // already defined coastal point - i.ctype = 1; // mark coastal land cells - // move cell point closer to coast - const x = (i.data[0] + cells[ea].data[0]) / 2; - const y = (i.data[1] + cells[ea].data[1]) / 2; - i.haven = ea; // harbor haven (oposite water cell) - i.coastX = x, i.coastY = y; - i.data[0] = rn(x + (i.data[0] - x) * 0.5, 1); - i.data[1] = rn(y + (i.data[1] - y) * 0.5, 1); - //debug.append("circle").attr("cx", x).attr("cy", y).attr("r", 0.2).attr("fill", "red"); - //debug.append("circle").attr("cx", i.data[0]).attr("cy", i.data[1]).attr("r", 0.2).attr("fill", "blue"); - } }); i.neighbors = neighbors; - if (i.haven === undefined) delete i.harbor; if (i.region === undefined) delete i.region; if (i.culture === undefined) delete i.culture; }); @@ -1340,8 +1343,8 @@ function fantasyMap() { function updateHeightmap() { cells.map(function(c) { let height = c.height; - if (height > 1) {height = 1;} - if (height < 0) {height = 0;} + if (height > 1) height = 1; + if (height < 0) height = 0; c.height = height; let cell = landmass.select("#cell"+c.index); const clr = color(1 - height); @@ -1421,53 +1424,78 @@ function fantasyMap() { // Detect and draw the coasline function drawCoastline() { console.time('drawCoastline'); - const shape = defs.append("mask").attr("id", "shape").attr("fill", "black") - .attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%"); + const shape = defs.append("mask").attr("id", "shape").attr("fill", "black").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%"); $("#landmass").empty(); let minX = graphWidth, maxX = 0; // extreme points let minXedge, maxXedge; // extreme edges - for (let f = 0; f < features.length; f++) { - if (!features[f].land) continue; - const coastal = $.grep(land, function(e) {return ((e.ctype === 1 || e.ctype === 99) && e.fn === f);}); - let oceanEdges = [], lakeEdges = []; - for (let i = 0; i < coastal.length; i++) { - const id = coastal[i].index, cell = diagram.cells[id]; - cell.halfedges.forEach(function(e) { - const edge = diagram.edges[e]; - const start = edge[0].join(" "); - const end = edge[1].join(" "); - if (edge.left && edge.right) { - const ea = edge.left.index === id ? edge.right.index : edge.left.index; - if (cells[ea].height < 0.2) { - if (features[cells[ea].fn].border) { - oceanEdges.push({start, end}); - // island extreme points - if (edge[0][0] < minX) {minX = edge[0][0]; minXedge = edge[0]} - if (edge[1][0] < minX) {minX = edge[1][0]; minXedge = edge[1]} - if (edge[0][0] > maxX) {maxX = edge[0][0]; maxXedge = edge[0]} - if (edge[1][0] > maxX) {maxX = edge[1][0]; maxXedge = edge[1]} - } else { - lakeEdges.push({start, end}); - } + const oceanEdges = [], lakeEdges = []; + for (let i=0; i < land.length; i++) { + const id = land[i].index, cell = diagram.cells[id]; + const f = land[i].fn; + land[i].height = Math.trunc(land[i].height * 100) / 100; + if (!oceanEdges[f]) {oceanEdges[f] = []; lakeEdges[f] = [];} + cell.halfedges.forEach(function(e) { + const edge = diagram.edges[e]; + const start = edge[0].join(" "); + const end = edge[1].join(" "); + if (edge.left && edge.right) { + const ea = edge.left.index === id ? edge.right.index : edge.left.index; + cells[ea].height = Math.trunc(cells[ea].height * 100) / 100; + if (cells[ea].height < 0.2) { + cells[ea].ctype = -1; + if (land[i].ctype !== 1) { + land[i].ctype = 1; // mark coastal land cells + // move cell point closer to coast + const x = (land[i].data[0] + cells[ea].data[0]) / 2; + const y = (land[i].data[1] + cells[ea].data[1]) / 2; + land[i].haven = ea; // harbor haven (oposite water cell) + land[i].coastX = x, land[i].coastY = y; + land[i].data[0] = rn(x + (land[i].data[0] - x) * 0.5, 1); + land[i].data[1] = rn(y + (land[i].data[1] - y) * 0.5, 1); } - } else { - oceanEdges.push({start, end}); - } - }) - } - if (coastal.length && lakeEdges.length && oceanEdges.length < 3) { - console.error("Feature " + f + " is an on-lake island. This can cause defects!"); - oceanEdges = lakeEdges; - lakeEdges = []; + if (features[cells[ea].fn].border) { + //debug.append("line").attr("x1", edge[0][0]).attr("y1", edge[0][1]).attr("x2", edge[1][0]).attr("y2", edge[1][1]).attr("stroke", "blue").attr("stroke-width", .2); + oceanEdges[f].push({start, end}); + // island extreme points + if (edge[0][0] < minX) {minX = edge[0][0]; minXedge = edge[0]} + if (edge[1][0] < minX) {minX = edge[1][0]; minXedge = edge[1]} + if (edge[0][0] > maxX) {maxX = edge[0][0]; maxXedge = edge[0]} + if (edge[1][0] > maxX) {maxX = edge[1][0]; maxXedge = edge[1]} + } else { + const l = cells[ea].fn; + if (!lakeEdges[f][l]) lakeEdges[f][l] = []; + lakeEdges[f][l].push({start, end}); + //debug.append("line").attr("x1", edge[0][0]).attr("y1", edge[0][1]).attr("x2", edge[1][0]).attr("y2", edge[1][1]).attr("stroke", "red").attr("stroke-width", .2); + } + } + } else { + oceanEdges[f].push({start, end}); + //debug.append("line").attr("x1", edge[0][0]).attr("y1", edge[0][1]).attr("x2", edge[1][0]).attr("y2", edge[1][1]).attr("stroke", "black").attr("stroke-width", .5); + } + }); + } + + for (let f = 0; f < features.length; f++) { + if (!oceanEdges[f]) continue; + if (!oceanEdges[f].length && lakeEdges[f].length) { + const m = lakeEdges[f].indexOf(d3.max(lakeEdges[f])); + oceanEdges[f] = lakeEdges[f][m]; + lakeEdges[f][m] = []; } lineGen.curve(d3.curveCatmullRomClosed.alpha(0.1)); - const oceanCoastline = getContinuousLine(oceanEdges, 3, 0); + const oceanCoastline = getContinuousLine(oceanEdges[f], 3, 0); + if (oceanCoastline) { + shape.append("path").attr("d", oceanCoastline).attr("fill", "white"); // draw the mask + coastline.append("path").attr("d", oceanCoastline); // draw the coastline + } lineGen.curve(d3.curveBasisClosed); - const lakeCoastline = getContinuousLine(lakeEdges, 1.5, 0); - shape.append("path").attr("d", oceanCoastline).attr("fill", "white"); - if (lakeCoastline) shape.append("path").attr("d", lakeCoastline).attr("fill", "black"); - coastline.append("path").attr("d", oceanCoastline); // draw the coastline - if (lakeCoastline) lakes.append("path").attr("d", lakeCoastline); // draw the lakes + lakeEdges[f].forEach(function(l) { + const lakeCoastline = getContinuousLine(l, 3, 0); + if (lakeCoastline) { + shape.append("path").attr("d", lakeCoastline).attr("fill", "black"); // draw the mask + lakes.append("path").attr("d", lakeCoastline); // draw the lakes + } + }); } landmass.append("rect").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight); // draw the landmass drawDefaultRuler(minXedge, maxXedge); @@ -1731,9 +1759,9 @@ function fantasyMap() { for (let i=0; i < lakes.length; i++) { const heights = []; lakes[i].neighbors.forEach(function(n) {if (cells[n].height >= 0.2) heights.push(cells[n].height)}); - if (heights.length) lakes[i].height = d3.min(heights) - 0.01; + if (heights.length) lakes[i].height = Math.trunc((d3.min(heights) - 0.01) * 100) / 100; if (cells[i].height < 0.2) lakes[i].height = 0.2; - lakes[i].lake = true; + lakes[i].lake = 1; } console.timeEnd('elevateLakes'); } @@ -1753,7 +1781,7 @@ function fantasyMap() { if (land[i].height <= minHigh) { depression++; land[i].pit = land[i].pit ? land[i].pit + 1 : 1; - land[i].height = minHigh + 0.02; + land[i].height = Math.trunc((minHigh + 0.02) * 100) / 100; } } if (l === 0) console.log(" depressions init: " + depression); @@ -1776,7 +1804,7 @@ function fantasyMap() { if (land[i].height <= minHigh) { depression++; land[i].pit = land[i].pit ? land[i].pit + 1 : 1; - land[i].height = minHigh + 0.02; + land[i].height = Math.trunc((minHigh + 0.02) * 100) / 100; } } if (l === 0) console.log(" depressions reGraphed: " + depression); @@ -2039,43 +2067,61 @@ function fantasyMap() { // add lakes on depressed points on river course function addLakes() { + console.time('addLakes'); for (let i=0; i < land.length; i++) { + // elavate all big lakes if (land[i].lake === 1) { land[i].height = 0.19; land[i].ctype = -1; - land[i].neighbors.forEach(function(e) {if (cells[e].height >= 0.2) cells[e].ctype = 1;}); } + // define eligible small lakes if (land[i].lake === 2) { if (land[i].river !== undefined) { - addLakeAtCell(land[i].index); + land[i].height = 0.19; + land[i].ctype = -1; + land[i].fn = -1; } else { - delete land[i].lake; + land[i].lake = undefined; land[i].neighbors.forEach(function(n) { - if (cells[n].river !== undefined) { - addLakeAtCell(n); - return; + if (cells[n].lake !== 1 && cells[n].river !== undefined) { + cells[n].lake = 2; + cells[n].height = 0.19; + cells[n].ctype = -1; + cells[n].fn = -1; + } else if (cells[n].lake === 2) { + cells[n].lake = undefined; } }); } } } - function addLakeAtCell(i) { - cells[i].lake = 2; - cells[i].height = 0.19; - cells[i].ctype = -1; - let fn = features.length; - cells[i].neighbors.forEach(function(e) { - if (cells[e].height >= 0.2) cells[e].ctype = 1; - // change fn to neighboring lake - if (cells[e].lake === 2 && cells[e].river !== undefined) fn = cells[e].fn; - else if (cells[e].lake === 1) fn = cells[e].fn; - }); - cells[i].fn = fn; - if (fn === features.length) features.push({i: fn, land: false, border: false}); + // mark small lakes + let unmarked = $.grep(land, function(e) {return e.fn === -1}); + while (unmarked.length) { + let fn = -1, queue = [unmarked[0].index], lakeCells = []; + unmarked[0].session = "addLakes"; + while (queue.length) { + const q = queue.pop(); + lakeCells.push(q); + if (cells[q].fn !== -1) fn = cells[q].fn; + cells[q].neighbors.forEach(function(e) { + if (cells[e].lake && cells[e].session !== "addLakes") { + cells[e].session = "addLakes"; + queue.push(e); + } + }); + } + if (fn === -1) { + fn = features.length; + features.push({i: fn, land: false, border: false}); + } + lakeCells.forEach(function(c) {cells[c].fn = fn;}); + unmarked = $.grep(land, function(e) {return e.fn === -1}); } land = $.grep(cells, function(e) {return e.height >= 0.2;}); + console.timeEnd('addLakes'); } function editRiver() { @@ -3276,8 +3322,8 @@ function fantasyMap() { console.time('rankPlacesGeography'); land.map(function(c) { let score = 0; - // truncate decimals to keep dta clear - c.height = rn(c.height, 2); + // truncate decimals to keep data clear + c.height = Math.trunc(c.height * 100) / 100; c.flux = rn(c.flux, 2); // get base score from height (will be biom) if (c.height <= 0.4) score = 2; @@ -3481,9 +3527,13 @@ function fantasyMap() { let x = manors[i].x, y = manors[i].y; if ((capital && cell.harbor) || cell.harbor === 1) { // port: capital with any harbor and towns with good harbors - cell.port = cells[cell.haven].fn; - x = cell.coastX; - y = cell.coastY; + if (cell.haven === undefined) { + cell.harbor = undefined; + } else { + cell.port = cells[cell.haven].fn; + x = cell.coastX; + y = cell.coastY; + } } if (cell.river) { let shift = 0.2 * cell.flux; @@ -4366,8 +4416,8 @@ function fantasyMap() { if (height < 0.2 && i.lake !== 2) return; if (i.lake === 2) { const heights = i.neighbors.map(function(e) {if (cells[e].height >= 0.2) return cells[e].height;}) - height = d3.mean(heights); - if (height < 0.2 || height === undefined) height = 0.2; + height = Math.trunc(d3.mean(heights) * 100) / 100; + if (height < 0.2 || isNaN(height)) height = 0.2; } const clr = hColor(1 - height); terrs.append("path") @@ -4433,8 +4483,9 @@ function fantasyMap() { delete c.used; delete c.coastX; delete c.coastY; - if (c.ctype === undefined) {delete c.ctype;} - c.height = rn(c.height, 2); + if (c.ctype === undefined) delete c.ctype; + if (c.lake === undefined) delete c.lake; + c.height = Math.trunc(c.height * 100) / 100; if (c.height >= 0.2) c.flux = rn(c.flux, 2); }); // restore layers if they was turned on @@ -4667,8 +4718,8 @@ function fantasyMap() { flux(); addLakes(); if (!changeHeights.checked) restoreCustomHeights(); - drawRelief(); drawCoastline(); + drawRelief(); if (!keepData) { generateCultures(); manorsAndRegions(); @@ -5014,7 +5065,7 @@ function fantasyMap() { $("#culture"+c).addClass("selected"); } - icons.selectAll(".circle").attr("stroke", color); + debug.selectAll(".circle").attr("stroke", color); } // fetch default fonts if not done before @@ -6004,7 +6055,7 @@ function fantasyMap() { $("button, a, li, i").on("click", function() { var id = this.id; var parent = this.parentNode.id; - if (icons.selectAll(".tag").size() > 0) {icons.selectAll(".tag, .line").remove();} + if (debug.selectAll(".tag").size()) {debug.selectAll(".tag, .line").remove();} if (id === "toggleHeight") {toggleHeight();} if (id === "toggleCountries") {$('#regions').fadeToggle();} if (id === "toggleCultures") {toggleCultures();} @@ -6051,7 +6102,7 @@ function fantasyMap() { $("div[data-sortby='expansion'], div[data-sortby='cells']").toggleClass("hidden"); } if (id === "countriesManuallyComplete") { - icons.selectAll(".circle").remove(); + debug.selectAll(".circle").remove(); var changedCells = regions.select("#temp").selectAll("path"); var changedStates = []; changedCells.each(function() { @@ -6077,7 +6128,7 @@ function fantasyMap() { } if (id === "countriesManuallyCancel") { redrawRegions(); - icons.selectAll(".circle").remove(); + debug.selectAll(".circle").remove(); if (grid.style("display") === "inline") {toggleGrid.click();} if (labels.style("display") === "none") {toggleLabels.click();} $("#countriesBottom").children().show(); @@ -6640,17 +6691,18 @@ function fantasyMap() { $("#brushesButtons > button").on("click", function() { const rSlider = $("#brushRadiusLabel, #brushRadius"); + debug.selectAll(".circle, .tag, .line").remove(); if ($(this).hasClass('pressed')) { $(this).removeClass('pressed'); restoreDefaultEvents(); - icons.selectAll(".circle").remove(); rSlider.attr("disabled", true).addClass("disabled"); } else { $("#brushesButtons > .pressed").removeClass('pressed'); $(this).addClass('pressed'); viewbox.style("cursor", "crosshair"); - if (this.id !== "brushRange" && this.id !== "brushTrough") {viewbox.call(drag);} // on drag brushes - else {viewbox.on("click", placeLinearFeature);} // on click brushes + const id = this.id; + if (id === "brushRange" || id === "brushTrough") {viewbox.on("click", placeLinearFeature);} // on click brushes + else {viewbox.call(drag).on("click", null);} // on drag brushes if ($(this).hasClass("feature")) {rSlider.attr("disabled", true).addClass("disabled");} else {rSlider.attr("disabled", false).removeClass("disabled");} } @@ -7196,7 +7248,7 @@ function fantasyMap() { $("#customizeHeightmap").slideUp(); $("#openEditor").slideDown(); $("#getMap").removeClass("glow"); - icons.selectAll(".circle").remove(); + debug.selectAll(".circle, .tag, .line").remove(); } // open editCountries dialog @@ -7336,7 +7388,7 @@ function fantasyMap() { const state = +$(this).attr("id").slice(5); let color = states[state].color; if (color === "neutral") {color = "white";} - if (icons.selectAll(".circle").size()) {icons.selectAll(".circle").attr("stroke", color);} + if (debug.selectAll(".circle").size()) debug.selectAll(".circle").attr("stroke", color); } }); @@ -7796,7 +7848,7 @@ function fantasyMap() { $(".selected").removeClass("selected"); $(this).addClass("selected"); let color = cultures[c].color; - icons.selectAll(".circle").attr("stroke", color); + debug.selectAll(".circle").attr("stroke", color); }); $(".cultures .stateColor").on("input", function() { @@ -7937,7 +7989,7 @@ function fantasyMap() { }); function exitCulturesManualAssignment() { - icons.selectAll(".circle").remove(); + debug.selectAll(".circle").remove(); $("#culturesBottom").children().show(); $("#culturesManuallyButtons").hide(); $(".selected").removeClass("selected"); From 53c961982fd66f834b8c619a266a73feff4400c3 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Wed, 8 Aug 2018 22:43:11 +0300 Subject: [PATCH 12/25] v. 0.58.11b --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 40f4a4b5..c439e58b 100644 --- a/index.html +++ b/index.html @@ -31,8 +31,8 @@ - - + + @@ -1109,5 +1109,5 @@ - + From bc3b421959738122a22fafd5a01cd16c98cf46ad Mon Sep 17 00:00:00 2001 From: Azgaar Date: Fri, 10 Aug 2018 00:14:44 +0300 Subject: [PATCH 13/25] v. 0.58.12b --- index.html | 6 +++--- script.js | 51 +++++++++++++++++++++++++++++---------------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/index.html b/index.html index c439e58b..f75dc532 100644 --- a/index.html +++ b/index.html @@ -31,8 +31,8 @@ - - + + @@ -1109,5 +1109,5 @@ - + diff --git a/script.js b/script.js index c311b2d8..38445e7c 100644 --- a/script.js +++ b/script.js @@ -502,7 +502,7 @@ function fantasyMap() { // return value (v) if defined with specified number of decimals (d) // else return "no" or attribute (r) function ifDefined(v, r, d) { - if (v === undefined) return r || "no"; + if (v === null || v === undefined) return r || "no"; if (d) return v.toFixed(d); return v; } @@ -3990,6 +3990,13 @@ function fantasyMap() { // generate random name using Markov's chain function generateName(culture, base) { if (base === undefined) base = cultures[culture].base; + if (!nameBases[base]) { + console.error("nameBase " + base + "is not defined. Will load default names data and first base"); + localStorage.removeItem("nameBase"); + localStorage.removeItem("nameBases"); + applyDefaultNamesData(); + base = 0; + } const method = nameBases[base].method; const error = function(base) { tip("Names data for base " + nameBases[base].name + " is incorrect. Please fix in Namesbase Editor"); @@ -3997,14 +4004,14 @@ function fantasyMap() { } if (method === "selection") { - if (nameBase[base].length < 1) {error; return;} + if (nameBase[base].length < 1) {error(base); return;} const rnd = rand(nameBase[base].length - 1); const name = nameBase[base][rnd]; return name; } const data = chain[base]; - if (data[" "] === undefined) {error; return;} + if (data === undefined || data[" "] === undefined) {error(base); return;} const max = nameBases[base].max; const min = nameBases[base].min; const d = nameBases[base].d; @@ -5570,7 +5577,7 @@ function fantasyMap() { viewbox.attr("transform", null); const oceanBack = ocean.select("rect"); const oceanShift = [oceanBack.attr("x"), oceanBack.attr("y"), oceanBack.attr("width"), oceanBack.attr("height")]; - oceanBack.attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%"); + oceanBack.attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight); var svg_xml = (new XMLSerializer()).serializeToString(svg.node()); var line = "\r\n"; @@ -5676,18 +5683,15 @@ function fantasyMap() { voronoi = d3.voronoi().extent([[-1, -1], [graphWidth+1, graphHeight+1]]); zoom.translateExtent([[0, 0], [graphWidth, graphHeight]]).scaleExtent([1, 20]).scaleTo(svg, 1); viewbox.attr("transform", null); - ocean.selectAll("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%"); // temporary fit loaded svg element to current canvas size svg.attr("width", svgWidth).attr("height", svgHeight); if (nWidth !== svgWidth || nHeight !== svgHeight) { - alertMessage.innerHTML = `The loaded map has size ${nWidth} x ${nHeight} pixels, - while the current canvas size is ${svgWidth} x ${svgHeight} pixels. - You may either fit the loaded map to the current canvas - or resize the current canvas to ${nWidth} x ${nHeight} pixels`; + alertMessage.innerHTML = `The loaded map has size ${nWidth} x ${nHeight} pixels, while the current canvas size is ${svgWidth} x ${svgHeight} pixels. + Click "Rescale" to fit the map to the current canvas size. Click "OK" to browse the map without rescaling`; $("#alert").dialog({title: "Map size conflict", buttons: { - Fit: function() { + Rescale: function() { applyLoadedData(data); // rescale loaded map const xRatio = svgWidth / nWidth; @@ -5701,9 +5705,7 @@ function fantasyMap() { zoom.translateExtent([[0, 0], [nWidth, nHeight]]).scaleExtent([scaleTo, 20]).scaleTo(svg, scaleTo); $(this).dialog("close"); }, - Resize: function() { - mapWidthInput.value = nWidth; - mapHeightInput.value = nHeight; + OK: function() { changeMapSize(); applyLoadedData(data); $(this).dialog("close"); @@ -5745,17 +5747,20 @@ function fantasyMap() { debug = viewbox.select("#debug"); // version control: ensure required groups are created with correct data - if (labels.select("#burgLabels").size() === 0) { + if (!labels.select("#burgLabels").size()) { labels.append("g").attr("id", "burgLabels"); - icons.append("g").attr("id", "burgIcons"); $("#labels #capitals, #labels #towns").detach().appendTo($("#burgLabels")); - $("#icons #capitals, #icons #towns").detach().appendTo($("#burgIcons")); labels.select("#burgLabels").selectAll("text").each(function() { let id = this.getAttribute("id"); if (!id) return; this.removeAttribute("id"); this.setAttribute("data-id", +id.replace("manorLabel", "")); }); + } + + if (!icons.select("#burgIcons").size()) { + icons.append("g").attr("id", "burgIcons"); + $("#icons #capitals, #icons #towns").detach().appendTo($("#burgIcons")); icons.select("#burgIcons").select("#capitals").attr("size", 1).attr("fill-opacity", .7).attr("stroke-opacity", 1); icons.select("#burgIcons").select("#towns").attr("size", .5).attr("fill-opacity", .7).attr("stroke-opacity", 1); icons.select("#burgIcons").selectAll("circle").each(function() { @@ -5775,9 +5780,9 @@ function fantasyMap() { this.setAttribute("width", "1"); this.setAttribute("height", "1"); }); - } - if (labels.select("#countries").size() === 0) { + + if (!labels.select("#countries").size()) { labels.append("g").attr("id", "countries") .attr("fill", "#3e3e4b").attr("opacity", 1) .attr("font-family", "Almendra SC").attr("data-font", "Almendra+SC") @@ -5823,7 +5828,6 @@ function fantasyMap() { const graphSizeAdj = 90 / Math.sqrt(cells.length, 2); // adjust to different graphSize land.forEach(function(i) { const p = i.index; - i.area = rn(Math.abs(d3.polygonArea(polygons[p])), 2); if (i.pop === undefined) { let population = 0; const elevationFactor = Math.pow(1 - i.height, 3); @@ -5831,6 +5835,9 @@ function fantasyMap() { if (i.region === "neutral") population *= 0.5; i.pop = rn(population, 1); } + if (!polygons[p] || !polygons[p].length) return; + const area = d3.polygonArea(polygons[p]); + i.area = rn(Math.abs(area), 2); }); // restore Heightmap customization mode @@ -5957,7 +5964,7 @@ function fantasyMap() { case 67: // "C" to log cells data console.log(cells); break; - case 77: // "B" to log burgs data + case 66: // "B" to log burgs data console.table(manors); break; case 83: // "S" to log states data @@ -8518,7 +8525,7 @@ function fantasyMap() { voronoi = d3.voronoi().extent([[-1, -1], [graphWidth+1, graphHeight+1]]); zoom.translateExtent([[0, 0], [graphWidth, graphHeight]]).scaleExtent([1, 20]).scaleTo(svg, 1); viewbox.attr("transform", null); - ocean.selectAll("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%"); + ocean.selectAll("rect").attr("x", 0).attr("y", 0).attr("width", graphWidth).attr("height", graphHeight); } // change svg size on manual size change or window resize, do not change graph size @@ -8545,7 +8552,7 @@ function fantasyMap() { // fit ScaleBar to map size function fitScaleBar() { const el = d3.select("#scaleBar"); - if (el.size() === 0) return; + if (!el.select("rect").size()) return; const bbox = el.select("rect").node().getBBox(); let tr = [svgWidth - bbox.width, svgHeight - (bbox.height - 10)]; if (sessionStorage.getItem("scaleBar")) { From 42dcae94bb5703f9da3746acc9ee8bf9df46027e Mon Sep 17 00:00:00 2001 From: Azgaar Date: Fri, 10 Aug 2018 02:06:46 +0300 Subject: [PATCH 14/25] v. 0.58.13b --- README.md | 8 +++---- index.html | 6 ++--- script.js | 66 +++++++++++++++++++++++++++++++++++------------------- 3 files changed, 49 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index c9d2d0cf..685bd197 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,12 @@ # Fantasy Map Generator -Azgaar's _Fantasy Map Generator_. Online tool generating maps based on [D3](https://d3js.org) Voronoi diagram rendered in svg. +Azgaar's _Fantasy Map Generator_. Online tool generating interactive svg maps based on [D3](https://d3js.org) voronoi diagram. -Project goal is a procedurally generated map for my *Medieval Dynasty* simulator. Map should be interactive, scalable, fast and plausible. Initial intend was to place at least 500 burgs within 7 cultural areas and imagined land area about 1 million km2. As for now all these parameters are customizable and Generator is mostly used for a homebrew DnD campaign maps. +Project is under active development, check out the work in progress version [here](https://azgaar.github.io/Fantasy-Map-Generator). Refer to the [project wiki](https://github.com/Azgaar/Fantasy-Map-Generator/wiki) for a guidance. Some details are covered in my blog [_Fantasy Maps for fun and glory_](https://azgaar.wordpress.com), you may also keep an eye on my [Trello devboard](https://trello.com/b/7x832DG4/fantasy-map-generator). [![alt tag](https://i0.wp.com/azgaar.files.wordpress.com/2017/03/80k-part.png)](https://azgaar.wordpress.com) -Project is under active development, check out the work in progress version [here](https://azgaar.github.io/Fantasy-Map-Generator). See the [changelog](https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog) for archived versions. Refer to the [project wiki](https://github.com/Azgaar/Fantasy-Map-Generator/wiki) for a quick guidance. Some details are covered in my blog [_Fantasy Maps for fun and glory_](https://azgaar.wordpress.com), you may also keep an eye on my [Trello devboard](https://trello.com/b/7x832DG4/fantasy-map-generator). - - Join our [Reddit community](https://www.reddit.com/r/FantasyMapGenerator) to share the created maps, discuss the Generator, suggest ideas and get a most recent updates. You may also contact me directly via [email](mailto:maxganiev@yandex.com). For bug reports please use the project [issues page](https://github.com/Azgaar/Fantasy-Map-Generator/issues). If you find the Demo performance low, open the page in a much smaller window and use the default graph size only. The best performance is observed in Chrome, there are also some reports about different features not working on Mac OS. + Join our [Reddit community](https://www.reddit.com/r/FantasyMapGenerator) to share the created maps, discuss the Generator, suggest ideas and get a most recent updates. You may also contact me directly via [email](mailto:maxganiev@yandex.com). For bug reports please use the project [issues page](https://github.com/Azgaar/Fantasy-Map-Generator/issues). If you face performance issues, please try to open the page in a small window and use the default graph size only. In Firefox fast map zooming may cause browser crush. _Inspiration:_ diff --git a/index.html b/index.html index f75dc532..4a4b07a1 100644 --- a/index.html +++ b/index.html @@ -31,8 +31,8 @@ - - + + @@ -1109,5 +1109,5 @@ - + diff --git a/script.js b/script.js index 38445e7c..7c1c408a 100644 --- a/script.js +++ b/script.js @@ -1,4 +1,8 @@ // Fantasy Map Generator main script +// Azgaar (Max Haniyeu). Minsk, 2017-2018 +// https://github.com/Azgaar/Fantasy-Map-Generator +// GNU General Public License v3.0 + "use strict;" fantasyMap(); function fantasyMap() { @@ -2068,6 +2072,7 @@ function fantasyMap() { // add lakes on depressed points on river course function addLakes() { console.time('addLakes'); + let smallLakes = 0; for (let i=0; i < land.length; i++) { // elavate all big lakes if (land[i].lake === 1) { @@ -2075,11 +2080,12 @@ function fantasyMap() { land[i].ctype = -1; } // define eligible small lakes - if (land[i].lake === 2) { + if (land[i].lake === 2 && smallLakes < 100) { if (land[i].river !== undefined) { land[i].height = 0.19; land[i].ctype = -1; land[i].fn = -1; + smallLakes++; } else { land[i].lake = undefined; land[i].neighbors.forEach(function(n) { @@ -2088,6 +2094,7 @@ function fantasyMap() { cells[n].height = 0.19; cells[n].ctype = -1; cells[n].fn = -1; + smallLakes++; } else if (cells[n].lake === 2) { cells[n].lake = undefined; } @@ -3989,9 +3996,16 @@ function fantasyMap() { // generate random name using Markov's chain function generateName(culture, base) { - if (base === undefined) base = cultures[culture].base; + if (base === undefined) { + if (!cultures[culture]) { + console.error("culture " + culture + " is not defined. Will load default cultures and set first culture"); + generateCultures(); + culture = 0; + } + base = cultures[culture].base; + } if (!nameBases[base]) { - console.error("nameBase " + base + "is not defined. Will load default names data and first base"); + console.error("nameBase " + base + " is not defined. Will load default names data and first base"); localStorage.removeItem("nameBase"); localStorage.removeItem("nameBases"); applyDefaultNamesData(); @@ -4420,10 +4434,12 @@ function fantasyMap() { if (!terrs.selectAll("path").size()) { cells.map(function(i, d) { let height = i.height; - if (height < 0.2 && i.lake !== 2) return; - if (i.lake === 2) { + if (height < 0.2 && !i.lake) return; + if (i.lake) { const heights = i.neighbors.map(function(e) {if (cells[e].height >= 0.2) return cells[e].height;}) - height = Math.trunc(d3.mean(heights) * 100) / 100; + const mean = d3.mean(heights); + if (!mean) return; + height = Math.trunc(mean * 100) / 100; if (height < 0.2 || isNaN(height)) height = 0.2; } const clr = hColor(1 - height); @@ -5763,25 +5779,29 @@ function fantasyMap() { $("#icons #capitals, #icons #towns").detach().appendTo($("#burgIcons")); icons.select("#burgIcons").select("#capitals").attr("size", 1).attr("fill-opacity", .7).attr("stroke-opacity", 1); icons.select("#burgIcons").select("#towns").attr("size", .5).attr("fill-opacity", .7).attr("stroke-opacity", 1); - icons.select("#burgIcons").selectAll("circle").each(function() { - let id = this.getAttribute("id"); - if (!id) return; - this.removeAttribute("id"); - this.setAttribute("r", this.parentNode.getAttribute("size")); - this.setAttribute("data-id", +id.replace("manorIcon", "")); - }); - icons.select("#capital-anchors").raise().attr("size", 2).attr("size", null); - icons.select("#capital-anchors").selectAll("use").each(function() { - this.setAttribute("width", "2"); - this.setAttribute("height", "2"); - }); - icons.select("#town-anchors").raise().attr("size", 1).attr("size", null); - icons.select("#town-anchors").selectAll("use").each(function() { - this.setAttribute("width", "1"); - this.setAttribute("height", "1"); - }); } + icons.selectAll("g").each(function(d) { + const size = this.getAttribute("font-size"); + if (size === undefined) return; + this.removeAttribute("font-size"); + this.setAttribute("size", size); + }); + + icons.select("#burgIcons").selectAll("circle").each(function() { + this.setAttribute("r", this.parentNode.getAttribute("size")); + const id = this.getAttribute("id"); + if (!id) return; + this.removeAttribute("id"); + this.setAttribute("data-id", +id.replace("manorIcon", "")); + }); + + icons.selectAll("use").each(function() { + const size = this.parentNode.getAttribute("size"); + this.setAttribute("width", size); + this.setAttribute("height", size); + }); + if (!labels.select("#countries").size()) { labels.append("g").attr("id", "countries") .attr("fill", "#3e3e4b").attr("opacity", 1) From bb37137f2167467f22d3b2693b09a61ca39686c5 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sat, 11 Aug 2018 01:34:42 +0300 Subject: [PATCH 15/25] v. 0.58.14b --- index.css | 13 +-- index.html | 17 ++-- script.js | 262 +++++++++++++++++++++++++++++++++++------------------ 3 files changed, 189 insertions(+), 103 deletions(-) diff --git a/index.css b/index.css index 15891f96..fc66801c 100644 --- a/index.css +++ b/index.css @@ -524,12 +524,13 @@ p { display: none; text-align: center; top: calc(98vh - (10px + 0.5vw)); - width: 100%; - cursor: default; - text-shadow: 1px 1px 2px #1d0e0f; - color: #ffffff; - font-size: calc(10px + 0.5vw); - pointer-events: none; + width: 90%; + left: 5%; + cursor: default; + text-shadow: 1px 1px 3px #0e0e0e; + color: #ffffff; + font-size: calc(10px + 0.5vw); + pointer-events: none; } #optionsContent table td:nth-of-type(1) { diff --git a/index.html b/index.html index 4a4b07a1..23f5b13f 100644 --- a/index.html +++ b/index.html @@ -164,8 +164,8 @@ @@ -752,6 +752,7 @@ 1000 + diff --git a/script.js b/script.js index 7c1c408a..4a9303fc 100644 --- a/script.js +++ b/script.js @@ -37,7 +37,7 @@ function fantasyMap() { labels = viewbox.append("g").attr("id", "labels"), burgLabels = labels.append("g").attr("id", "burgLabels"), icons = viewbox.append("g").attr("id", "icons"), - burgIcons = icons.append("g").attr("id", "burgIcons") + burgIcons = icons.append("g").attr("id", "burgIcons"), ruler = viewbox.append("g").attr("id", "ruler"), debug = viewbox.append("g").attr("id", "debug"); @@ -1581,6 +1581,10 @@ function fantasyMap() { const x = d3.event.x, y = d3.event.y; const transform = `translate(${(dx+x)},${(dy+y)})`; el.attr("transform", transform); + const pp = this.parentNode.parentNode.id; + if (pp === "burgIcons" || pp === "burgLabels") { + tip('Use dragging for fine-tuning only, to move burg to a different cell use "Relocate" button'); + } }); d3.event.on("end", function() { @@ -2433,7 +2437,7 @@ function fantasyMap() { function unselect() { if (elSelected) { - elSelected.call(d3.drag().on("drag", null)).classed("draggable", false); + elSelected.call(d3.drag().on("drag", null)).attr("class", null); debug.select(".controlPoints").remove(); viewbox.style("cursor", "default"); elSelected = null; @@ -2917,12 +2921,8 @@ function fantasyMap() { } function editBurg() { - if (customization) {return;} - if (elSelected) { - const self = d3.select(this).attr("data-id") === elSelected.attr("data-id"); - if (self) {return;} - } - + if (customization) return; + unselect(); closeDialogs("#burgEditor, .stable"); elSelected = d3.select(this); const id = +elSelected.attr("data-id"); @@ -2987,7 +2987,7 @@ function fantasyMap() { }); } - $("#burgEditor > button").not("#burgAddfromEditor").not("#burgRemove").click(function() { + $("#burgEditor > button").not("#burgAddfromEditor").not("#burgRelocate").not("#burgRemove").click(function() { if ($(this).next().is(":visible")) { $("#burgEditor > button").show(); $(this).next("div").hide(); @@ -3260,6 +3260,75 @@ function fantasyMap() { manors[id].population = +this.value; }); + $("#burgRelocate").click(function() { + if ($(this).hasClass('pressed')) { + $(".pressed").removeClass('pressed'); + restoreDefaultEvents(); + tip("", true); + } else { + $(".pressed").removeClass('pressed'); + const id = elSelected.attr("data-id"); + $(this).addClass('pressed').attr("data-id", id); + viewbox.style("cursor", "crosshair").on("click", relocateBurgOnClick); + tip("Click on map to relocate burg. Hold Shift for continuous move", true); + } + }); + + // move burg to a different cell + function relocateBurgOnClick() { + const point = d3.mouse(this); + const index = getIndex(point); + const i = +$("#burgRelocate").attr("data-id"); + if (isNaN(i) || !manors[i]) return; + + if (cells[index].height < 0.2) { + tip("Cannot place burg in the water! Select a land cell", null, "error"); + return; + } + + if (cells[index].manor !== undefined && cells[index].manor !== i) { + tip("There is already a burg in this cell. Please select a free cell", null, "error"); + $('#grid').fadeIn(); + d3.select("#toggleGrid").classed("buttonoff", false); + return; + } + + let region = cells[index].region; + const oldRegion = manors[i].region; + // relocating capital to other country you "conqure" thid cell + if (states[oldRegion] && states[oldRegion].capital === i) { + if (region !== oldRegion) { + tip("Capital cannot be moved to another country!", null, "error"); + return; + } + } + + if (d3.event.shiftKey === false) { + $("#burgRelocate").removeClass("pressed"); + restoreDefaultEvents(); + tip("", true); + if (region !== oldRegion) { + recalculateStateData(oldRegion); + recalculateStateData(region); + updateCountryEditors(); + } + } + + const x = rn(point[0], 2), y = rn(point[1], 2); + burgIcons.select("circle[data-id='"+i+"']").attr("cx", x).attr("cy", y); + burgLabels.select("text[data-id='"+i+"']").attr("x", x).attr("y", y); + const anchor = icons.select("use[data-id='"+i+"']"); + if (anchor.size()) { + const size = anchor.attr("width"); + const xa = rn(x - size * 0.47, 2); + const ya = rn(y - size * 0.47, 2); + icons.select("use[data-id='"+i+"']").attr("x", xa).attr("y", ya); + } + cells[index].manor = i; + cells[manors[i].cell].manor = undefined; + manors[i].x = x, manors[i].y = y, manors[i].region = region, manors[i].cell = index; + } + $("#burgAddfromEditor").click(function() { clickToAdd(); // to load on click event function $("#addBurg").click(); @@ -3393,7 +3462,8 @@ function fantasyMap() { if (m.i === m.region && !cell.port) {score *= 2;} // land-capitals if (m.i === m.region && cell.port) {score *= 3;} // port-capitals if (m.region === "neutral") score *= urbanFactor; - m.population = rn(score, 1); + const rnd = 0.6 + Math.random() * 0.8; // random factor + m.population = rn(score * rnd, 1); }); // calculate rural population for each cell based on area + elevation (elevation to be changed to biome) @@ -4296,7 +4366,10 @@ function fantasyMap() { if (Math.random() < 0.85 || culture === null) { // culture is random if capital is not yet defined if (culture === null) culture = rand(cultures.length - 1); - while (name.length > 8) {name = generateName(culture);} + // try to avoid too long words as a basename + for (let i=0; i < 20 && name.length > 7; i++) { + name = generateName(culture); + } } else { name = manors[state].name; } @@ -4309,10 +4382,30 @@ function fantasyMap() { // remove -sk and -ev/-ov for Ruthenian name = name.slice(0,-2); addSuffix = true; + } else if (name.length > 5 && base === 1 && name.slice(-3) === "ton") { + // remove -ton ending for English + name = name.slice(0,-3); + addSuffix = true; } else if (name.length > 6 && name.slice(-4) === "berg") { // remove -berg ending for any name = name.slice(0,-4); addSuffix = true; + } else if (base === 12) { + // Japanese ends on vowels + if (vowels.includes(name.slice(-1))) return name; + return name + "u"; + } else if (base === 10) { + // Korean has "guk" suffix + if (name.slice(-3) === "guk") return name; + if (name.slice(-1) === "g") name = name.slice(0,-1); + if (Math.random() < 0.2 && name.length < 7) name = name + "guk"; // 20% for "guk" + return name; + } else if (base === 11) { + // Chinese has "guo" suffix + if (name.slice(-3) === "guo") return name; + if (name.slice(-1) === "g") name = name.slice(0,-1); + if (Math.random() < 0.3 && name.length < 7) name = name + " Guo"; // 30% for "guo" + return name; } // define if suffix should be used @@ -4332,7 +4425,6 @@ function fantasyMap() { } if (addSuffix === false) return name; - let suffix = "ia"; // common latin suffix const rnd = Math.random(); if (rnd < 0.05 && base === 3) suffix = "terra"; // 5% "terra" for Italian @@ -4341,6 +4433,8 @@ function fantasyMap() { else if (rnd < 0.5 && base == 0) suffix = "land"; // 50% "land" for German else if (rnd < 0.4 && base == 1) suffix = "land"; // 40% "land" for English else if (rnd < 0.3 && base == 6) suffix = "land"; // 30% "land" for Nordic + else if (rnd < 0.1 && base == 7) suffix = "eia"; // 10% "eia" for Greek ("ia" is also Greek) + else if (rnd < 0.4 && base == 9) suffix = "maa"; // 40% "maa" for Finnic if (name.slice(-1 * suffix.length) === suffix) return name; // no suffix if name already ends with it return name + suffix; } @@ -4756,7 +4850,7 @@ function fantasyMap() { // Add support "click to add" button events $("#customizeTab").click(function() {clickToAdd()}); function clickToAdd() { - if (modules.clickToAdd) {return;} + if (modules.clickToAdd) return; modules.clickToAdd = true; // add label on click @@ -4802,11 +4896,11 @@ function fantasyMap() { if ($(this).hasClass('pressed')) { $(".pressed").removeClass('pressed'); restoreDefaultEvents(); + tip("", true); } else { $(".pressed").removeClass('pressed'); $(this).attr("data-state", -1).addClass('pressed'); - $("#burgAdd").addClass('pressed'); - closeDialogs(".stable"); + $("#burgAdd, #burgAddfromEditor").addClass('pressed'); viewbox.style("cursor", "crosshair").on("click", addBurgOnClick); tip("Click on map to place burg icon with a label. Hold Shift to place several", true); } @@ -4823,11 +4917,11 @@ function fantasyMap() { const name = generateName(culture); if (cells[index].height < 0.2) { - tip("Cannot place burg in the water! Select a land cell"); + tip("Cannot place burg in the water! Select a land cell", null, "error"); return; } if (cells[index].manor !== undefined) { - tip("There is already a burg in this cell. You have to select a free cell"); + tip("There is already a burg in this cell. Please select a free cell", null, "error"); $('#grid').fadeIn(); d3.select("#toggleGrid").classed("buttonoff", false); return; @@ -4839,7 +4933,7 @@ function fantasyMap() { invokeActiveZooming(); if (d3.event.shiftKey === false) { - $("#addBurg, #burgAdd").removeClass("pressed"); + $("#addBurg, #burgAdd, #burgAddfromEditor").removeClass("pressed"); restoreDefaultEvents(); } @@ -5011,7 +5105,7 @@ function fantasyMap() { // re-calculate data for a particular state function recalculateStateData(state) { - const s = states[state]; + const s = states[state] || states[states.length - 1]; if (s.capital === "neutral") state = "neutral"; const burgs = $.grep(manors, function(e) {return e.region === state;}); s.burgs = burgs.length; @@ -5717,7 +5811,7 @@ function fantasyMap() { const extent = (100 / scaleTo) + "%"; const xShift = (nWidth * scaleTo - svgWidth) / 2 / scaleTo; const yShift = (nHeight * scaleTo - svgHeight) / 2 / scaleTo; - ocean.selectAll("rect").attr("x", xShift).attr("y", yShift).attr("width", extent).attr("height", extent); + svg.select("#ocean").selectAll("rect").attr("x", xShift).attr("y", yShift).attr("width", extent).attr("height", extent); zoom.translateExtent([[0, 0], [nWidth, nHeight]]).scaleExtent([scaleTo, 20]).scaleTo(svg, scaleTo); $(this).dialog("close"); }, @@ -5767,8 +5861,8 @@ function fantasyMap() { labels.append("g").attr("id", "burgLabels"); $("#labels #capitals, #labels #towns").detach().appendTo($("#burgLabels")); labels.select("#burgLabels").selectAll("text").each(function() { - let id = this.getAttribute("id"); - if (!id) return; + const id = this.getAttribute("id"); + if (id === null || id === undefined) return; this.removeAttribute("id"); this.setAttribute("data-id", +id.replace("manorLabel", "")); }); @@ -5781,9 +5875,9 @@ function fantasyMap() { icons.select("#burgIcons").select("#towns").attr("size", .5).attr("fill-opacity", .7).attr("stroke-opacity", 1); } - icons.selectAll("g").each(function(d) { + icons.selectAll("g").each(function() { const size = this.getAttribute("font-size"); - if (size === undefined) return; + if (size === null || size === undefined) return; this.removeAttribute("font-size"); this.setAttribute("size", size); }); @@ -5791,13 +5885,14 @@ function fantasyMap() { icons.select("#burgIcons").selectAll("circle").each(function() { this.setAttribute("r", this.parentNode.getAttribute("size")); const id = this.getAttribute("id"); - if (!id) return; + if (id === null || id === undefined) return; this.removeAttribute("id"); this.setAttribute("data-id", +id.replace("manorIcon", "")); }); icons.selectAll("use").each(function() { const size = this.parentNode.getAttribute("size"); + if (size === null || size === undefined) return; this.setAttribute("width", size); this.setAttribute("height", size); }); @@ -5962,71 +6057,56 @@ function fantasyMap() { } } - // Hotkeys + // Hotkeys, see github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys d3.select("body").on("keydown", function() { const active = document.activeElement.tagName; if (active === "INPUT" || active === "SELECT" || active === "TEXTAREA") return; - switch(d3.event.keyCode) { - case 27: // Escape to close all dialogs - closeDialogs(); - break; - case 79: // "O" to toggle options - optionsTrigger.click(); - break; - case 113: // "F2" for new map - $("#randomMap").click(); - break; - case 32: // Space to log focused cell data - var point = d3.mouse(this); - const index = diagram.find(point[0], point[1]).index; - console.table(cells[index]); - break; - case 67: // "C" to log cells data - console.log(cells); - break; - case 66: // "B" to log burgs data - console.table(manors); - break; - case 83: // "S" to log states data - console.table(states); - break; - case 70: // "F" to log features data - console.table(features); - break; - case 37: // Left to scroll map left - zoom.translateBy(svg, 10, 0); - break; - case 39: // Right to scroll map right - zoom.translateBy(svg, -10, 0); - break; - case 38: // Up to scroll map up - zoom.translateBy(svg, 0, 10); - break; - case 40: // Down to scroll map down - zoom.translateBy(svg, 0, -10); - break; - case 107: // Plus to zoom map up - zoom.scaleBy(svg, 1.2); - break; - case 109: // Minus to zoom map out - zoom.scaleBy(svg, 0.8); - break; - case 9: // Tab to toggle full-screen mode - $("#updateFullscreen").click(); - break; - case 90: // Ctrl + "Z" to toggle undo - if (customization !== 1) return; - if (d3.event.ctrlKey === false) return; - undo.click(); - break; - case 89: // Ctrl + "Y" to toggle undo - if (customization !== 1) return; - if (d3.event.ctrlKey === false) return; - redo.click(); - break; - } + const key = d3.event.keyCode; + const ctrl = d3.event.ctrlKey; + const p = d3.mouse(this); + if (key === 117) $("#randomMap").click(); // "F6" for new map + else if (key === 27) closeDialogs(); // Escape to close all dialogs + else if (key === 79) optionsTrigger.click(); // "O" to toggle options + else if (key === 80) saveAsImage("png"); // "P" to save as PNG + else if (key === 83) saveAsImage("svg"); // "S" to save as SVG + else if (key === 77) saveMap(); // "M" to save MAP file + else if (key === 76) mapToLoad.click(); // "L" to load MAP + else if (key === 32) console.table(cells[diagram.find(p[0], p[1]).index]); // Space to log focused cell data + else if (key === 192) console.log(cells); // "`" to log cells data + else if (key === 66) console.table(manors); // "B" to log burgs data + else if (key === 67) console.table(states); // "C" to log countries data + else if (key === 70) console.table(features); // "F" to log features data + else if (key === 37) zoom.translateBy(svg, 10, 0); // Left to scroll map left + else if (key === 39) zoom.translateBy(svg, -10, 0); // Right to scroll map right + else if (key === 38) zoom.translateBy(svg, 0, 10); // Up to scroll map up + else if (key === 40) zoom.translateBy(svg, 0, -10); // Up to scroll map up + else if (key === 107) zoom.scaleBy(svg, 1.2); // Plus to zoom map up + else if (key === 109) zoom.scaleBy(svg, 0.8); // Minus to zoom map out + else if (key === 48 || key === 96) resetZoom(); // 0 to reset zoom + else if (key === 49 || key === 97) zoom.scaleTo(svg, 1); // 1 to zoom to 1 + else if (key === 50 || key === 98) zoom.scaleTo(svg, 2); // 2 to zoom to 2 + else if (key === 51 || key === 99) zoom.scaleTo(svg, 3); // 3 to zoom to 3 + else if (key === 52 || key === 100) zoom.scaleTo(svg, 4); // 4 to zoom to 4 + else if (key === 53 || key === 101) zoom.scaleTo(svg, 5); // 5 to zoom to 5 + else if (key === 54 || key === 102) zoom.scaleTo(svg, 6); // 6 to zoom to 6 + else if (key === 55 || key === 103) zoom.scaleTo(svg, 7); // 7 to zoom to 7 + else if (key === 56 || key === 104) zoom.scaleTo(svg, 8); // 8 to zoom to 8 + else if (key === 57 || key === 105) zoom.scaleTo(svg, 9); // 9 to zoom to 9 + else if (key === 9) $("#updateFullscreen").click(); // Tab to fit map to fullscreen + else if (ctrl && key === 90) undo.click(); // Ctrl + "Z" to toggle undo + else if (ctrl && key === 89) redo.click(); // Ctrl + "Y" to toggle undo }); + // Show help + function showHelp() { + $("#help").dialog({ + title: "About Fantasy Map Generator", + minHeight: 30, width: "auto", maxWidth: 275, resizable: false, + position: {my: "center top+10", at: "bottom", of: this}, + close: unselect + }); + } + // Toggle Options pane $("#optionsTrigger").on("click", function() { if (tooltip.getAttribute("data-main") === "Сlick the arrow button to open options") { @@ -8557,7 +8637,8 @@ function fantasyMap() { const width = Math.max(svgWidth, graphWidth); const height = Math.max(svgHeight, graphHeight); zoom.translateExtent([[0, 0], [width, height]]); - ocean.selectAll("rect").attr("width", width).attr("height", height); + svg.select("#ocean").selectAll("rect").attr("x", 0) + .attr("y", 0).attr("width", width).attr("height", height); } // fit full-screen map if window is resized @@ -8996,9 +9077,12 @@ function fantasyMap() { } } -function tip(tip, main) { - tooltip.innerHTML = tip; - if (main) {tooltip.setAttribute("data-main", tip);} +function tip(tip, main, error) { + const tooltip = d3.select("#tooltip"); + const reg = "linear-gradient(0.1turn, #ffffff00, #5e5c5c33, #ffffff00)"; + const red = "linear-gradient(0.1turn, #ffffff00, #c71d1d4d, #ffffff00)"; + tooltip.text(tip).style("background", error ? red : reg); + if (main) tooltip.attr("data-main", tip); } $("#optionsContainer *").on("mouseout", function() { From 9a1311b50e4c144c097dcd2d56ed426cd7c3dac6 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sat, 11 Aug 2018 16:43:24 +0300 Subject: [PATCH 16/25] v. 0.58.15b --- index.css | 2 +- index.html | 16 ++-- script.js | 213 +++++++++++++++++++++++++++-------------------------- 3 files changed, 117 insertions(+), 114 deletions(-) diff --git a/index.css b/index.css index fc66801c..59ad26b5 100644 --- a/index.css +++ b/index.css @@ -516,7 +516,7 @@ p { } #customizeOptions { - margin: 2px 0; + margin: 2px 0 6px 0; } #tooltip { diff --git a/index.html b/index.html index 23f5b13f..a239d0a0 100644 --- a/index.html +++ b/index.html @@ -31,8 +31,8 @@ - - + + @@ -502,7 +502,7 @@
- +
@@ -680,7 +680,7 @@ - + diff --git a/script.js b/script.js index 4a9303fc..d1b56021 100644 --- a/script.js +++ b/script.js @@ -1235,23 +1235,28 @@ function fantasyMap() { } // recalculate Voronoi Graph to pack cells - function reGraph() { + function reGraph(noChange) { console.time("reGraph"); const tempCells = [], newPoints = []; // to store new data // get average precipitation based on graph size const avPrec = precInput.value / 5000; + const smallLakesMax = 500; + let smallLakes = 0; const evaporation = 2; cells.map(function(i) { let height = Math.trunc(i.height * 100) / 100; + const pit = i.pit; const ctype = i.ctype; if (ctype !== -1 && ctype !== -2 && height < 0.2) return; // exclude all depp ocean points const x = rn(i.data[0], 1), y = rn(i.data[1], 1); const fn = i.fn; const harbor = i.harbor; let lake = i.lake; - if (!lake && i.pit > evaporation && ctype !== 2) { + // mark potential cells for small lakes to add additional point there + // not for custom map if "changeHeights" is not alkowed + if (!noChange && smallLakes < smallLakesMax && !lake && pit > evaporation && ctype !== 2) { lake = 2; - height = Math.trunc(height * 100 - i.pit) / 100; + smallLakes++; } if (height > 1) height = 1; if (height < 0) height = 0; @@ -1260,7 +1265,7 @@ function fantasyMap() { let copy = $.grep(newPoints, function(e) {return (e[0] == x && e[1] == y);}); if (!copy.length) { newPoints.push([x, y]); - tempCells.push({index:tempCells.length, data:[x, y], height, ctype, fn, harbor, lake, region, culture}); + tempCells.push({index:tempCells.length, data:[x, y], height, pit, ctype, fn, harbor, lake, region, culture}); } // add additional points for cells along coast if (ctype === 2 || ctype === -1) { @@ -1274,13 +1279,12 @@ function fantasyMap() { copy = $.grep(newPoints, function(e) {return e[0] === x1 && e[1] === y1;}); if (copy.length) return; newPoints.push([x1, y1]); - tempCells.push({index:tempCells.length, data:[x1, y1], height, ctype, fn, harbor, lake, region, culture}); + tempCells.push({index:tempCells.length, data:[x1, y1], height, pit, ctype, fn, harbor, lake, region, culture}); }; }); } if (lake === 2) { // add potential small lakes //debug.append("circle").attr("r", 0.3).attr("cx", x).attr("cy", y).attr("fill", "blue"); - height = Math.trunc(height * 100 + 1) / 100; polygons[i.index].forEach(function(e) { if (Math.random() > 0.8) return; let rnd = Math.random() * 0.6 + 0.8; @@ -1291,7 +1295,7 @@ function fantasyMap() { if (copy.length) return; //debug.append("circle").attr("r", 0.2).attr("cx", x1).attr("cy", y1).attr("fill", "red"); newPoints.push([x1, y1]); - tempCells.push({index:tempCells.length, data:[x1, y1], height, ctype, fn, region, culture}); + tempCells.push({index:tempCells.length, data:[x1, y1], height, pit, ctype, fn, region, culture}); }); } }); @@ -1389,7 +1393,7 @@ function fantasyMap() { let landCells = 0; cells.map(function(c) { heights.push(c.height); - if (c.height >= 0.2) {landCells++;} + if (c.height >= 0.2) landCells++; }); history = history.slice(0, historyStage); history[historyStage] = heights; @@ -1399,8 +1403,6 @@ function fantasyMap() { var elevationAverage = rn(d3.mean(heights), 2); var landRatio = rn(landCells / cells.length * 100); landmassCounter.innerHTML = landCells + " (" + landRatio + "%); Average Elevation: " + elevationAverage; - if (landCells > 100) {$("#getMap").attr("disabled", false).removeClass("buttonoff").addClass("glow");} - else {$("#getMap").attr("disabled", true).addClass("buttonoff").removeClass("glow");} // if perspective is displayed, update it if ($("#perspectivePanel").is(":visible")) {drawPerspective();} } @@ -1822,7 +1824,12 @@ function fantasyMap() { } function restoreCustomHeights() { - land.forEach(function(l) {if (l.pit) rn(l.height -= l.pit / 50, 2);}); + land.forEach(function(l) { + if (l.pit) { + l.height = Math.trunc(l.height * 100 - l.pit * 2) / 100; + if (l.height < 0.2) l.height = 0.2; + } + }); } function flux() { @@ -3012,15 +3019,7 @@ function fantasyMap() { $("#burgSelectGroup").change(function() { const id = +elSelected.attr("data-id"); const g = this.value; - $("#burgIcons [data-id=" + id + "]").detach().appendTo($("#burgIcons > #"+g)); - $("#burgLabels [data-id=" + id + "]").detach().appendTo($("#burgLabels > #"+g)); - // special case for port icons (anchors) - if (g === "towns" || g === "capitals") { - const el = $("#icons g[id*='anchors'] [data-id=" + id + "]"); - if (!el.length) return; - const to = g === "towns" ? $("#town-anchors") : $("#capital-anchors"); - el.detach().appendTo(to); - } + moveBurgToGroup(id, g); }); $("#burgInputGroup").change(function() { @@ -3215,22 +3214,14 @@ function fantasyMap() { if (states[state] === undefined) return; const capital = states[manors[id].region] ? id === states[manors[id].region].capital ? 0 : 1 : 1; if (capital && states[state].capital !== "select") { - // move oldCapital to burg + // move oldCapital to a town group const oldCapital = states[state].capital; - $("#burgIcons [data-id=" + oldCapital + "]").detach().appendTo($("#burgIcons > #towns")); - $("#burgLabels [data-id=" + oldCapital + "]").detach().appendTo($("#burgLabels > #towns")); - $("#icons #capital-anchors [data-id=" + oldCapital + "]").detach().appendTo($("#town-anchors")); + moveBurgToGroup(oldCapital, "towns"); } states[state].capital = capital ? id : "select"; d3.select("#burgToggleCapital").classed("pressed", capital); const g = capital ? "capitals" : "towns"; - $("#burgIcons [data-id=" + id + "]").detach().appendTo($("#burgIcons > #"+g)); - $("#burgLabels [data-id=" + id + "]").detach().appendTo($("#burgLabels > #"+g)); - const el = $("#icons g[id*='anchors'] [data-id=" + id + "]"); - updateCountryEditors(); - if (!el.length) return; - const to = g === "towns" ? $("#town-anchors") : $("#capital-anchors"); - el.detach().appendTo(to); + moveBurgToGroup(id, g); }); $("#burgTogglePort").click(function() { @@ -3315,14 +3306,14 @@ function fantasyMap() { } const x = rn(point[0], 2), y = rn(point[1], 2); - burgIcons.select("circle[data-id='"+i+"']").attr("cx", x).attr("cy", y); - burgLabels.select("text[data-id='"+i+"']").attr("x", x).attr("y", y); + burgIcons.select("circle[data-id='"+i+"']").attr("transform", null).attr("cx", x).attr("cy", y); + burgLabels.select("text[data-id='"+i+"']").attr("transform", null).attr("x", x).attr("y", y); const anchor = icons.select("use[data-id='"+i+"']"); if (anchor.size()) { const size = anchor.attr("width"); const xa = rn(x - size * 0.47, 2); const ya = rn(y - size * 0.47, 2); - icons.select("use[data-id='"+i+"']").attr("x", xa).attr("y", ya); + anchor.attr("transform", null).attr("x", xa).attr("y", ya); } cells[index].manor = i; cells[manors[i].cell].manor = undefined; @@ -3359,6 +3350,24 @@ function fantasyMap() { }); } + // generic function to move any burg to any group + function moveBurgToGroup(id, g) { + $("#burgLabels [data-id=" + id + "]").detach().appendTo($("#burgLabels > #"+g)); + $("#burgIcons [data-id=" + id + "]").detach().appendTo($("#burgIcons > #"+g)); + const rSize = $("#burgIcons > #"+g).attr("size"); + $("#burgIcons [data-id=" + id + "]").attr("r", rSize); + const el = $("#icons g[id*='anchors'] [data-id=" + id + "]"); + if (el.length) { + const to = g === "towns" ? $("#town-anchors") : $("#capital-anchors"); + el.detach().appendTo(to); + const useSize = to.attr("size"); + const x = rn(manors[id].x - useSize * 0.47, 2); + const y = rn(manors[id].y - useSize * 0.47, 2); + el.attr("x", x).attr("y", y).attr("width", useSize).attr("height", useSize); + } + updateCountryEditors(); + } + // generate cultures for a new map based on options and namesbase function generateCultures() { const count = +culturesInput.value; @@ -4822,26 +4831,36 @@ function fantasyMap() { } // Complete the map for the "customize" mode - function getMap(keepData) { + function getMap() { + if (customization !== 1) { + tip('Nothing to complete! Click on "Edit" or "Clear all" to enter a heightmap customizaton mode', null, "error"); + return; + } + land = $.grep(cells, function(e) {return e.height >= 0.2;}); + if (land.length < 100) { + tip("Insufficient land area! Please add more land cells to complete the map", null, "error"); + return; + } exitCustomization(); console.time("TOTAL"); markFeatures(); - // if (changeHeights.checked) reduceClosedLakes(); drawOcean(); elevateLakes(); resolveDepressionsPrimary(); - reGraph(); + const noChange = !changeHeights.checked; + reGraph(noChange); resolveDepressionsSecondary(); flux(); addLakes(); - if (!changeHeights.checked) restoreCustomHeights(); + if (noChange) restoreCustomHeights(); drawCoastline(); drawRelief(); - if (!keepData) { + const keepData = states.length && manors.length; + if (keepData) { + restoreRegions(); + } else { generateCultures(); manorsAndRegions(); - } else { - restoreRegions(); } cleanData(); console.timeEnd("TOTAL"); @@ -6176,9 +6195,9 @@ function fantasyMap() { generate(); return; } - if (id === "editCountries") {editCountries();} - if (id === "editCultures") {editCultures();} - if (id === "editScale" || id === "editScaleCountries" || id === "editScaleBurgs") {editScale();} + if (id === "editCountries") editCountries(); + if (id === "editCultures") editCultures(); + if (id === "editScale" || id === "editScaleCountries" || id === "editScaleBurgs") editScale(); if (id === "countriesManually") { customization = 2; tip("Click to select a country, drag the circle to re-assign", true); @@ -6337,7 +6356,9 @@ function fantasyMap() { link.click(); window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000); } - if (id === "burgNamesImport") {burgsListToLoad.click();} + + if (id === "burgNamesImport") burgsListToLoad.click(); + if (id === "removeCountries") { alertMessage.innerHTML = `Are you sure you want remove all countries?`; $("#alert").dialog({resizable: false, title: "Remove countries", @@ -6351,8 +6372,7 @@ function fantasyMap() { states.map(function(s) { const c = +s.capital; if (isNaN(c)) return; - $("#burgLabels [data-id=" + c + "]").detach().appendTo($("#burgLabels #towns")); - $("#burgIcons [data-id=" + c + "]").detach().appendTo($("#burgIcons #towns")); + moveBurgToGroup(c, "towns"); }); labels.select("#countries").selectAll("text").remove(); regions.selectAll("path").remove(); @@ -6488,9 +6508,11 @@ function fantasyMap() { }); } if (id === "fromHeightmap") { - let message = "It's highly recommended to finalize a heightmap as a first step. "; - message += "If you want to edit a map, it's better to clean up all the data except on heights. "; - message += "You may also keep the data, but it can cause unexpected errors"; + const message = `Hightmap is a basic element on which secondary data (burgs, countries, cultures) is based. + If you want to significantly change the hightmap, it may be better to clean up all the secondary data + and let the system to re-generate it based on the updated hightmap. In case of minor changes, you can keep the data. + Newly added lands will be considered as neutral. Burgs located on a removed land cells will be deleted. + Routes won't be regenerated.` alertMessage.innerHTML = message; $("#alert").dialog({resizable: false, title: "Edit Heightmap", buttons: { @@ -6538,9 +6560,7 @@ function fantasyMap() { updateHeightmap(); updateHistory(); } - if (id === "getMap") { - if (states.length && manors.length) {getMap("keep");} else {getMap();} - } + if (id === "getMap") getMap(); if (id === "applyTemplate") { if ($("#templateEditor").is(":visible")) {return;} $("#templateEditor").dialog({ @@ -6690,9 +6710,7 @@ function fantasyMap() { start.click(); } } - if (id === "templateComplete") { - if (customization === 1 && !$("#getMap").attr("disabled")) {getMap();} - } + if (id === "templateComplete") getMap(); if (id === "convertColorsMinus") { var current = +convertColors.value - 1; if (current < 4) {current = 3;} @@ -7327,7 +7345,8 @@ function fantasyMap() { // Enter Heightmap Customization mode function customizeHeightmap() { customization = 1; - tip("Heightmap customization mode is active. Click on \"Complete\" to finalize the Heightmap", true); + tip('Heightmap customization mode is active. Click on "Complete" to finalize the Heightmap', true); + $("#getMap").removeClass("buttonoff").addClass("glow"); resetZoom(); landmassCounter.innerHTML = "0"; $('#grid').fadeIn(); @@ -7343,7 +7362,7 @@ function fantasyMap() { tip("", true); canvas.style.opacity = 0; $("#customizationMenu").slideUp(); - $("#getMap").attr("disabled", true).addClass("buttonoff"); + $("#getMap").addClass("buttonoff").removeClass("glow"); $("#landmass").empty(); $('#grid').empty().fadeOut(); $('#toggleGrid').addClass("buttonoff"); @@ -7354,7 +7373,6 @@ function fantasyMap() { historyStage = 0; $("#customizeHeightmap").slideUp(); $("#openEditor").slideDown(); - $("#getMap").removeClass("glow"); debug.selectAll(".circle, .tag, .line").remove(); } @@ -7536,8 +7554,7 @@ function fantasyMap() { if (oldState === "neutral") {manors[burg].population *= (1 / urbanFactor);} manors[burg].population *= 2; // give capital x2 population bonus states[state].capital = burg; - $("#burgLabels [data-id=" + burg + "]").detach().appendTo($("#burgLabels #capitals")); - $("#burgIcons [data-id=" + burg + "]").detach().appendTo($("#burgIcons #capitals")); + moveBurgToGroup(burg, "capitals"); } } else { // free cell -> create new burg for a capital @@ -7605,47 +7622,33 @@ function fantasyMap() { }); // fully remove country $("#countriesBody .icon-trash-empty").on("click", function() { - var s = +(this.parentNode.id).slice(5); - if (states[s].capital === "select") { - removeCountry(s); - return; - } - alertMessage.innerHTML = `Are you sure you want to remove the country?`; + const s = +(this.parentNode.id).slice(5); + alertMessage.innerHTML = `Are you sure you want to remove the country? All lands and burgs will become neutral`; $("#alert").dialog({resizable: false, title: "Remove country", buttons: { - Remove: function() { - removeCountry(s); - $(this).dialog("close"); - }, + Remove: function() {removeCountry(s); $(this).dialog("close");}, Cancel: function() {$(this).dialog("close");} }}); }); function removeCountry(s) { const cellsCount = states[s].cells; - const capital = states[s].capital; + const capital = +states[s].capital; + if (!isNaN(capital)) moveBurgToGroup(capital, "towns"); states.splice(s, 1); states.map(function(s, i) {s.i = i;}); - cells.map(function(c) { + land.map(function(c) { if (c.region === s) c.region = "neutral"; else if (c.region > s) c.region -= 1; }); // do only if removed state had cells if (cellsCount) { - // change capital to burg - $("#burgLabels [data-id=" + capital + "]").detach().appendTo($("#burgLabels #towns")); - $("#burgIcons [data-id=" + capital + "]").detach().appendTo($("#burgIcons #towns")); - var burgsSelection = $.grep(manors, function(e) {return (e.region === s);}); - var urbanFactor = 0.9; - burgsSelection.map(function(b) { - if (b.i === capital) {b.population *= 0.5;} - b.population *= urbanFactor; - b.region = "neutral"; - }); + manors.map(function(b) {if (b.region === s) b.region = "neutral";}); // re-calculate neutral data - if (states[states.length-1].capital !== "neutral") { - states.push({i: states.length, color: "neutral", name: "Neutrals", capital: "neutral"}); + const i = states.length; + if (states[i-1].capital !== "neutral") { + states.push({i, color: "neutral", name: "Neutrals", capital: "neutral"}); } - recalculateStateData(states.length - 1); // re-calc data for neutrals + recalculateStateData(i-1); // re-calc data for neutrals redrawRegions(); } editCountries(); @@ -7708,25 +7711,25 @@ function fantasyMap() { var x = +l.attr("x"), y = +l.attr("y"); zoomTo(x, y, 8, 1600); }); + $("#burgsBody > div").hover(focusBurg, unfocus); + $("#burgsBody > div").click(function() { - if (!$("#changeCapital").hasClass("pressed")) {return;} - var type = $(this).attr("data-type"); - if (type.includes("capital")) {return;} - var s = +$("#burgsEditor").attr("data-state"); - var b = +$(this).attr("id").slice(5); - var oldCap = states[s].capital; - manors[oldCap].population *= 0.5; - manors[b].population *= 2; - states[s].capital = b; - recalculateStateData(s); - $("#labels [data-id=" + oldCap + "]").detach().appendTo($("#burgLabels #towns")); - $("#icons [data-id=" + oldCap + "]").detach().appendTo($("#burgIcons #towns")); - $("#labels [data-id=" + b + "]").detach().appendTo($("#burgLabels #capitals")); - $("#icons [data-id=" + b + "]").detach().appendTo($("#burgIcons #towns")); - updateCountryEditors(); + if (!$("#changeCapital").hasClass("pressed")) return; + const s = +$("#burgsEditor").attr("data-state"); + const newCap = +$(this).attr("id").slice(5); + const oldCap = +states[s].capital; + if (newCap === oldCap) { + tip("This burg is already a capital! Please select a different burg", null, "error"); + return; + } $("#changeCapital").removeClass("pressed"); + states[s].capital = newCap; + if (!isNaN(oldCap)) moveBurgToGroup(oldCap, "towns"); + recalculateStateData(s); + moveBurgToGroup(newCap, "capitals"); }); + $(".burgName").on("input", function() { var b = +(this.parentNode.id).slice(5); manors[b].name = this.value; @@ -7858,7 +7861,7 @@ function fantasyMap() { // open editCultures dialog function editCultures() { - if (cults.selectAll("path").size() === 0) $("#toggleCultures").click(); + if (!cults.selectAll("path").size()) $("#toggleCultures").click(); if (regions.style("display") !== "none") $("#toggleCountries").click(); layoutPreset.value = "layoutCultural"; $("#culturesBody").empty(); @@ -7876,9 +7879,9 @@ function fantasyMap() { }); manors.map(function(m) { - const r = m.region; - if (r === undefined || r === "removed") return; - urbPops[r] = urbPops[r] ? urbPops[r] + m.population : m.population; + const c = m.culture; + if (isNaN(c)) return; + urbPops[c] = urbPops[c] ? urbPops[c] + m.population : m.population; }); for (let c = 0; c < cultures.length; c++) { From 5e809de96296d42d1b4d80ba0f6b035e950c87a6 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sat, 11 Aug 2018 23:23:51 +0300 Subject: [PATCH 17/25] v. 0.58.16b --- index.html | 6 +++--- script.js | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index a239d0a0..8b989aee 100644 --- a/index.html +++ b/index.html @@ -582,7 +582,7 @@ - + @@ -1083,8 +1083,8 @@
- - + + diff --git a/script.js b/script.js index d1b56021..935415a6 100644 --- a/script.js +++ b/script.js @@ -1299,6 +1299,7 @@ function fantasyMap() { }); } }); + console.log( "small lakes candidates: " + smallLakes); cells = tempCells; // use tempCells as the only cells array calculateVoronoi(newPoints); // recalculate Voronoi diagram using new points let gridPath = ""; // store grid as huge single path string @@ -2113,6 +2114,7 @@ function fantasyMap() { } } } + console.log( "small lakes: " + smallLakes); // mark small lakes let unmarked = $.grep(land, function(e) {return e.fn === -1}); From 265731c5977c75a5b20be2818b9d65d87acd03d5 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Tue, 28 Aug 2018 23:39:07 +0300 Subject: [PATCH 18/25] v. 0.59.00b --- icons.css | 1 - index.css | 79 +- index.html | 1061 +++++++++++++------------ libs/jquery-ui.css | 558 +++++++++++++ libs/jquery-ui.min.js | 16 +- libs/seedrandom.min.js | 1 + script.js | 1683 +++++++++++++++++++++++----------------- 7 files changed, 2128 insertions(+), 1271 deletions(-) create mode 100644 libs/jquery-ui.css create mode 100644 libs/seedrandom.min.js diff --git a/icons.css b/icons.css index 88ab7e4c..61b3d935 100644 --- a/icons.css +++ b/icons.css @@ -10,7 +10,6 @@ font-style: normal; font-weight: normal; speak: none; - display: inline-block; text-decoration: inherit; width: 1em; diff --git a/index.css b/index.css index 59ad26b5..e52267a2 100644 --- a/index.css +++ b/index.css @@ -293,7 +293,6 @@ text.drag { font-size: smaller; font-family: monospace; position: absolute; - background-color: rgba(168, 130, 147, 0.85); border: solid 1px #5e4fa2; } @@ -452,7 +451,7 @@ button.active { } .tabcontent button { - background-color: #997c89; + background-color: #916e7f; font-family: monospace; border: none; padding: 5px 8px; @@ -471,9 +470,13 @@ button.active { margin: 0; } +fieldset { + border: 1px solid #5d4651; +} + .tabcontent li { list-style-type: none; - background-color: #997c89; + background-color: #916e7f; cursor: pointer; padding: 5px 8px; margin: 4px; @@ -516,7 +519,7 @@ p { } #customizeOptions { - margin: 2px 0 6px 0; + margin: 2px 0; } #tooltip { @@ -524,13 +527,12 @@ p { display: none; text-align: center; top: calc(98vh - (10px + 0.5vw)); - width: 90%; - left: 5%; - cursor: default; - text-shadow: 1px 1px 3px #0e0e0e; - color: #ffffff; - font-size: calc(10px + 0.5vw); - pointer-events: none; + width: 100%; + cursor: default; + text-shadow: 1px 1px 2px #1d0e0f; + color: #ffffff; + font-size: calc(10px + 0.5vw); + pointer-events: none; } #optionsContent table td:nth-of-type(1) { @@ -538,8 +540,6 @@ p { } #optionsContent table td:nth-of-type(2) { - text-decoration: underline dotted gray; - cursor: help; width: 126px; } @@ -602,8 +602,9 @@ body button.noicon { background-image: linear-gradient(to right, #ffffff 0%, #fafafa 51%, #ebebeb 100%); margin: 1px 1px; width: 226px; - padding: 1px 2px; - font-size: 9px; + padding: 0px 2px; + height: 12px; + font-size: 10px; } #templateBody>div:hover { @@ -632,11 +633,10 @@ body button.noicon { } #templateBody input { - height: 4px; - width: 45px; - font-family: monospace; - height: 4px; - font-family: monospace; + width: 40px; + height: 10px; + border: none; + font-family: monospace; } #templateBody select { @@ -669,9 +669,9 @@ body button.noicon { border-right-color: #5e4fa2; } -#styleInputs div { +#styleInputs > div { display: none; - line-height: 6px; + line-height: 8px; } #styleInputs #styleOcean, @@ -680,7 +680,7 @@ body button.noicon { display: block; } -#styleInputs button { +#styleInputs .whiteButton { padding: 0 6px; margin: 0 2px; border: 1px #827c7f solid; @@ -692,11 +692,21 @@ body button.noicon { font-size: xx-small; } +#styleLabelGroups { + margin-top: 6px; + display: block; +} + +#styleLabelGroups button { + display: inline-block; + margin: 5px 3px 0 3px; + padding: 2px 6px; +} + .pureInput { display: inline-block; width: 50px; height: 10px; - font-size: small; font-size: smaller; font-family: monospace; } @@ -749,15 +759,6 @@ body button.noicon { stroke: #da3126; } -body .ui-dialog { - padding: 1px; - font-size: 12px; -} - -body .ui-dialog-titlebar { - font-size: 14px; -} - .ui-dialog input { height: 14px; } @@ -771,7 +772,7 @@ body .ui-dialog-titlebar { .ui-dialog input[type="range"] { outline: none; height: 2px; - background: #e9e9e9; + background: #d4d4d4; top: -4px; position: relative; appearance: none; @@ -798,6 +799,12 @@ body .ui-dialog-titlebar { cursor: pointer; } +.ui-dialog input[type="number"] { + width: 28px; + height: 12px; + cursor: pointer; +} + .ui-dialog .disabled { opacity: 0.2; } @@ -891,7 +898,7 @@ div.slider .ui-slider-handle { div.states { border: 1px solid #d4d4d4; - background-image: linear-gradient(to right, #fcfcfc 0%, #f2f2f2 51%, #dedede 100%); + background-image: linear-gradient(to right, #fafafa80 0%, #f0f0f080 50%, #c8c8c880 100%); margin: 1px 0; padding: 0 2px; font-size: 10px; @@ -899,7 +906,7 @@ div.states { div.states:hover { border: 1px solid #c4c4c4; - background-image: linear-gradient(to right, #dedede 100%, #f2f2f2 51%, #fcfcfc 0%); + background-image: linear-gradient(to right, #dedede 100%, #f2f2f2 50%, #fcfcfc 0%); } div.states * { diff --git a/index.html b/index.html index 8b989aee..f083a2e5 100644 --- a/index.html +++ b/index.html @@ -3,6 +3,7 @@ + - - - + + + @@ -201,10 +202,12 @@
  • Icons
  • - - +
    @@ -276,11 +279,11 @@
    -
    Font size: +
    Font size:
    -
    Radius: - Stroke: +
    Radius: + Stroke:

    Opacity: @@ -308,6 +311,14 @@
    +
    +
    + Label groups: + + +
    +
    +

    Toggle filters:

    @@ -356,6 +367,8 @@ + + @@ -400,7 +413,7 @@ - Neutral distance + Neutral distance @@ -408,6 +421,19 @@ 200 + + + + + Burg names style + + + + + @@ -463,6 +489,16 @@

    Generator settings:

    + + + + + + @@ -516,9 +552,11 @@ - + -
    +
    @@ -573,522 +611,521 @@
    - - - - - - - - - - -
    Transparency + + + 0 +
    PNG resolution
    "+"",P=u?"":"",w=0;7>w;w++)M=(w+c)%7,P+="";for(T+=P+"",S=this._getDaysInMonth(te,Z),te===t.selectedYear&&Z===t.selectedMonth&&(t.selectedDay=Math.min(t.selectedDay,S)),H=(this._getFirstDayOfMonth(te,Z)-c+7)%7,z=Math.ceil((H+S)/7),O=X?this.maxRows>z?this.maxRows:z:z,this.maxRows=O,A=this._daylightSavingAdjust(new Date(te,Z,1-H)),N=0;O>N;N++){for(T+="",W=u?"":"",w=0;7>w;w++)E=m?m.apply(t.input?t.input[0]:null,[A]):[!0,""],F=A.getMonth()!==Z,L=F&&!v||!E[0]||Q&&Q>A||J&&A>J,W+="",A.setDate(A.getDate()+1),A=this._daylightSavingAdjust(A);T+=W+""}Z++,Z>11&&(Z=0,te++),T+="
    "+this._get(t,"weekHeader")+"=5?" class='ui-datepicker-week-end'":"")+">"+""+p[M]+"
    "+this._get(t,"calculateWeek")(A)+""+(F&&!_?" ":L?""+A.getDate()+"":""+A.getDate()+"")+"
    "+(X?"
    "+(U[0]>0&&C===U[1]-1?"
    ":""):""),x+=T}y+=x}return y+=l,t._keyEvent=!1,y},_generateMonthYearHeader:function(t,e,i,s,n,o,a,r){var h,l,c,u,d,p,f,g,m=this._get(t,"changeMonth"),_=this._get(t,"changeYear"),v=this._get(t,"showMonthAfterYear"),b="
    ",y="";if(o||!m)y+=""+a[e]+"";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,y+=""}if(v||(b+=y+(!o&&m&&_?"":" ")),!t.yearshtml)if(t.yearshtml="",o||!_)b+=""+i+"";else{for(u=this._get(t,"yearRange").split(":"),d=(new Date).getFullYear(),p=function(t){var e=t.match(/c[+\-].*/)?i+parseInt(t.substring(1),10):t.match(/[+\-].*/)?d+parseInt(t,10):parseInt(t,10);return isNaN(e)?d:e},f=p(u[0]),g=Math.max(f,p(u[1]||"")),f=s?Math.max(f,s.getFullYear()):f,g=n?Math.min(g,n.getFullYear()):g,t.yearshtml+="",b+=t.yearshtml,t.yearshtml=null}return b+=this._get(t,"yearSuffix"),v&&(b+=(!o&&m&&_?"":" ")+y),b+="
    "},_adjustInstDate:function(t,e,i){var s=t.selectedYear+("Y"===i?e:0),n=t.selectedMonth+("M"===i?e:0),o=Math.min(t.selectedDay,this._getDaysInMonth(s,n))+("D"===i?e:0),a=this._restrictMinMax(t,this._daylightSavingAdjust(new Date(s,n,o)));t.selectedDay=a.getDate(),t.drawMonth=t.selectedMonth=a.getMonth(),t.drawYear=t.selectedYear=a.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(t)},_restrictMinMax:function(t,e){var i=this._getMinMaxDate(t,"min"),s=this._getMinMaxDate(t,"max"),n=i&&i>e?i:e;return s&&n>s?s:n},_notifyChange:function(t){var e=this._get(t,"onChangeMonthYear");e&&e.apply(t.input?t.input[0]:null,[t.selectedYear,t.selectedMonth+1,t])},_getNumberOfMonths:function(t){var e=this._get(t,"numberOfMonths");return null==e?[1,1]:"number"==typeof e?[1,e]:e},_getMinMaxDate:function(t,e){return this._determineDate(t,this._get(t,e+"Date"),null)},_getDaysInMonth:function(t,e){return 32-this._daylightSavingAdjust(new Date(t,e,32)).getDate()},_getFirstDayOfMonth:function(t,e){return new Date(t,e,1).getDay()},_canAdjustMonth:function(t,e,i,s){var n=this._getNumberOfMonths(t),o=this._daylightSavingAdjust(new Date(i,s+(0>e?e:n[0]*n[1]),1));return 0>e&&o.setDate(this._getDaysInMonth(o.getFullYear(),o.getMonth())),this._isInRange(t,o)},_isInRange:function(t,e){var i,s,n=this._getMinMaxDate(t,"min"),o=this._getMinMaxDate(t,"max"),a=null,r=null,h=this._get(t,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),a=parseInt(i[0],10),r=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(a+=s),i[1].match(/[+\-].*/)&&(r+=s)),(!n||e.getTime()>=n.getTime())&&(!o||e.getTime()<=o.getTime())&&(!a||e.getFullYear()>=a)&&(!r||r>=e.getFullYear())},_getFormatConfig:function(t){var e=this._get(t,"shortYearCutoff");return e="string"!=typeof e?e:(new Date).getFullYear()%100+parseInt(e,10),{shortYearCutoff:e,dayNamesShort:this._get(t,"dayNamesShort"),dayNames:this._get(t,"dayNames"),monthNamesShort:this._get(t,"monthNamesShort"),monthNames:this._get(t,"monthNames")}},_formatDate:function(t,e,i,s){e||(t.currentDay=t.selectedDay,t.currentMonth=t.selectedMonth,t.currentYear=t.selectedYear);var n=e?"object"==typeof e?e:this._daylightSavingAdjust(new Date(s,i,e)):this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return this.formatDate(this._get(t,"dateFormat"),n,this._getFormatConfig(t))}}),t.fn.datepicker=function(e){if(!this.length)return this;t.datepicker.initialized||(t(document).on("mousedown",t.datepicker._checkExternalClick),t.datepicker.initialized=!0),0===t("#"+t.datepicker._mainDivId).length&&t("body").append(t.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof e||"isDisabled"!==e&&"getDate"!==e&&"widget"!==e?"option"===e&&2===arguments.length&&"string"==typeof arguments[1]?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof e?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this].concat(i)):t.datepicker._attachDatepicker(this,e)}):t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i))},t.datepicker=new s,t.datepicker.initialized=!1,t.datepicker.uuid=(new Date).getTime(),t.datepicker.version="1.12.1",t.datepicker,t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var _=!1;t(document).on("mouseup",function(){_=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!_){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,s=1===e.which,n="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),_=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,_=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.ui.plugin={add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;o.length>n;n++)t.options[o[n][0]]&&o[n][1].apply(t.element,i)}},t.ui.safeBlur=function(e){e&&"body"!==e.nodeName.toLowerCase()&&t(e).trigger("blur")},t.widget("ui.draggable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"===this.options.helper&&this._setPositionRelative(),this.options.addClasses&&this._addClass("ui-draggable"),this._setHandleClassName(),this._mouseInit()},_setOption:function(t,e){this._super(t,e),"handle"===t&&(this._removeHandleClassName(),this._setHandleClassName())},_destroy:function(){return(this.helper||this.element).is(".ui-draggable-dragging")?(this.destroyOnClear=!0,void 0):(this._removeHandleClassName(),this._mouseDestroy(),void 0)},_mouseCapture:function(e){var i=this.options;return this.helper||i.disabled||t(e.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(e),this.handle?(this._blurActiveElement(e),this._blockFrames(i.iframeFix===!0?"iframe":i.iframeFix),!0):!1)},_blockFrames:function(e){this.iframeBlocks=this.document.find(e).map(function(){var e=t(this);return t("
    ").css("position","absolute").appendTo(e.parent()).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_blurActiveElement:function(e){var i=t.ui.safeActiveElement(this.document[0]),s=t(e.target);s.closest(i).length||t.ui.safeBlur(i)},_mouseStart:function(e){var i=this.options;return this.helper=this._createHelper(e),this._addClass(this.helper,"ui-draggable-dragging"),this._cacheHelperProportions(),t.ui.ddmanager&&(t.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(!0),this.offsetParent=this.helper.offsetParent(),this.hasFixedAncestor=this.helper.parents().filter(function(){return"fixed"===t(this).css("position")}).length>0,this.positionAbs=this.element.offset(),this._refreshOffsets(e),this.originalPosition=this.position=this._generatePosition(e,!1),this.originalPageX=e.pageX,this.originalPageY=e.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",e)===!1?(this._clear(),!1):(this._cacheHelperProportions(),t.ui.ddmanager&&!i.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this._mouseDrag(e,!0),t.ui.ddmanager&&t.ui.ddmanager.dragStart(this,e),!0)},_refreshOffsets:function(t){this.offset={top:this.positionAbs.top-this.margins.top,left:this.positionAbs.left-this.margins.left,scroll:!1,parent:this._getParentOffset(),relative:this._getRelativeOffset()},this.offset.click={left:t.pageX-this.offset.left,top:t.pageY-this.offset.top}},_mouseDrag:function(e,i){if(this.hasFixedAncestor&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(e,!0),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",e,s)===!1)return this._mouseUp(new t.Event("mouseup",e)),!1;this.position=s.position}return this.helper[0].style.left=this.position.left+"px",this.helper[0].style.top=this.position.top+"px",t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),!1},_mouseStop:function(e){var i=this,s=!1;return t.ui.ddmanager&&!this.options.dropBehaviour&&(s=t.ui.ddmanager.drop(this,e)),this.dropped&&(s=this.dropped,this.dropped=!1),"invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||t.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?t(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",e)!==!1&&i._clear()}):this._trigger("stop",e)!==!1&&this._clear(),!1},_mouseUp:function(e){return this._unblockFrames(),t.ui.ddmanager&&t.ui.ddmanager.dragStop(this,e),this.handleElement.is(e.target)&&this.element.trigger("focus"),t.ui.mouse.prototype._mouseUp.call(this,e)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp(new t.Event("mouseup",{target:this.element[0]})):this._clear(),this},_getHandle:function(e){return this.options.handle?!!t(e.target).closest(this.element.find(this.options.handle)).length:!0},_setHandleClassName:function(){this.handleElement=this.options.handle?this.element.find(this.options.handle):this.element,this._addClass(this.handleElement,"ui-draggable-handle")},_removeHandleClassName:function(){this._removeClass(this.handleElement,"ui-draggable-handle")},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper),n=s?t(i.helper.apply(this.element[0],[e])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return n.parents("body").length||n.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s&&n[0]===this.element[0]&&this._setPositionRelative(),n[0]===this.element[0]||/(fixed|absolute)/.test(n.css("position"))||n.css("position","absolute"),n},_setPositionRelative:function(){/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative")},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_isRootNode:function(t){return/(html|body)/i.test(t.tagName)||t===this.document[0]},_getParentOffset:function(){var e=this.offsetParent.offset(),i=this.document[0];return"absolute"===this.cssPosition&&this.scrollParent[0]!==i&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),this._isRootNode(this.offsetParent[0])&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"!==this.cssPosition)return{top:0,left:0};var t=this.element.position(),e=this._isRootNode(this.scrollParent[0]);return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+(e?0:this.scrollParent.scrollTop()),left:t.left-(parseInt(this.helper.css("left"),10)||0)+(e?0:this.scrollParent.scrollLeft())} -},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options,o=this.document[0];return this.relativeContainer=null,n.containment?"window"===n.containment?(this.containment=[t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,t(window).scrollLeft()+t(window).width()-this.helperProportions.width-this.margins.left,t(window).scrollTop()+(t(window).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===n.containment?(this.containment=[0,0,t(o).width()-this.helperProportions.width-this.margins.left,(t(o).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):n.containment.constructor===Array?(this.containment=n.containment,void 0):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=t(n.containment),s=i[0],s&&(e=/(scroll|auto)/.test(i.css("overflow")),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relativeContainer=i),void 0):(this.containment=null,void 0)},_convertPositionTo:function(t,e){e||(e=this.position);var i="absolute"===t?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:e.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:e.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(t,e){var i,s,n,o,a=this.options,r=this._isRootNode(this.scrollParent[0]),h=t.pageX,l=t.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),e&&(this.containment&&(this.relativeContainer?(s=this.relativeContainer.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,t.pageX-this.offset.click.lefti[2]&&(h=i[2]+this.offset.click.left),t.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),a.grid&&(n=a.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/a.grid[1])*a.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-a.grid[1]:n+a.grid[1]:n,o=a.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/a.grid[0])*a.grid[0]:this.originalPageX,h=i?o-this.offset.click.left>=i[0]||o-this.offset.click.left>i[2]?o:o-this.offset.click.left>=i[0]?o-a.grid[0]:o+a.grid[0]:o),"y"===a.axis&&(h=this.originalPageX),"x"===a.axis&&(l=this.originalPageY)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)}},_clear:function(){this._removeClass(this.helper,"ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s,this],!0),/^(drag|start|stop)/.test(e)&&(this.positionAbs=this._convertPositionTo("absolute"),s.offset=this.positionAbs),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i,s){var n=t.extend({},i,{item:s.element});s.sortables=[],t(s.options.connectToSortable).each(function(){var i=t(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push(i),i.refreshPositions(),i._trigger("activate",e,n))})},stop:function(e,i,s){var n=t.extend({},i,{item:s.element});s.cancelHelperRemoval=!1,t.each(s.sortables,function(){var t=this;t.isOver?(t.isOver=0,s.cancelHelperRemoval=!0,t.cancelHelperRemoval=!1,t._storedCSS={position:t.placeholder.css("position"),top:t.placeholder.css("top"),left:t.placeholder.css("left")},t._mouseStop(e),t.options.helper=t.options._helper):(t.cancelHelperRemoval=!0,t._trigger("deactivate",e,n))})},drag:function(e,i,s){t.each(s.sortables,function(){var n=!1,o=this;o.positionAbs=s.positionAbs,o.helperProportions=s.helperProportions,o.offset.click=s.offset.click,o._intersectsWith(o.containerCache)&&(n=!0,t.each(s.sortables,function(){return this.positionAbs=s.positionAbs,this.helperProportions=s.helperProportions,this.offset.click=s.offset.click,this!==o&&this._intersectsWith(this.containerCache)&&t.contains(o.element[0],this.element[0])&&(n=!1),n})),n?(o.isOver||(o.isOver=1,s._parent=i.helper.parent(),o.currentItem=i.helper.appendTo(o.element).data("ui-sortable-item",!0),o.options._helper=o.options.helper,o.options.helper=function(){return i.helper[0]},e.target=o.currentItem[0],o._mouseCapture(e,!0),o._mouseStart(e,!0,!0),o.offset.click.top=s.offset.click.top,o.offset.click.left=s.offset.click.left,o.offset.parent.left-=s.offset.parent.left-o.offset.parent.left,o.offset.parent.top-=s.offset.parent.top-o.offset.parent.top,s._trigger("toSortable",e),s.dropped=o.element,t.each(s.sortables,function(){this.refreshPositions()}),s.currentItem=s.element,o.fromOutside=s),o.currentItem&&(o._mouseDrag(e),i.position=o.position)):o.isOver&&(o.isOver=0,o.cancelHelperRemoval=!0,o.options._revert=o.options.revert,o.options.revert=!1,o._trigger("out",e,o._uiHash(o)),o._mouseStop(e,!0),o.options.revert=o.options._revert,o.options.helper=o.options._helper,o.placeholder&&o.placeholder.remove(),i.helper.appendTo(s._parent),s._refreshOffsets(e),i.position=s._generatePosition(e,!0),s._trigger("fromSortable",e),s.dropped=!1,t.each(s.sortables,function(){this.refreshPositions()}))})}}),t.ui.plugin.add("draggable","cursor",{start:function(e,i,s){var n=t("body"),o=s.options;n.css("cursor")&&(o._cursor=n.css("cursor")),n.css("cursor",o.cursor)},stop:function(e,i,s){var n=s.options;n._cursor&&t("body").css("cursor",n._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("opacity")&&(o._opacity=n.css("opacity")),n.css("opacity",o.opacity)},stop:function(e,i,s){var n=s.options;n._opacity&&t(i.helper).css("opacity",n._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(t,e,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(e,i,s){var n=s.options,o=!1,a=s.scrollParentNotHidden[0],r=s.document[0];a!==r&&"HTML"!==a.tagName?(n.axis&&"x"===n.axis||(s.overflowOffset.top+a.offsetHeight-e.pageY=0;d--)h=s.snapElements[d].left-s.margins.left,l=h+s.snapElements[d].width,c=s.snapElements[d].top-s.margins.top,u=c+s.snapElements[d].height,h-g>_||m>l+g||c-g>b||v>u+g||!t.contains(s.snapElements[d].item.ownerDocument,s.snapElements[d].item)?(s.snapElements[d].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=!1):("inner"!==f.snapMode&&(n=g>=Math.abs(c-b),o=g>=Math.abs(u-v),a=g>=Math.abs(h-_),r=g>=Math.abs(l-m),n&&(i.position.top=s._convertPositionTo("relative",{top:c-s.helperProportions.height,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left)),p=n||o||a||r,"outer"!==f.snapMode&&(n=g>=Math.abs(c-v),o=g>=Math.abs(u-b),a=g>=Math.abs(h-m),r=g>=Math.abs(l-_),n&&(i.position.top=s._convertPositionTo("relative",{top:c,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left)),!s.snapElements[d].snapping&&(n||o||a||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=n||o||a||r||p)}}),t.ui.plugin.add("draggable","stack",{start:function(e,i,s){var n,o=s.options,a=t.makeArray(t(o.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});a.length&&(n=parseInt(t(a[0]).css("zIndex"),10)||0,t(a).each(function(e){t(this).css("zIndex",n+e)}),this.css("zIndex",n+a.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("zIndex")&&(o._zIndex=n.css("zIndex")),n.css("zIndex",o.zIndex)},stop:function(e,i,s){var n=s.options;n._zIndex&&t(i.helper).css("zIndex",n._zIndex)}}),t.ui.draggable,t.widget("ui.resizable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,classes:{"ui-resizable-se":"ui-icon ui-icon-gripsmall-diagonal-se"},containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(t){return parseFloat(t)||0},_isNumber:function(t){return!isNaN(parseFloat(t))},_hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)},_create:function(){var e,i=this.options,s=this;this._addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!i.aspectRatio,aspectRatio:i.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:i.helper||i.ghost||i.animate?i.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(t("
    ").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,e={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(e),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(e),this._proportionallyResize()),this._setupHandles(),i.autoHide&&t(this.element).on("mouseenter",function(){i.disabled||(s._removeClass("ui-resizable-autohide"),s._handles.show())}).on("mouseleave",function(){i.disabled||s.resizing||(s._addClass("ui-resizable-autohide"),s._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;default:}},_setupHandles:function(){var e,i,s,n,o,a=this.options,r=this;if(this.handles=a.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=t(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),s=this.handles.split(","),this.handles={},i=0;s.length>i;i++)e=t.trim(s[i]),n="ui-resizable-"+e,o=t("
    "),this._addClass(o,"ui-resizable-handle "+n),o.css({zIndex:a.zIndex}),this.handles[e]=".ui-resizable-"+e,this.element.append(o);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=t(this.handles[i]),this._on(this.handles[i],{mousedown:r._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){r.resizing||(this.className&&(o=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),r.axis=o&&o[1]?o[1]:"se")}),a.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(e){var i,s,n,o=this.options,a=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),o.containment&&(i+=t(o.containment).scrollLeft()||0,s+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:a.width(),height:a.height()},this.originalSize=this._helper?{width:a.outerWidth(),height:a.outerHeight()}:{width:a.width(),height:a.height()},this.sizeDiff={width:a.outerWidth()-a.width(),height:a.outerHeight()-a.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:e.pageX,top:e.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===n?this.axis+"-resize":n),this._addClass("ui-resizable-resizing"),this._propagate("start",e),!0},_mouseDrag:function(e){var i,s,n=this.originalMousePosition,o=this.axis,a=e.pageX-n.left||0,r=e.pageY-n.top||0,h=this._change[o];return this._updatePrevProperties(),h?(i=h.apply(this,[e,a,r]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",e,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseFloat(c.element.css("left"))+(c.position.left-c.originalPosition.left)||null,h=parseFloat(c.element.css("top"))+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s,n,o,a=this.options;o={minWidth:this._isNumber(a.minWidth)?a.minWidth:0,maxWidth:this._isNumber(a.maxWidth)?a.maxWidth:1/0,minHeight:this._isNumber(a.minHeight)?a.minHeight:0,maxHeight:this._isNumber(a.maxHeight)?a.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,s=o.minWidth/this.aspectRatio,i=o.maxHeight*this.aspectRatio,n=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),s>o.minHeight&&(o.minHeight=s),o.maxWidth>i&&(o.maxWidth=i),o.maxHeight>n&&(o.maxHeight=n)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),this._isNumber(t.left)&&(this.position.left=t.left),this._isNumber(t.top)&&(this.position.top=t.top),this._isNumber(t.height)&&(this.size.height=t.height),this._isNumber(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,i=this.size,s=this.axis;return this._isNumber(t.height)?t.width=t.height*this.aspectRatio:this._isNumber(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===s&&(t.left=e.left+(i.width-t.width),t.top=null),"nw"===s&&(t.top=e.top+(i.height-t.height),t.left=e.left+(i.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,i=this.axis,s=this._isNumber(t.width)&&e.maxWidth&&e.maxWidtht.width,a=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,r=this.originalPosition.left+this.originalSize.width,h=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),c=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),a&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=r-e.minWidth),s&&l&&(t.left=r-e.maxWidth),a&&c&&(t.top=h-e.minHeight),n&&c&&(t.top=h-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];4>e;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;this._proportionallyResizeElements.length>e;e++)t=this._proportionallyResizeElements[e],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(t)),t.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
    "),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,c=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var e,i,s,n,o,a,r,h=t(this).resizable("instance"),l=h.options,c=h.element,u=l.containment,d=u instanceof t?u.get(0):/parent/.test(u)?c.parent().get(0):u;d&&(h.containerElement=t(d),/document/.test(u)||u===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(e=t(d),i=[],t(["Top","Right","Left","Bottom"]).each(function(t,s){i[t]=h._num(e.css("padding"+s))}),h.containerOffset=e.offset(),h.containerPosition=e.position(),h.containerSize={height:e.innerHeight()-i[3],width:e.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,o=h.containerSize.width,a=h._hasScroll(d,"left")?d.scrollWidth:o,r=h._hasScroll(d)?d.scrollHeight:n,h.parentData={element:d,left:s.left,top:s.top,width:a,height:r}))},resize:function(e){var i,s,n,o,a=t(this).resizable("instance"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement,p=!0;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio,p=!1),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio,p=!1),a.position.top=a._helper?h.top:0),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o?(a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top):(a.offset.left=a.element.offset().left,a.offset.top=a.element.offset().top),i=Math.abs(a.sizeDiff.width+(a._helper?a.offset.left-u.left:a.offset.left-h.left)),s=Math.abs(a.sizeDiff.height+(a._helper?a.offset.top-u.top:a.offset.top-h.top)),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio,p=!1)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio,p=!1)),p||(a.position.left=a.prevPosition.left,a.position.top=a.prevPosition.top,a.size.width=a.prevSize.width,a.size.height=a.prevSize.height)},stop:function(){var e=t(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).resizable("instance"),i=e.options;t(i.alsoResize).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseFloat(e.width()),height:parseFloat(e.height()),left:parseFloat(e.css("left")),top:parseFloat(e.css("top"))})})},resize:function(e,i){var s=t(this).resizable("instance"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0};t(n.alsoResize).each(function(){var e=t(this),s=t(this).data("ui-resizable-alsoresize"),n={},o=e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&i>=0&&(n[e]=i||null)}),e.css(n)})},stop:function(){t(this).removeData("ui-resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).resizable("instance"),i=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:i.height,width:i.width,margin:0,left:0,top:0}),e._addClass(e.ghost,"ui-resizable-ghost"),t.uiBackCompat!==!1&&"string"==typeof e.options.ghost&&e.ghost.addClass(this.options.ghost),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).resizable("instance");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).resizable("instance");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e,i=t(this).resizable("instance"),s=i.options,n=i.size,o=i.originalSize,a=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,c=h[1]||1,u=Math.round((n.width-o.width)/l)*l,d=Math.round((n.height-o.height)/c)*c,p=o.width+u,f=o.height+d,g=s.maxWidth&&p>s.maxWidth,m=s.maxHeight&&f>s.maxHeight,_=s.minWidth&&s.minWidth>p,v=s.minHeight&&s.minHeight>f;s.grid=h,_&&(p+=l),v&&(f+=c),g&&(p-=l),m&&(f-=c),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=a.top-d):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=a.left-u):((0>=f-c||0>=p-l)&&(e=i._getPaddingPlusBorderDimensions(this)),f-c>0?(i.size.height=f,i.position.top=a.top-d):(f=c-e.height,i.size.height=f,i.position.top=a.top+o.height-f),p-l>0?(i.size.width=p,i.position.left=a.left-u):(p=l-e.width,i.size.width=p,i.position.left=a.left+o.width-p))}}),t.ui.resizable,t.widget("ui.dialog",{version:"1.12.1",options:{appendTo:"body",autoOpen:!0,buttons:[],classes:{"ui-dialog":"ui-corner-all","ui-dialog-titlebar":"ui-corner-all"},closeOnEscape:!0,closeText:"Close",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(e){var i=t(this).css(e).offset().top;0>i&&t(this).css("top",e.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},sizeRelatedOptions:{buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},resizableRelatedOptions:{maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),null==this.options.title&&null!=this.originalTitle&&(this.options.title=this.originalTitle),this.options.disabled&&(this.options.disabled=!1),this._createWrapper(),this.element.show().removeAttr("title").appendTo(this.uiDialog),this._addClass("ui-dialog-content","ui-widget-content"),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&t.fn.draggable&&this._makeDraggable(),this.options.resizable&&t.fn.resizable&&this._makeResizable(),this._isOpen=!1,this._trackFocus()},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var e=this.options.appendTo;return e&&(e.jquery||e.nodeType)?t(e):this.document.find(e||"body").eq(0)},_destroy:function(){var t,e=this.originalPosition;this._untrackInstance(),this._destroyOverlay(),this.element.removeUniqueId().css(this.originalCss).detach(),this.uiDialog.remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),t=e.parent.children().eq(e.index),t.length&&t[0]!==this.element[0]?t.before(this.element):e.parent.append(this.element)},widget:function(){return this.uiDialog -},disable:t.noop,enable:t.noop,close:function(e){var i=this;this._isOpen&&this._trigger("beforeClose",e)!==!1&&(this._isOpen=!1,this._focusedElement=null,this._destroyOverlay(),this._untrackInstance(),this.opener.filter(":focusable").trigger("focus").length||t.ui.safeBlur(t.ui.safeActiveElement(this.document[0])),this._hide(this.uiDialog,this.options.hide,function(){i._trigger("close",e)}))},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(e,i){var s=!1,n=this.uiDialog.siblings(".ui-front:visible").map(function(){return+t(this).css("z-index")}).get(),o=Math.max.apply(null,n);return o>=+this.uiDialog.css("z-index")&&(this.uiDialog.css("z-index",o+1),s=!0),s&&!i&&this._trigger("focus",e),s},open:function(){var e=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),void 0):(this._isOpen=!0,this.opener=t(t.ui.safeActiveElement(this.document[0])),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this.overlay&&this.overlay.css("z-index",this.uiDialog.css("z-index")-1),this._show(this.uiDialog,this.options.show,function(){e._focusTabbable(),e._trigger("focus")}),this._makeFocusTarget(),this._trigger("open"),void 0)},_focusTabbable:function(){var t=this._focusedElement;t||(t=this.element.find("[autofocus]")),t.length||(t=this.element.find(":tabbable")),t.length||(t=this.uiDialogButtonPane.find(":tabbable")),t.length||(t=this.uiDialogTitlebarClose.filter(":tabbable")),t.length||(t=this.uiDialog),t.eq(0).trigger("focus")},_keepFocus:function(e){function i(){var e=t.ui.safeActiveElement(this.document[0]),i=this.uiDialog[0]===e||t.contains(this.uiDialog[0],e);i||this._focusTabbable()}e.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=t("
    ").hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._addClass(this.uiDialog,"ui-dialog","ui-widget ui-widget-content ui-front"),this._on(this.uiDialog,{keydown:function(e){if(this.options.closeOnEscape&&!e.isDefaultPrevented()&&e.keyCode&&e.keyCode===t.ui.keyCode.ESCAPE)return e.preventDefault(),this.close(e),void 0;if(e.keyCode===t.ui.keyCode.TAB&&!e.isDefaultPrevented()){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");e.target!==n[0]&&e.target!==this.uiDialog[0]||e.shiftKey?e.target!==s[0]&&e.target!==this.uiDialog[0]||!e.shiftKey||(this._delay(function(){n.trigger("focus")}),e.preventDefault()):(this._delay(function(){s.trigger("focus")}),e.preventDefault())}},mousedown:function(t){this._moveToTop(t)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var e;this.uiDialogTitlebar=t("
    "),this._addClass(this.uiDialogTitlebar,"ui-dialog-titlebar","ui-widget-header ui-helper-clearfix"),this._on(this.uiDialogTitlebar,{mousedown:function(e){t(e.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.trigger("focus")}}),this.uiDialogTitlebarClose=t("").button({label:t("").text(this.options.closeText).html(),icon:"ui-icon-closethick",showLabel:!1}).appendTo(this.uiDialogTitlebar),this._addClass(this.uiDialogTitlebarClose,"ui-dialog-titlebar-close"),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),e=t("").uniqueId().prependTo(this.uiDialogTitlebar),this._addClass(e,"ui-dialog-title"),this._title(e),this.uiDialogTitlebar.prependTo(this.uiDialog),this.uiDialog.attr({"aria-labelledby":e.attr("id")})},_title:function(t){this.options.title?t.text(this.options.title):t.html(" ")},_createButtonPane:function(){this.uiDialogButtonPane=t("
    "),this._addClass(this.uiDialogButtonPane,"ui-dialog-buttonpane","ui-widget-content ui-helper-clearfix"),this.uiButtonSet=t("
    ").appendTo(this.uiDialogButtonPane),this._addClass(this.uiButtonSet,"ui-dialog-buttonset"),this._createButtons()},_createButtons:function(){var e=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),t.isEmptyObject(i)||t.isArray(i)&&!i.length?(this._removeClass(this.uiDialog,"ui-dialog-buttons"),void 0):(t.each(i,function(i,s){var n,o;s=t.isFunction(s)?{click:s,text:i}:s,s=t.extend({type:"button"},s),n=s.click,o={icon:s.icon,iconPosition:s.iconPosition,showLabel:s.showLabel,icons:s.icons,text:s.text},delete s.click,delete s.icon,delete s.iconPosition,delete s.showLabel,delete s.icons,"boolean"==typeof s.text&&delete s.text,t("",s).button(o).appendTo(e.uiButtonSet).on("click",function(){n.apply(e.element[0],arguments)})}),this._addClass(this.uiDialog,"ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),void 0)},_makeDraggable:function(){function e(t){return{position:t.position,offset:t.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){i._addClass(t(this),"ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,e(n))},drag:function(t,s){i._trigger("drag",t,e(s))},stop:function(n,o){var a=o.offset.left-i.document.scrollLeft(),r=o.offset.top-i.document.scrollTop();s.position={my:"left top",at:"left"+(a>=0?"+":"")+a+" "+"top"+(r>=0?"+":"")+r,of:i.window},i._removeClass(t(this),"ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,e(o))}})},_makeResizable:function(){function e(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}var i=this,s=this.options,n=s.resizable,o=this.uiDialog.css("position"),a="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:a,start:function(s,n){i._addClass(t(this),"ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,e(n))},resize:function(t,s){i._trigger("resize",t,e(s))},stop:function(n,o){var a=i.uiDialog.offset(),r=a.left-i.document.scrollLeft(),h=a.top-i.document.scrollTop();s.height=i.uiDialog.height(),s.width=i.uiDialog.width(),s.position={my:"left top",at:"left"+(r>=0?"+":"")+r+" "+"top"+(h>=0?"+":"")+h,of:i.window},i._removeClass(t(this),"ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,e(o))}}).css("position",o)},_trackFocus:function(){this._on(this.widget(),{focusin:function(e){this._makeFocusTarget(),this._focusedElement=t(e.target)}})},_makeFocusTarget:function(){this._untrackInstance(),this._trackingInstances().unshift(this)},_untrackInstance:function(){var e=this._trackingInstances(),i=t.inArray(this,e);-1!==i&&e.splice(i,1)},_trackingInstances:function(){var t=this.document.data("ui-dialog-instances");return t||(t=[],this.document.data("ui-dialog-instances",t)),t},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(e){var i=this,s=!1,n={};t.each(e,function(t,e){i._setOption(t,e),t in i.sizeRelatedOptions&&(s=!0),t in i.resizableRelatedOptions&&(n[t]=e)}),s&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",n)},_setOption:function(e,i){var s,n,o=this.uiDialog;"disabled"!==e&&(this._super(e,i),"appendTo"===e&&this.uiDialog.appendTo(this._appendTo()),"buttons"===e&&this._createButtons(),"closeText"===e&&this.uiDialogTitlebarClose.button({label:t("").text(""+this.options.closeText).html()}),"draggable"===e&&(s=o.is(":data(ui-draggable)"),s&&!i&&o.draggable("destroy"),!s&&i&&this._makeDraggable()),"position"===e&&this._position(),"resizable"===e&&(n=o.is(":data(ui-resizable)"),n&&!i&&o.resizable("destroy"),n&&"string"==typeof i&&o.resizable("option","handles",i),n||i===!1||this._makeResizable()),"title"===e&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var e=t(this);return t("
    ").css({position:"absolute",width:e.outerWidth(),height:e.outerHeight()}).appendTo(e.parent()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(e){return t(e.target).closest(".ui-dialog").length?!0:!!t(e.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var e=!0;this._delay(function(){e=!1}),this.document.data("ui-dialog-overlays")||this._on(this.document,{focusin:function(t){e||this._allowInteraction(t)||(t.preventDefault(),this._trackingInstances()[0]._focusTabbable())}}),this.overlay=t("
    ").appendTo(this._appendTo()),this._addClass(this.overlay,null,"ui-widget-overlay ui-front"),this._on(this.overlay,{mousedown:"_keepFocus"}),this.document.data("ui-dialog-overlays",(this.document.data("ui-dialog-overlays")||0)+1)}},_destroyOverlay:function(){if(this.options.modal&&this.overlay){var t=this.document.data("ui-dialog-overlays")-1;t?this.document.data("ui-dialog-overlays",t):(this._off(this.document,"focusin"),this.document.removeData("ui-dialog-overlays")),this.overlay.remove(),this.overlay=null}}}),t.uiBackCompat!==!1&&t.widget("ui.dialog",t.ui.dialog,{options:{dialogClass:""},_createWrapper:function(){this._super(),this.uiDialog.addClass(this.options.dialogClass)},_setOption:function(t,e){"dialogClass"===t&&this.uiDialog.removeClass(this.options.dialogClass).addClass(e),this._superApply(arguments)}}),t.ui.dialog,t.widget("ui.droppable",{version:"1.12.1",widgetEventPrefix:"drop",options:{accept:"*",addClasses:!0,greedy:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var e,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=t.isFunction(s)?s:function(t){return t.is(s)},this.proportions=function(){return arguments.length?(e=arguments[0],void 0):e?e:e={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},this._addToManager(i.scope),i.addClasses&&this._addClass("ui-droppable")},_addToManager:function(e){t.ui.ddmanager.droppables[e]=t.ui.ddmanager.droppables[e]||[],t.ui.ddmanager.droppables[e].push(this)},_splice:function(t){for(var e=0;t.length>e;e++)t[e]===this&&t.splice(e,1)},_destroy:function(){var e=t.ui.ddmanager.droppables[this.options.scope];this._splice(e)},_setOption:function(e,i){if("accept"===e)this.accept=t.isFunction(i)?i:function(t){return t.is(i)};else if("scope"===e){var s=t.ui.ddmanager.droppables[this.options.scope];this._splice(s),this._addToManager(i)}this._super(e,i)},_activate:function(e){var i=t.ui.ddmanager.current;this._addActiveClass(),i&&this._trigger("activate",e,this.ui(i))},_deactivate:function(e){var i=t.ui.ddmanager.current;this._removeActiveClass(),i&&this._trigger("deactivate",e,this.ui(i))},_over:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this._addHoverClass(),this._trigger("over",e,this.ui(i)))},_out:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this._removeHoverClass(),this._trigger("out",e,this.ui(i)))},_drop:function(e,i){var s=i||t.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var i=t(this).droppable("instance");return i.options.greedy&&!i.options.disabled&&i.options.scope===s.options.scope&&i.accept.call(i.element[0],s.currentItem||s.element)&&v(s,t.extend(i,{offset:i.element.offset()}),i.options.tolerance,e)?(n=!0,!1):void 0}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this._removeActiveClass(),this._removeHoverClass(),this._trigger("drop",e,this.ui(s)),this.element):!1):!1},ui:function(t){return{draggable:t.currentItem||t.element,helper:t.helper,position:t.position,offset:t.positionAbs}},_addHoverClass:function(){this._addClass("ui-droppable-hover")},_removeHoverClass:function(){this._removeClass("ui-droppable-hover")},_addActiveClass:function(){this._addClass("ui-droppable-active")},_removeActiveClass:function(){this._removeClass("ui-droppable-active")}});var v=t.ui.intersect=function(){function t(t,e,i){return t>=e&&e+i>t}return function(e,i,s,n){if(!i.offset)return!1;var o=(e.positionAbs||e.position.absolute).left+e.margins.left,a=(e.positionAbs||e.position.absolute).top+e.margins.top,r=o+e.helperProportions.width,h=a+e.helperProportions.height,l=i.offset.left,c=i.offset.top,u=l+i.proportions().width,d=c+i.proportions().height;switch(s){case"fit":return o>=l&&u>=r&&a>=c&&d>=h;case"intersect":return o+e.helperProportions.width/2>l&&u>r-e.helperProportions.width/2&&a+e.helperProportions.height/2>c&&d>h-e.helperProportions.height/2;case"pointer":return t(n.pageY,c,i.proportions().height)&&t(n.pageX,l,i.proportions().width);case"touch":return(a>=c&&d>=a||h>=c&&d>=h||c>a&&h>d)&&(o>=l&&u>=o||r>=l&&u>=r||l>o&&r>u);default:return!1}}}();t.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,i){var s,n,o=t.ui.ddmanager.droppables[e.options.scope]||[],a=i?i.type:null,r=(e.currentItem||e.element).find(":data(ui-droppable)").addBack();t:for(s=0;o.length>s;s++)if(!(o[s].options.disabled||e&&!o[s].accept.call(o[s].element[0],e.currentItem||e.element))){for(n=0;r.length>n;n++)if(r[n]===o[s].element[0]){o[s].proportions().height=0;continue t}o[s].visible="none"!==o[s].element.css("display"),o[s].visible&&("mousedown"===a&&o[s]._activate.call(o[s],i),o[s].offset=o[s].element.offset(),o[s].proportions({width:o[s].element[0].offsetWidth,height:o[s].element[0].offsetHeight}))}},drop:function(e,i){var s=!1;return t.each((t.ui.ddmanager.droppables[e.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&v(e,this,this.options.tolerance,i)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],e.currentItem||e.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(e,i){e.element.parentsUntil("body").on("scroll.droppable",function(){e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)})},drag:function(e,i){e.options.refreshPositions&&t.ui.ddmanager.prepareOffsets(e,i),t.each(t.ui.ddmanager.droppables[e.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,o,a=v(e,this,this.options.tolerance,i),r=!a&&this.isover?"isout":a&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,o=this.element.parents(":data(ui-droppable)").filter(function(){return t(this).droppable("instance").options.scope===n}),o.length&&(s=t(o[0]).droppable("instance"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(e,i){e.element.parentsUntil("body").off("scroll.droppable"),e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)}},t.uiBackCompat!==!1&&t.widget("ui.droppable",t.ui.droppable,{options:{hoverClass:!1,activeClass:!1},_addActiveClass:function(){this._super(),this.options.activeClass&&this.element.addClass(this.options.activeClass)},_removeActiveClass:function(){this._super(),this.options.activeClass&&this.element.removeClass(this.options.activeClass)},_addHoverClass:function(){this._super(),this.options.hoverClass&&this.element.addClass(this.options.hoverClass)},_removeHoverClass:function(){this._super(),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass)}}),t.ui.droppable,t.widget("ui.progressbar",{version:"1.12.1",options:{classes:{"ui-progressbar":"ui-corner-all","ui-progressbar-value":"ui-corner-left","ui-progressbar-complete":"ui-corner-right"},max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.attr({role:"progressbar","aria-valuemin":this.min}),this._addClass("ui-progressbar","ui-widget ui-widget-content"),this.valueDiv=t("
    ").appendTo(this.element),this._addClass(this.valueDiv,"ui-progressbar-value","ui-widget-header"),this._refreshValue()},_destroy:function(){this.element.removeAttr("role aria-valuemin aria-valuemax aria-valuenow"),this.valueDiv.remove()},value:function(t){return void 0===t?this.options.value:(this.options.value=this._constrainedValue(t),this._refreshValue(),void 0)},_constrainedValue:function(t){return void 0===t&&(t=this.options.value),this.indeterminate=t===!1,"number"!=typeof t&&(t=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t),this._toggleClass(null,"ui-state-disabled",!!t)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var e=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||e>this.min).width(i.toFixed(0)+"%"),this._toggleClass(this.valueDiv,"ui-progressbar-complete",null,e===this.options.max)._toggleClass("ui-progressbar-indeterminate",null,this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=t("
    ").appendTo(this.valueDiv),this._addClass(this.overlayDiv,"ui-progressbar-overlay"))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":e}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),e===this.options.max&&this._trigger("complete")}}),t.widget("ui.selectable",t.ui.mouse,{version:"1.12.1",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var e=this;this._addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){e.elementPos=t(e.element[0]).offset(),e.selectees=t(e.options.filter,e.element[0]),e._addClass(e.selectees,"ui-selectee"),e.selectees.each(function(){var i=t(this),s=i.offset(),n={left:s.left-e.elementPos.left,top:s.top-e.elementPos.top};t.data(this,"selectable-item",{element:this,$element:i,left:n.left,top:n.top,right:n.left+i.outerWidth(),bottom:n.top+i.outerHeight(),startselected:!1,selected:i.hasClass("ui-selected"),selecting:i.hasClass("ui-selecting"),unselecting:i.hasClass("ui-unselecting")})})},this.refresh(),this._mouseInit(),this.helper=t("
    "),this._addClass(this.helper,"ui-selectable-helper")},_destroy:function(){this.selectees.removeData("selectable-item"),this._mouseDestroy()},_mouseStart:function(e){var i=this,s=this.options;this.opos=[e.pageX,e.pageY],this.elementPos=t(this.element[0]).offset(),this.options.disabled||(this.selectees=t(s.filter,this.element[0]),this._trigger("start",e),t(s.appendTo).append(this.helper),this.helper.css({left:e.pageX,top:e.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=t.data(this,"selectable-item");s.startselected=!0,e.metaKey||e.ctrlKey||(i._removeClass(s.$element,"ui-selected"),s.selected=!1,i._addClass(s.$element,"ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",e,{unselecting:s.element}))}),t(e.target).parents().addBack().each(function(){var s,n=t.data(this,"selectable-item");return n?(s=!e.metaKey&&!e.ctrlKey||!n.$element.hasClass("ui-selected"),i._removeClass(n.$element,s?"ui-unselecting":"ui-selected")._addClass(n.$element,s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",e,{selecting:n.element}):i._trigger("unselecting",e,{unselecting:n.element}),!1):void 0}))},_mouseDrag:function(e){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,o=this.opos[0],a=this.opos[1],r=e.pageX,h=e.pageY;return o>r&&(i=r,r=o,o=i),a>h&&(i=h,h=a,a=i),this.helper.css({left:o,top:a,width:r-o,height:h-a}),this.selectees.each(function(){var i=t.data(this,"selectable-item"),l=!1,c={};i&&i.element!==s.element[0]&&(c.left=i.left+s.elementPos.left,c.right=i.right+s.elementPos.left,c.top=i.top+s.elementPos.top,c.bottom=i.bottom+s.elementPos.top,"touch"===n.tolerance?l=!(c.left>r||o>c.right||c.top>h||a>c.bottom):"fit"===n.tolerance&&(l=c.left>o&&r>c.right&&c.top>a&&h>c.bottom),l?(i.selected&&(s._removeClass(i.$element,"ui-selected"),i.selected=!1),i.unselecting&&(s._removeClass(i.$element,"ui-unselecting"),i.unselecting=!1),i.selecting||(s._addClass(i.$element,"ui-selecting"),i.selecting=!0,s._trigger("selecting",e,{selecting:i.element}))):(i.selecting&&((e.metaKey||e.ctrlKey)&&i.startselected?(s._removeClass(i.$element,"ui-selecting"),i.selecting=!1,s._addClass(i.$element,"ui-selected"),i.selected=!0):(s._removeClass(i.$element,"ui-selecting"),i.selecting=!1,i.startselected&&(s._addClass(i.$element,"ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",e,{unselecting:i.element}))),i.selected&&(e.metaKey||e.ctrlKey||i.startselected||(s._removeClass(i.$element,"ui-selected"),i.selected=!1,s._addClass(i.$element,"ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",e,{unselecting:i.element})))))}),!1}},_mouseStop:function(e){var i=this;return this.dragged=!1,t(".ui-unselecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");i._removeClass(s.$element,"ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",e,{unselected:s.element})}),t(".ui-selecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");i._removeClass(s.$element,"ui-selecting")._addClass(s.$element,"ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",e,{selected:s.element})}),this._trigger("stop",e),this.helper.remove(),!1}}),t.widget("ui.selectmenu",[t.ui.formResetMixin,{version:"1.12.1",defaultElement:"",widgetEventPrefix:"spin",options:{classes:{"ui-spinner":"ui-corner-all","ui-spinner-down":"ui-corner-br","ui-spinner-up":"ui-corner-tr"},culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e=this._super(),i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);null!=n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var e=this.element[0]===t.ui.safeActiveElement(this.document[0]);e||(this.element.trigger("focus"),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===t.ui.safeActiveElement(this.document[0])?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap("").parent().append("")},_draw:function(){this._enhance(),this._addClass(this.uiSpinner,"ui-spinner","ui-widget ui-widget-content"),this._addClass("ui-spinner-input"),this.element.attr("role","spinbutton"),this.buttons=this.uiSpinner.children("a").attr("tabIndex",-1).attr("aria-hidden",!0).button({classes:{"ui-button":""}}),this._removeClass(this.buttons,"ui-corner-all"),this._addClass(this.buttons.first(),"ui-spinner-button ui-spinner-up"),this._addClass(this.buttons.last(),"ui-spinner-button ui-spinner-down"),this.buttons.first().button({icon:this.options.icons.up,showLabel:!1}),this.buttons.last().button({icon:this.options.icons.down,showLabel:!1}),this.buttons.height()>Math.ceil(.5*this.uiSpinner.height())&&this.uiSpinner.height()>0&&this.uiSpinner.height(this.uiSpinner.height())},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){var i,s,n;return"culture"===t||"numberFormat"===t?(i=this._parse(this.element.val()),this.options[t]=e,this.element.val(this._format(i)),void 0):(("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(s=this.buttons.first().find(".ui-icon"),this._removeClass(s,null,this.options.icons.up),this._addClass(s,null,e.up),n=this.buttons.last().find(".ui-icon"),this._removeClass(n,null,this.options.icons.down),this._addClass(n,null,e.down)),this._super(t,e),void 0)},_setOptionDisabled:function(t){this._super(t),this._toggleClass(this.uiSpinner,null,"ui-state-disabled",!!t),this.element.prop("disabled",!!t),this.buttons.button(t?"disable":"enable")},_setOptions:r(function(t){this._super(t)}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},isValid:function(){var t=this.value();return null===t?!1:t===this._adjustValue(t)},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.prop("disabled",!1).removeAttr("autocomplete role aria-valuemin aria-valuemax aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:r(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:r(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:r(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:r(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(r(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}}),t.uiBackCompat!==!1&&t.widget("ui.spinner",t.ui.spinner,{_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml())},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return""}}),t.ui.spinner,t.widget("ui.tabs",{version:"1.12.1",delay:300,options:{active:null,classes:{"ui-tabs":"ui-corner-all","ui-tabs-nav":"ui-corner-all","ui-tabs-panel":"ui-corner-bottom","ui-tabs-tab":"ui-corner-top"},collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_isLocal:function(){var t=/#.*$/;return function(e){var i,s;i=e.href.replace(t,""),s=location.href.replace(t,"");try{i=decodeURIComponent(i)}catch(n){}try{s=decodeURIComponent(s)}catch(n){}return e.hash.length>1&&i===s}}(),_create:function(){var e=this,i=this.options;this.running=!1,this._addClass("ui-tabs","ui-widget ui-widget-content"),this._toggleClass("ui-tabs-collapsible",null,i.collapsible),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var e=this.options.active,i=this.options.collapsible,s=location.hash.substring(1);return null===e&&(s&&this.tabs.each(function(i,n){return t(n).attr("aria-controls")===s?(e=i,!1):void 0}),null===e&&(e=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===e||-1===e)&&(e=this.tabs.length?0:!1)),e!==!1&&(e=this.tabs.index(this.tabs.eq(e)),-1===e&&(e=i?!1:0)),!i&&e===!1&&this.anchors.length&&(e=0),e},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(e){var i=t(t.ui.safeActiveElement(this.document[0])).closest("li"),s=this.tabs.index(i),n=!0;if(!this._handlePageNav(e)){switch(e.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:s++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:n=!1,s--;break;case t.ui.keyCode.END:s=this.anchors.length-1;break;case t.ui.keyCode.HOME:s=0;break;case t.ui.keyCode.SPACE:return e.preventDefault(),clearTimeout(this.activating),this._activate(s),void 0;case t.ui.keyCode.ENTER:return e.preventDefault(),clearTimeout(this.activating),this._activate(s===this.options.active?!1:s),void 0;default:return}e.preventDefault(),clearTimeout(this.activating),s=this._focusNextTab(s,n),e.ctrlKey||e.metaKey||(i.attr("aria-selected","false"),this.tabs.eq(s).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",s)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.trigger("focus"))},_handlePageNav:function(e){return e.altKey&&e.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):e.altKey&&e.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).trigger("focus"),t},_setOption:function(t,e){return"active"===t?(this._activate(e),void 0):(this._super(t,e),"collapsible"===t&&(this._toggleClass("ui-tabs-collapsible",null,e),e||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(e),"heightStyle"===t&&this._setupHeightStyle(e),void 0)},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setOptionDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-hidden":"true"}),this.active.length?(this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}),this._addClass(this.active,"ui-tabs-active","ui-state-active"),this._getPanelForTab(this.active).show().attr({"aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this,i=this.tabs,s=this.anchors,n=this.panels;this.tablist=this._getList().attr("role","tablist"),this._addClass(this.tablist,"ui-tabs-nav","ui-helper-reset ui-helper-clearfix ui-widget-header"),this.tablist.on("mousedown"+this.eventNamespace,"> li",function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).on("focus"+this.eventNamespace,".ui-tabs-anchor",function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this.tabs=this.tablist.find("> li:has(a[href])").attr({role:"tab",tabIndex:-1}),this._addClass(this.tabs,"ui-tabs-tab","ui-state-default"),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).attr({role:"presentation",tabIndex:-1}),this._addClass(this.anchors,"ui-tabs-anchor"),this.panels=t(),this.anchors.each(function(i,s){var n,o,a,r=t(s).uniqueId().attr("id"),h=t(s).closest("li"),l=h.attr("aria-controls");e._isLocal(s)?(n=s.hash,a=n.substring(1),o=e.element.find(e._sanitizeSelector(n))):(a=h.attr("aria-controls")||t({}).uniqueId()[0].id,n="#"+a,o=e.element.find(n),o.length||(o=e._createPanel(a),o.insertAfter(e.panels[i-1]||e.tablist)),o.attr("aria-live","polite")),o.length&&(e.panels=e.panels.add(o)),l&&h.data("ui-tabs-aria-controls",l),h.attr({"aria-controls":a,"aria-labelledby":r}),o.attr("aria-labelledby",r)}),this.panels.attr("role","tabpanel"),this._addClass(this.panels,"ui-tabs-panel","ui-widget-content"),i&&(this._off(i.not(this.tabs)),this._off(s.not(this.anchors)),this._off(n.not(this.panels)))},_getList:function(){return this.tablist||this.element.find("ol, ul").eq(0)},_createPanel:function(e){return t("
    ").attr("id",e).data("ui-tabs-destroy",!0)},_setOptionDisabled:function(e){var i,s,n;for(t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1),n=0;s=this.tabs[n];n++)i=t(s),e===!0||-1!==t.inArray(n,e)?(i.attr("aria-disabled","true"),this._addClass(i,null,"ui-state-disabled")):(i.removeAttr("aria-disabled"),this._removeClass(i,null,"ui-state-disabled"));this.options.disabled=e,this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,e===!0)},_setupEvents:function(e){var i={};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(!0,this.anchors,{click:function(t){t.preventDefault()}}),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n.closest("li"),a=o[0]===s[0],r=a&&i.collapsible,h=r?t():this._getPanelForTab(o),l=s.length?this._getPanelForTab(s):t(),c={oldTab:s,oldPanel:l,newTab:r?t():o,newPanel:h};e.preventDefault(),o.hasClass("ui-state-disabled")||o.hasClass("ui-tabs-loading")||this.running||a&&!i.collapsible||this._trigger("beforeActivate",e,c)===!1||(i.active=r?!1:this.tabs.index(o),this.active=a?t():o,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(o),e),this._toggle(e,c))},_toggle:function(e,i){function s(){o.running=!1,o._trigger("activate",e,i)}function n(){o._addClass(i.newTab.closest("li"),"ui-tabs-active","ui-state-active"),a.length&&o.options.show?o._show(a,o.options.show,s):(a.show(),s())}var o=this,a=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){o._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),n()}):(this._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),r.hide(),n()),r.attr("aria-hidden","true"),i.oldTab.attr({"aria-selected":"false","aria-expanded":"false"}),a.length&&r.length?i.oldTab.attr("tabIndex",-1):a.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),a.attr("aria-hidden","false"),i.newTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(e){return"string"==typeof e&&(e=this.anchors.index(this.anchors.filter("[href$='"+t.ui.escapeSelector(e)+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.tablist.removeAttr("role").off(this.eventNamespace),this.anchors.removeAttr("role tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeAttr("role tabIndex aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(e){var i=this.options.disabled;i!==!1&&(void 0===e?i=!1:(e=this._getIndex(e),i=t.isArray(i)?t.map(i,function(t){return t!==e?t:null}):t.map(this.tabs,function(t,i){return i!==e?i:null})),this._setOptionDisabled(i))},disable:function(e){var i=this.options.disabled;if(i!==!0){if(void 0===e)i=!0;else{if(e=this._getIndex(e),-1!==t.inArray(e,i))return;i=t.isArray(i)?t.merge([e],i).sort():[e]}this._setOptionDisabled(i)}},load:function(e,i){e=this._getIndex(e);var s=this,n=this.tabs.eq(e),o=n.find(".ui-tabs-anchor"),a=this._getPanelForTab(n),r={tab:n,panel:a},h=function(t,e){"abort"===e&&s.panels.stop(!1,!0),s._removeClass(n,"ui-tabs-loading"),a.removeAttr("aria-busy"),t===s.xhr&&delete s.xhr};this._isLocal(o[0])||(this.xhr=t.ajax(this._ajaxSettings(o,i,r)),this.xhr&&"canceled"!==this.xhr.statusText&&(this._addClass(n,"ui-tabs-loading"),a.attr("aria-busy","true"),this.xhr.done(function(t,e,n){setTimeout(function(){a.html(t),s._trigger("load",i,r),h(n,e)},1)}).fail(function(t,e){setTimeout(function(){h(t,e)},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href").replace(/#.*$/,""),beforeSend:function(e,o){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:o},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}}),t.uiBackCompat!==!1&&t.widget("ui.tabs",t.ui.tabs,{_processTabs:function(){this._superApply(arguments),this._addClass(this.tabs,"ui-tab")}}),t.ui.tabs,t.widget("ui.tooltip",{version:"1.12.1",options:{classes:{"ui-tooltip":"ui-corner-all ui-widget-shadow"},content:function(){var e=t(this).attr("title")||"";return t("").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,track:!1,close:null,open:null},_addDescribedBy:function(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))},_removeDescribedBy:function(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.liveRegion=t("
    ").attr({role:"log","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this.disabledTitles=t([])},_setOption:function(e,i){var s=this;this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e.element)})},_setOptionDisabled:function(t){this[t?"_disable":"_enable"]()},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s.element[0],e.close(n,!0)}),this.disabledTitles=this.disabledTitles.add(this.element.find(this.options.items).addBack().filter(function(){var e=t(this);return e.is("[title]")?e.data("ui-tooltip-title",e.attr("title")).removeAttr("title"):void 0}))},_enable:function(){this.disabledTitles.each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))}),this.disabledTitles=t([])},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._registerCloseHandlers(e,s),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,o=e?e.type:null;return"string"==typeof s||s.nodeType||s.jquery?this._open(e,t,s):(i=s.call(t[0],function(i){n._delay(function(){t.data("ui-tooltip-open")&&(e&&(e.type=o),this._open(e,t,i))})}),i&&this._open(e,t,i),void 0)},_open:function(e,i,s){function n(t){l.of=t,a.is(":hidden")||a.position(l)}var o,a,r,h,l=t.extend({},this.options.position);if(s){if(o=this._find(i))return o.tooltip.find(".ui-tooltip-content").html(s),void 0;i.is("[title]")&&(e&&"mouseover"===e.type?i.attr("title",""):i.removeAttr("title")),o=this._tooltip(i),a=o.tooltip,this._addDescribedBy(i,a.attr("id")),a.find(".ui-tooltip-content").html(s),this.liveRegion.children().hide(),h=t("
    ").html(a.find(".ui-tooltip-content").html()),h.removeAttr("name").find("[name]").removeAttr("name"),h.removeAttr("id").find("[id]").removeAttr("id"),h.appendTo(this.liveRegion),this.options.track&&e&&/^mouse/.test(e.type)?(this._on(this.document,{mousemove:n}),n(e)):a.position(t.extend({of:i},this.options.position)),a.hide(),this._show(a,this.options.show),this.options.track&&this.options.show&&this.options.show.delay&&(r=this.delayedShow=setInterval(function(){a.is(":visible")&&(n(l.of),clearInterval(r))},t.fx.interval)),this._trigger("open",e,{tooltip:a})}},_registerCloseHandlers:function(e,i){var s={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var s=t.Event(e);s.currentTarget=i[0],this.close(s,!0)}}};i[0]!==this.element[0]&&(s.remove=function(){this._removeTooltip(this._find(i).tooltip)}),e&&"mouseover"!==e.type||(s.mouseleave="close"),e&&"focusin"!==e.type||(s.focusout="close"),this._on(!0,i,s)},close:function(e){var i,s=this,n=t(e?e.currentTarget:this.element),o=this._find(n);return o?(i=o.tooltip,o.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&!n.attr("title")&&n.attr("title",n.data("ui-tooltip-title")),this._removeDescribedBy(n),o.hiding=!0,i.stop(!0),this._hide(i,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),o.closing=!0,this._trigger("close",e,{tooltip:i}),o.hiding||(o.closing=!1)),void 0):(n.removeData("ui-tooltip-open"),void 0)},_tooltip:function(e){var i=t("
    ").attr("role","tooltip"),s=t("
    ").appendTo(i),n=i.uniqueId().attr("id");return this._addClass(s,"ui-tooltip-content"),this._addClass(i,"ui-tooltip","ui-widget ui-widget-content"),i.appendTo(this._appendTo(e)),this.tooltips[n]={element:e,tooltip:i}},_find:function(t){var e=t.data("ui-tooltip-id");return e?this.tooltips[e]:null},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_appendTo:function(t){var e=t.closest(".ui-front, dialog");return e.length||(e=this.document[0].body),e},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur"),o=s.element;n.target=n.currentTarget=o[0],e.close(n,!0),t("#"+i).remove(),o.data("ui-tooltip-title")&&(o.attr("title")||o.attr("title",o.data("ui-tooltip-title")),o.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}}),t.uiBackCompat!==!1&&t.widget("ui.tooltip",t.ui.tooltip,{options:{tooltipClass:null},_tooltip:function(){var t=this._superApply(arguments);return this.options.tooltipClass&&t.tooltip.addClass(this.options.tooltipClass),t}}),t.ui.tooltip}); \ No newline at end of file +(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)})(function(t){function e(t){for(var e=t.css("visibility");"inherit"===e;)t=t.parent(),e=t.css("visibility");return"hidden"!==e}t.ui=t.ui||{},t.ui.version="1.12.1";var i=0,s=Array.prototype.slice;t.cleanData=function(e){return function(i){var s,n,o;for(o=0;null!=(n=i[o]);o++)try{s=t._data(n,"events"),s&&s.remove&&t(n).triggerHandler("remove")}catch(a){}e(i)}}(t.cleanData),t.widget=function(e,i,s){var n,o,a,r={},l=e.split(".")[0];e=e.split(".")[1];var h=l+"-"+e;return s||(s=i,i=t.Widget),t.isArray(s)&&(s=t.extend.apply(null,[{}].concat(s))),t.expr[":"][h.toLowerCase()]=function(e){return!!t.data(e,h)},t[l]=t[l]||{},n=t[l][e],o=t[l][e]=function(t,e){return this._createWidget?(arguments.length&&this._createWidget(t,e),void 0):new o(t,e)},t.extend(o,n,{version:s.version,_proto:t.extend({},s),_childConstructors:[]}),a=new i,a.options=t.widget.extend({},a.options),t.each(s,function(e,s){return t.isFunction(s)?(r[e]=function(){function t(){return i.prototype[e].apply(this,arguments)}function n(t){return i.prototype[e].apply(this,t)}return function(){var e,i=this._super,o=this._superApply;return this._super=t,this._superApply=n,e=s.apply(this,arguments),this._super=i,this._superApply=o,e}}(),void 0):(r[e]=s,void 0)}),o.prototype=t.widget.extend(a,{widgetEventPrefix:n?a.widgetEventPrefix||e:e},r,{constructor:o,namespace:l,widgetName:e,widgetFullName:h}),n?(t.each(n._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete n._childConstructors):i._childConstructors.push(o),t.widget.bridge(e,o),o},t.widget.extend=function(e){for(var i,n,o=s.call(arguments,1),a=0,r=o.length;r>a;a++)for(i in o[a])n=o[a][i],o[a].hasOwnProperty(i)&&void 0!==n&&(e[i]=t.isPlainObject(n)?t.isPlainObject(e[i])?t.widget.extend({},e[i],n):t.widget.extend({},n):n);return e},t.widget.bridge=function(e,i){var n=i.prototype.widgetFullName||e;t.fn[e]=function(o){var a="string"==typeof o,r=s.call(arguments,1),l=this;return a?this.length||"instance"!==o?this.each(function(){var i,s=t.data(this,n);return"instance"===o?(l=s,!1):s?t.isFunction(s[o])&&"_"!==o.charAt(0)?(i=s[o].apply(s,r),i!==s&&void 0!==i?(l=i&&i.jquery?l.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+o+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+o+"'")}):l=void 0:(r.length&&(o=t.widget.extend.apply(null,[o].concat(r))),this.each(function(){var e=t.data(this,n);e?(e.option(o||{}),e._init&&e._init()):t.data(this,n,new i(o,this))})),l}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
    ",options:{classes:{},disabled:!1,create:null},_createWidget:function(e,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(e){function i(i,o){var a,r;for(r=0;i.length>r;r++)a=n.classesElementLookup[i[r]]||t(),a=e.add?t(t.unique(a.get().concat(e.element.get()))):t(a.not(e.element).get()),n.classesElementLookup[i[r]]=a,s.push(i[r]),o&&e.classes[i[r]]&&s.push(e.classes[i[r]])}var s=[],n=this;return e=t.extend({element:this.element,classes:this.options.classes||{}},e),this._on(e.element,{remove:"_untrackClassesElement"}),e.keys&&i(e.keys.match(/\S+/g)||[],!0),e.extra&&i(e.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(e){var i=this;t.each(i.classesElementLookup,function(s,n){-1!==t.inArray(e.target,n)&&(i.classesElementLookup[s]=t(n.not(e.target).get()))})},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){s="boolean"==typeof s?s:i;var n="string"==typeof t||null===t,o={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s};return o.element.toggleClass(this._classes(o),s),this},_on:function(e,i,s){var n,o=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,a){function r(){return e||o.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof a?o[a]:a).apply(o,arguments):void 0}"string"!=typeof a&&(r.guid=a.guid=a.guid||r.guid||t.guid++);var l=s.match(/^([\w:-]*)\s*(.*)$/),h=l[1]+o.eventNamespace,c=l[2];c?n.on(h,c,r):i.on(h,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.off(i).off(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){this._addClass(t(e.currentTarget),null,"ui-state-hover")},mouseleave:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){this._addClass(t(e.currentTarget),null,"ui-state-focus")},focusout:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}}),t.widget,function(){function e(t,e,i){return[parseFloat(t[0])*(u.test(t[0])?e/100:1),parseFloat(t[1])*(u.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}var n,o=Math.max,a=Math.abs,r=/left|center|right/,l=/top|center|bottom/,h=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,u=/%$/,d=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==n)return n;var e,i,s=t("
    "),o=s.children()[0];return t("body").append(s),e=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,e===i&&(i=s[0].clientWidth),s.remove(),n=e-i},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widthi?"left":e>0?"right":"center",vertical:0>r?"top":s>0?"bottom":"middle"};h>p&&p>a(e+i)&&(u.horizontal="center"),c>f&&f>a(s+r)&&(u.vertical="middle"),u.important=o(a(e),a(i))>o(a(s),a(r))?"horizontal":"vertical",n.using.call(this,t,u)}),l.offset(t.extend(D,{using:r}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,l=n-r,h=r+e.collisionWidth-a-n;e.collisionWidth>a?l>0&&0>=h?(i=t.left+l+e.collisionWidth-a-n,t.left+=l-i):t.left=h>0&&0>=l?n:l>h?n+a-e.collisionWidth:n:l>0?t.left+=l:h>0?t.left-=h:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,l=n-r,h=r+e.collisionHeight-a-n;e.collisionHeight>a?l>0&&0>=h?(i=t.top+l+e.collisionHeight-a-n,t.top+=l-i):t.top=h>0&&0>=l?n:l>h?n+a-e.collisionHeight:n:l>0?t.top+=l:h>0?t.top-=h:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,r=n.width,l=n.isWindow?n.scrollLeft:n.offset.left,h=t.left-e.collisionPosition.marginLeft,c=h-l,u=h+e.collisionWidth-r-l,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-r-o,(0>i||a(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-l,(s>0||u>a(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,r=n.height,l=n.isWindow?n.scrollTop:n.offset.top,h=t.top-e.collisionPosition.marginTop,c=h-l,u=h+e.collisionHeight-r-l,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,g=-2*e.offset[1];0>c?(s=t.top+p+f+g+e.collisionHeight-r-o,(0>s||a(c)>s)&&(t.top+=p+f+g)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+g-l,(i>0||u>a(i))&&(t.top+=p+f+g))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}}}(),t.ui.position,t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])}}),t.fn.extend({disableSelection:function(){var t="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.on(t+".ui-disableSelection",function(t){t.preventDefault()})}}(),enableSelection:function(){return this.off(".ui-disableSelection")}}),t.ui.focusable=function(i,s){var n,o,a,r,l,h=i.nodeName.toLowerCase();return"area"===h?(n=i.parentNode,o=n.name,i.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap='#"+o+"']"),a.length>0&&a.is(":visible")):!1):(/^(input|select|textarea|button|object)$/.test(h)?(r=!i.disabled,r&&(l=t(i).closest("fieldset")[0],l&&(r=!l.disabled))):r="a"===h?i.href||s:s,r&&t(i).is(":visible")&&e(t(i)))},t.extend(t.expr[":"],{focusable:function(e){return t.ui.focusable(e,null!=t.attr(e,"tabindex"))}}),t.ui.focusable,t.fn.form=function(){return"string"==typeof this[0].form?this.closest("form"):t(this[0].form)},t.ui.formResetMixin={_formResetHandler:function(){var e=t(this);setTimeout(function(){var i=e.data("ui-form-reset-instances");t.each(i,function(){this.refresh()})})},_bindFormResetHandler:function(){if(this.form=this.element.form(),this.form.length){var t=this.form.data("ui-form-reset-instances")||[];t.length||this.form.on("reset.ui-form-reset",this._formResetHandler),t.push(this),this.form.data("ui-form-reset-instances",t)}},_unbindFormResetHandler:function(){if(this.form.length){var e=this.form.data("ui-form-reset-instances");e.splice(t.inArray(this,e),1),e.length?this.form.data("ui-form-reset-instances",e):this.form.removeData("ui-form-reset-instances").off("reset.ui-form-reset")}}},"1.7"===t.fn.jquery.substring(0,3)&&(t.each(["Width","Height"],function(e,i){function s(e,i,s,o){return t.each(n,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),o&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],o=i.toLowerCase(),a={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+i]=function(e){return void 0===e?a["inner"+i].call(this):this.each(function(){t(this).css(o,s(this,e)+"px")})},t.fn["outer"+i]=function(e,n){return"number"!=typeof e?a["outer"+i].call(this,e):this.each(function(){t(this).css(o,s(this,e,!0,n)+"px")})}}),t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38},t.ui.escapeSelector=function(){var t=/([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;return function(e){return e.replace(t,"\\$1")}}(),t.fn.labels=function(){var e,i,s,n,o;return this[0].labels&&this[0].labels.length?this.pushStack(this[0].labels):(n=this.eq(0).parents("label"),s=this.attr("id"),s&&(e=this.eq(0).parents().last(),o=e.add(e.length?e.siblings():this.siblings()),i="label[for='"+t.ui.escapeSelector(s)+"']",n=n.add(o.find(i).addBack(i))),this.pushStack(n))},t.fn.scrollParent=function(e){var i=this.css("position"),s="absolute"===i,n=e?/(auto|scroll|hidden)/:/(auto|scroll)/,o=this.parents().filter(function(){var e=t(this);return s&&"static"===e.css("position")?!1:n.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==i&&o.length?o:t(this[0].ownerDocument||document)},t.extend(t.expr[":"],{tabbable:function(e){var i=t.attr(e,"tabindex"),s=null!=i;return(!s||i>=0)&&t.ui.focusable(e,s)}}),t.fn.extend({uniqueId:function(){var t=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++t)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&t(this).removeAttr("id")})}}),t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var n=!1;t(document).on("mouseup",function(){n=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!n){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,s=1===e.which,o="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return s&&!o&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),n=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,n=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.ui.plugin={add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;o.length>n;n++)t.options[o[n][0]]&&o[n][1].apply(t.element,i)}},t.ui.safeActiveElement=function(t){var e;try{e=t.activeElement}catch(i){e=t.body}return e||(e=t.body),e.nodeName||(e=t.body),e},t.ui.safeBlur=function(e){e&&"body"!==e.nodeName.toLowerCase()&&t(e).trigger("blur")},t.widget("ui.draggable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"===this.options.helper&&this._setPositionRelative(),this.options.addClasses&&this._addClass("ui-draggable"),this._setHandleClassName(),this._mouseInit()},_setOption:function(t,e){this._super(t,e),"handle"===t&&(this._removeHandleClassName(),this._setHandleClassName())},_destroy:function(){return(this.helper||this.element).is(".ui-draggable-dragging")?(this.destroyOnClear=!0,void 0):(this._removeHandleClassName(),this._mouseDestroy(),void 0)},_mouseCapture:function(e){var i=this.options;return this.helper||i.disabled||t(e.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(e),this.handle?(this._blurActiveElement(e),this._blockFrames(i.iframeFix===!0?"iframe":i.iframeFix),!0):!1)},_blockFrames:function(e){this.iframeBlocks=this.document.find(e).map(function(){var e=t(this);return t("
    ").css("position","absolute").appendTo(e.parent()).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_blurActiveElement:function(e){var i=t.ui.safeActiveElement(this.document[0]),s=t(e.target);s.closest(i).length||t.ui.safeBlur(i)},_mouseStart:function(e){var i=this.options;return this.helper=this._createHelper(e),this._addClass(this.helper,"ui-draggable-dragging"),this._cacheHelperProportions(),t.ui.ddmanager&&(t.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(!0),this.offsetParent=this.helper.offsetParent(),this.hasFixedAncestor=this.helper.parents().filter(function(){return"fixed"===t(this).css("position")}).length>0,this.positionAbs=this.element.offset(),this._refreshOffsets(e),this.originalPosition=this.position=this._generatePosition(e,!1),this.originalPageX=e.pageX,this.originalPageY=e.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",e)===!1?(this._clear(),!1):(this._cacheHelperProportions(),t.ui.ddmanager&&!i.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this._mouseDrag(e,!0),t.ui.ddmanager&&t.ui.ddmanager.dragStart(this,e),!0)},_refreshOffsets:function(t){this.offset={top:this.positionAbs.top-this.margins.top,left:this.positionAbs.left-this.margins.left,scroll:!1,parent:this._getParentOffset(),relative:this._getRelativeOffset()},this.offset.click={left:t.pageX-this.offset.left,top:t.pageY-this.offset.top}},_mouseDrag:function(e,i){if(this.hasFixedAncestor&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(e,!0),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",e,s)===!1)return this._mouseUp(new t.Event("mouseup",e)),!1;this.position=s.position}return this.helper[0].style.left=this.position.left+"px",this.helper[0].style.top=this.position.top+"px",t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),!1},_mouseStop:function(e){var i=this,s=!1;return t.ui.ddmanager&&!this.options.dropBehaviour&&(s=t.ui.ddmanager.drop(this,e)),this.dropped&&(s=this.dropped,this.dropped=!1),"invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||t.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?t(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",e)!==!1&&i._clear()}):this._trigger("stop",e)!==!1&&this._clear(),!1},_mouseUp:function(e){return this._unblockFrames(),t.ui.ddmanager&&t.ui.ddmanager.dragStop(this,e),this.handleElement.is(e.target)&&this.element.trigger("focus"),t.ui.mouse.prototype._mouseUp.call(this,e)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp(new t.Event("mouseup",{target:this.element[0]})):this._clear(),this},_getHandle:function(e){return this.options.handle?!!t(e.target).closest(this.element.find(this.options.handle)).length:!0},_setHandleClassName:function(){this.handleElement=this.options.handle?this.element.find(this.options.handle):this.element,this._addClass(this.handleElement,"ui-draggable-handle")},_removeHandleClassName:function(){this._removeClass(this.handleElement,"ui-draggable-handle")},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper),n=s?t(i.helper.apply(this.element[0],[e])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return n.parents("body").length||n.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s&&n[0]===this.element[0]&&this._setPositionRelative(),n[0]===this.element[0]||/(fixed|absolute)/.test(n.css("position"))||n.css("position","absolute"),n},_setPositionRelative:function(){/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative")},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_isRootNode:function(t){return/(html|body)/i.test(t.tagName)||t===this.document[0]},_getParentOffset:function(){var e=this.offsetParent.offset(),i=this.document[0];return"absolute"===this.cssPosition&&this.scrollParent[0]!==i&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),this._isRootNode(this.offsetParent[0])&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"!==this.cssPosition)return{top:0,left:0};var t=this.element.position(),e=this._isRootNode(this.scrollParent[0]);return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+(e?0:this.scrollParent.scrollTop()),left:t.left-(parseInt(this.helper.css("left"),10)||0)+(e?0:this.scrollParent.scrollLeft())}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options,o=this.document[0];return this.relativeContainer=null,n.containment?"window"===n.containment?(this.containment=[t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,t(window).scrollLeft()+t(window).width()-this.helperProportions.width-this.margins.left,t(window).scrollTop()+(t(window).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===n.containment?(this.containment=[0,0,t(o).width()-this.helperProportions.width-this.margins.left,(t(o).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):n.containment.constructor===Array?(this.containment=n.containment,void 0):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=t(n.containment),s=i[0],s&&(e=/(scroll|auto)/.test(i.css("overflow")),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relativeContainer=i),void 0):(this.containment=null,void 0)},_convertPositionTo:function(t,e){e||(e=this.position);var i="absolute"===t?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:e.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:e.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(t,e){var i,s,n,o,a=this.options,r=this._isRootNode(this.scrollParent[0]),l=t.pageX,h=t.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),e&&(this.containment&&(this.relativeContainer?(s=this.relativeContainer.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,t.pageX-this.offset.click.lefti[2]&&(l=i[2]+this.offset.click.left),t.pageY-this.offset.click.top>i[3]&&(h=i[3]+this.offset.click.top)),a.grid&&(n=a.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/a.grid[1])*a.grid[1]:this.originalPageY,h=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-a.grid[1]:n+a.grid[1]:n,o=a.grid[0]?this.originalPageX+Math.round((l-this.originalPageX)/a.grid[0])*a.grid[0]:this.originalPageX,l=i?o-this.offset.click.left>=i[0]||o-this.offset.click.left>i[2]?o:o-this.offset.click.left>=i[0]?o-a.grid[0]:o+a.grid[0]:o),"y"===a.axis&&(l=this.originalPageX),"x"===a.axis&&(h=this.originalPageY)),{top:h-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:l-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)} +},_clear:function(){this._removeClass(this.helper,"ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s,this],!0),/^(drag|start|stop)/.test(e)&&(this.positionAbs=this._convertPositionTo("absolute"),s.offset=this.positionAbs),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i,s){var n=t.extend({},i,{item:s.element});s.sortables=[],t(s.options.connectToSortable).each(function(){var i=t(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push(i),i.refreshPositions(),i._trigger("activate",e,n))})},stop:function(e,i,s){var n=t.extend({},i,{item:s.element});s.cancelHelperRemoval=!1,t.each(s.sortables,function(){var t=this;t.isOver?(t.isOver=0,s.cancelHelperRemoval=!0,t.cancelHelperRemoval=!1,t._storedCSS={position:t.placeholder.css("position"),top:t.placeholder.css("top"),left:t.placeholder.css("left")},t._mouseStop(e),t.options.helper=t.options._helper):(t.cancelHelperRemoval=!0,t._trigger("deactivate",e,n))})},drag:function(e,i,s){t.each(s.sortables,function(){var n=!1,o=this;o.positionAbs=s.positionAbs,o.helperProportions=s.helperProportions,o.offset.click=s.offset.click,o._intersectsWith(o.containerCache)&&(n=!0,t.each(s.sortables,function(){return this.positionAbs=s.positionAbs,this.helperProportions=s.helperProportions,this.offset.click=s.offset.click,this!==o&&this._intersectsWith(this.containerCache)&&t.contains(o.element[0],this.element[0])&&(n=!1),n})),n?(o.isOver||(o.isOver=1,s._parent=i.helper.parent(),o.currentItem=i.helper.appendTo(o.element).data("ui-sortable-item",!0),o.options._helper=o.options.helper,o.options.helper=function(){return i.helper[0]},e.target=o.currentItem[0],o._mouseCapture(e,!0),o._mouseStart(e,!0,!0),o.offset.click.top=s.offset.click.top,o.offset.click.left=s.offset.click.left,o.offset.parent.left-=s.offset.parent.left-o.offset.parent.left,o.offset.parent.top-=s.offset.parent.top-o.offset.parent.top,s._trigger("toSortable",e),s.dropped=o.element,t.each(s.sortables,function(){this.refreshPositions()}),s.currentItem=s.element,o.fromOutside=s),o.currentItem&&(o._mouseDrag(e),i.position=o.position)):o.isOver&&(o.isOver=0,o.cancelHelperRemoval=!0,o.options._revert=o.options.revert,o.options.revert=!1,o._trigger("out",e,o._uiHash(o)),o._mouseStop(e,!0),o.options.revert=o.options._revert,o.options.helper=o.options._helper,o.placeholder&&o.placeholder.remove(),i.helper.appendTo(s._parent),s._refreshOffsets(e),i.position=s._generatePosition(e,!0),s._trigger("fromSortable",e),s.dropped=!1,t.each(s.sortables,function(){this.refreshPositions()}))})}}),t.ui.plugin.add("draggable","cursor",{start:function(e,i,s){var n=t("body"),o=s.options;n.css("cursor")&&(o._cursor=n.css("cursor")),n.css("cursor",o.cursor)},stop:function(e,i,s){var n=s.options;n._cursor&&t("body").css("cursor",n._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("opacity")&&(o._opacity=n.css("opacity")),n.css("opacity",o.opacity)},stop:function(e,i,s){var n=s.options;n._opacity&&t(i.helper).css("opacity",n._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(t,e,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(e,i,s){var n=s.options,o=!1,a=s.scrollParentNotHidden[0],r=s.document[0];a!==r&&"HTML"!==a.tagName?(n.axis&&"x"===n.axis||(s.overflowOffset.top+a.offsetHeight-e.pageY=0;d--)l=s.snapElements[d].left-s.margins.left,h=l+s.snapElements[d].width,c=s.snapElements[d].top-s.margins.top,u=c+s.snapElements[d].height,l-g>_||m>h+g||c-g>b||v>u+g||!t.contains(s.snapElements[d].item.ownerDocument,s.snapElements[d].item)?(s.snapElements[d].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=!1):("inner"!==f.snapMode&&(n=g>=Math.abs(c-b),o=g>=Math.abs(u-v),a=g>=Math.abs(l-_),r=g>=Math.abs(h-m),n&&(i.position.top=s._convertPositionTo("relative",{top:c-s.helperProportions.height,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left)),p=n||o||a||r,"outer"!==f.snapMode&&(n=g>=Math.abs(c-v),o=g>=Math.abs(u-b),a=g>=Math.abs(l-m),r=g>=Math.abs(h-_),n&&(i.position.top=s._convertPositionTo("relative",{top:c,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left)),!s.snapElements[d].snapping&&(n||o||a||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=n||o||a||r||p)}}),t.ui.plugin.add("draggable","stack",{start:function(e,i,s){var n,o=s.options,a=t.makeArray(t(o.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});a.length&&(n=parseInt(t(a[0]).css("zIndex"),10)||0,t(a).each(function(e){t(this).css("zIndex",n+e)}),this.css("zIndex",n+a.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("zIndex")&&(o._zIndex=n.css("zIndex")),n.css("zIndex",o.zIndex)},stop:function(e,i,s){var n=s.options;n._zIndex&&t(i.helper).css("zIndex",n._zIndex)}}),t.ui.draggable,t.widget("ui.resizable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,classes:{"ui-resizable-se":"ui-icon ui-icon-gripsmall-diagonal-se"},containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(t){return parseFloat(t)||0},_isNumber:function(t){return!isNaN(parseFloat(t))},_hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)},_create:function(){var e,i=this.options,s=this;this._addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!i.aspectRatio,aspectRatio:i.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:i.helper||i.ghost||i.animate?i.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(t("
    ").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,e={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(e),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(e),this._proportionallyResize()),this._setupHandles(),i.autoHide&&t(this.element).on("mouseenter",function(){i.disabled||(s._removeClass("ui-resizable-autohide"),s._handles.show())}).on("mouseleave",function(){i.disabled||s.resizing||(s._addClass("ui-resizable-autohide"),s._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;default:}},_setupHandles:function(){var e,i,s,n,o,a=this.options,r=this;if(this.handles=a.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=t(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),s=this.handles.split(","),this.handles={},i=0;s.length>i;i++)e=t.trim(s[i]),n="ui-resizable-"+e,o=t("
    "),this._addClass(o,"ui-resizable-handle "+n),o.css({zIndex:a.zIndex}),this.handles[e]=".ui-resizable-"+e,this.element.append(o);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=t(this.handles[i]),this._on(this.handles[i],{mousedown:r._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){r.resizing||(this.className&&(o=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),r.axis=o&&o[1]?o[1]:"se")}),a.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(e){var i,s,n,o=this.options,a=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),o.containment&&(i+=t(o.containment).scrollLeft()||0,s+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:a.width(),height:a.height()},this.originalSize=this._helper?{width:a.outerWidth(),height:a.outerHeight()}:{width:a.width(),height:a.height()},this.sizeDiff={width:a.outerWidth()-a.width(),height:a.outerHeight()-a.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:e.pageX,top:e.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===n?this.axis+"-resize":n),this._addClass("ui-resizable-resizing"),this._propagate("start",e),!0},_mouseDrag:function(e){var i,s,n=this.originalMousePosition,o=this.axis,a=e.pageX-n.left||0,r=e.pageY-n.top||0,l=this._change[o];return this._updatePrevProperties(),l?(i=l.apply(this,[e,a,r]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",e,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,l,h=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseFloat(c.element.css("left"))+(c.position.left-c.originalPosition.left)||null,l=parseFloat(c.element.css("top"))+(c.position.top-c.originalPosition.top)||null,h.animate||this.element.css(t.extend(a,{top:l,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!h.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s,n,o,a=this.options;o={minWidth:this._isNumber(a.minWidth)?a.minWidth:0,maxWidth:this._isNumber(a.maxWidth)?a.maxWidth:1/0,minHeight:this._isNumber(a.minHeight)?a.minHeight:0,maxHeight:this._isNumber(a.maxHeight)?a.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,s=o.minWidth/this.aspectRatio,i=o.maxHeight*this.aspectRatio,n=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),s>o.minHeight&&(o.minHeight=s),o.maxWidth>i&&(o.maxWidth=i),o.maxHeight>n&&(o.maxHeight=n)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),this._isNumber(t.left)&&(this.position.left=t.left),this._isNumber(t.top)&&(this.position.top=t.top),this._isNumber(t.height)&&(this.size.height=t.height),this._isNumber(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,i=this.size,s=this.axis;return this._isNumber(t.height)?t.width=t.height*this.aspectRatio:this._isNumber(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===s&&(t.left=e.left+(i.width-t.width),t.top=null),"nw"===s&&(t.top=e.top+(i.height-t.height),t.left=e.left+(i.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,i=this.axis,s=this._isNumber(t.width)&&e.maxWidth&&e.maxWidtht.width,a=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,r=this.originalPosition.left+this.originalSize.width,l=this.originalPosition.top+this.originalSize.height,h=/sw|nw|w/.test(i),c=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),a&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&h&&(t.left=r-e.minWidth),s&&h&&(t.left=r-e.maxWidth),a&&c&&(t.top=l-e.minHeight),n&&c&&(t.top=l-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];4>e;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;this._proportionallyResizeElements.length>e;e++)t=this._proportionallyResizeElements[e],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(t)),t.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
    "),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,l={width:i.size.width-r,height:i.size.height-a},h=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,c=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(l,c&&h?{top:c,left:h}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var e,i,s,n,o,a,r,l=t(this).resizable("instance"),h=l.options,c=l.element,u=h.containment,d=u instanceof t?u.get(0):/parent/.test(u)?c.parent().get(0):u;d&&(l.containerElement=t(d),/document/.test(u)||u===document?(l.containerOffset={left:0,top:0},l.containerPosition={left:0,top:0},l.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(e=t(d),i=[],t(["Top","Right","Left","Bottom"]).each(function(t,s){i[t]=l._num(e.css("padding"+s))}),l.containerOffset=e.offset(),l.containerPosition=e.position(),l.containerSize={height:e.innerHeight()-i[3],width:e.innerWidth()-i[1]},s=l.containerOffset,n=l.containerSize.height,o=l.containerSize.width,a=l._hasScroll(d,"left")?d.scrollWidth:o,r=l._hasScroll(d)?d.scrollHeight:n,l.parentData={element:d,left:s.left,top:s.top,width:a,height:r}))},resize:function(e){var i,s,n,o,a=t(this).resizable("instance"),r=a.options,l=a.containerOffset,h=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement,p=!0;d[0]!==document&&/static/.test(d.css("position"))&&(u=l),h.left<(a._helper?l.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-l.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio,p=!1),a.position.left=r.helper?l.left:0),h.top<(a._helper?l.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-l.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio,p=!1),a.position.top=a._helper?l.top:0),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o?(a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top):(a.offset.left=a.element.offset().left,a.offset.top=a.element.offset().top),i=Math.abs(a.sizeDiff.width+(a._helper?a.offset.left-u.left:a.offset.left-l.left)),s=Math.abs(a.sizeDiff.height+(a._helper?a.offset.top-u.top:a.offset.top-l.top)),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio,p=!1)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio,p=!1)),p||(a.position.left=a.prevPosition.left,a.position.top=a.prevPosition.top,a.size.width=a.prevSize.width,a.size.height=a.prevSize.height)},stop:function(){var e=t(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),l=a.outerWidth()-e.sizeDiff.width,h=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:l,height:h}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:l,height:h})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).resizable("instance"),i=e.options;t(i.alsoResize).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseFloat(e.width()),height:parseFloat(e.height()),left:parseFloat(e.css("left")),top:parseFloat(e.css("top"))})})},resize:function(e,i){var s=t(this).resizable("instance"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0};t(n.alsoResize).each(function(){var e=t(this),s=t(this).data("ui-resizable-alsoresize"),n={},o=e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&i>=0&&(n[e]=i||null)}),e.css(n)})},stop:function(){t(this).removeData("ui-resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).resizable("instance"),i=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:i.height,width:i.width,margin:0,left:0,top:0}),e._addClass(e.ghost,"ui-resizable-ghost"),t.uiBackCompat!==!1&&"string"==typeof e.options.ghost&&e.ghost.addClass(this.options.ghost),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).resizable("instance");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).resizable("instance");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e,i=t(this).resizable("instance"),s=i.options,n=i.size,o=i.originalSize,a=i.originalPosition,r=i.axis,l="number"==typeof s.grid?[s.grid,s.grid]:s.grid,h=l[0]||1,c=l[1]||1,u=Math.round((n.width-o.width)/h)*h,d=Math.round((n.height-o.height)/c)*c,p=o.width+u,f=o.height+d,g=s.maxWidth&&p>s.maxWidth,m=s.maxHeight&&f>s.maxHeight,_=s.minWidth&&s.minWidth>p,v=s.minHeight&&s.minHeight>f;s.grid=l,_&&(p+=h),v&&(f+=c),g&&(p-=h),m&&(f-=c),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=a.top-d):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=a.left-u):((0>=f-c||0>=p-h)&&(e=i._getPaddingPlusBorderDimensions(this)),f-c>0?(i.size.height=f,i.position.top=a.top-d):(f=c-e.height,i.size.height=f,i.position.top=a.top+o.height-f),p-h>0?(i.size.width=p,i.position.left=a.left-u):(p=h-e.width,i.size.width=p,i.position.left=a.left+o.width-p))}}),t.ui.resizable,t.widget("ui.sortable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(t,e,i){return t>=e&&e+i>t},_isFloating:function(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))},_create:function(){this.containerCache={},this._addClass("ui-sortable"),this.refresh(),this.offset=this.element.offset(),this._mouseInit(),this._setHandleClassName(),this.ready=!0},_setOption:function(t,e){this._super(t,e),"handle"===t&&this._setHandleClassName()},_setHandleClassName:function(){var e=this;this._removeClass(this.element.find(".ui-sortable-handle"),"ui-sortable-handle"),t.each(this.items,function(){e._addClass(this.instance.options.handle?this.item.find(this.instance.options.handle):this.item,"ui-sortable-handle")})},_destroy:function(){this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_mouseCapture:function(e,i){var s=null,n=!1,o=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,o.widgetName+"-item")===o?(s=t(this),!1):void 0}),t.data(e.target,o.widgetName+"-item")===o&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,o,a=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,a.cursorAt&&this._adjustOffsetFromHelper(a.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),a.containment&&this._setContainment(),a.cursor&&"auto"!==a.cursor&&(o=this.document.find("body"),this.storedCursor=o.css("cursor"),o.css("cursor",a.cursor),this.storedStylesheet=t("").appendTo(o)),a.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",a.opacity)),a.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",a.zIndex)),this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this._addClass(this.helper,"ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,o,a=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY=0;i--)if(s=this.items[i],n=s.item[0],o=this._intersectsWithPointer(s),o&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===o?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===o?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1 +},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),o=this.options.axis,a={};o&&"x"!==o||(a.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollLeft)),o&&"y"!==o||(a.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===this.document[0].body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(a,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp(new t.Event("mouseup",{target:null})),"original"===this.options.helper?(this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,o=t.left,a=o+t.width,r=t.top,l=r+t.height,h=this.offset.click.top,c=this.offset.click.left,u="x"===this.options.axis||s+h>r&&l>s+h,d="y"===this.options.axis||e+c>o&&a>e+c,p=u&&d;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?p:e+this.helperProportions.width/2>o&&a>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&l>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var e,i,s="x"===this.options.axis||this._isOverAxis(this.positionAbs.top+this.offset.click.top,t.top,t.height),n="y"===this.options.axis||this._isOverAxis(this.positionAbs.left+this.offset.click.left,t.left,t.width),o=s&&n;return o?(e=this._getDragVerticalDirection(),i=this._getDragHorizontalDirection(),this.floating?"right"===i||"down"===e?2:1:e&&("down"===e?2:1)):!1},_intersectsWithSides:function(t){var e=this._isOverAxis(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),i=this._isOverAxis(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),s=this._getDragVerticalDirection(),n=this._getDragHorizontalDirection();return this.floating&&n?"right"===n&&i||"left"===n&&!i:s&&("down"===s&&e||"up"===s&&!e)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this._setHandleClassName(),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){function i(){r.push(this)}var s,n,o,a,r=[],l=[],h=this._connectWith();if(h&&e)for(s=h.length-1;s>=0;s--)for(o=t(h[s],this.document[0]),n=o.length-1;n>=0;n--)a=t.data(o[n],this.widgetFullName),a&&a!==this&&!a.options.disabled&&l.push([t.isFunction(a.options.items)?a.options.items.call(a.element):t(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a]);for(l.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=l.length-1;s>=0;s--)l[s][0].each(i);return t(r)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,o,a,r,l,h,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i],this.document[0]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&(u.push([t.isFunction(o.options.items)?o.options.items.call(o.element[0],e,{item:this.currentItem}):t(o.options.items,o.element),o]),this.containers.push(o));for(i=u.length-1;i>=0;i--)for(a=u[i][1],r=u[i][0],s=0,h=r.length;h>s;s++)l=t(r[s]),l.data(this.widgetName+"-item",a),c.push({item:l,instance:a,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.floating=this.items.length?"x"===this.options.axis||this._isFloating(this.items[0].item):!1,this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,o;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),o=n.offset(),s.left=o.left,s.top=o.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)o=this.containers[i].element.offset(),this.containers[i].containerCache.left=o.left,this.containers[i].containerCache.top=o.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t("<"+s+">",e.document[0]);return e._addClass(n,"ui-sortable-placeholder",i||e.currentItem[0].className)._removeClass(n,"ui-sortable-helper"),"tbody"===s?e._createTrPlaceholder(e.currentItem.find("tr").eq(0),t("",e.document[0]).appendTo(n)):"tr"===s?e._createTrPlaceholder(e.currentItem,n):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_createTrPlaceholder:function(e,i){var s=this;e.children().each(function(){t(" ",s.document[0]).attr("colspan",t(this).attr("colspan")||1).appendTo(i)})},_contactContainers:function(e){var i,s,n,o,a,r,l,h,c,u,d=null,p=null;for(i=this.containers.length-1;i>=0;i--)if(!t.contains(this.currentItem[0],this.containers[i].element[0]))if(this._intersectsWith(this.containers[i].containerCache)){if(d&&t.contains(this.containers[i].element[0],d.element[0]))continue;d=this.containers[i],p=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",e,this._uiHash(this)),this.containers[i].containerCache.over=0);if(d)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",e,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(n=1e4,o=null,c=d.floating||this._isFloating(this.currentItem),a=c?"left":"top",r=c?"width":"height",u=c?"pageX":"pageY",s=this.items.length-1;s>=0;s--)t.contains(this.containers[p].element[0],this.items[s].item[0])&&this.items[s].item[0]!==this.currentItem[0]&&(l=this.items[s].item.offset()[a],h=!1,e[u]-l>this.items[s][r]/2&&(h=!0),n>Math.abs(e[u]-l)&&(n=Math.abs(e[u]-l),o=this.items[s],this.direction=h?"up":"down"));if(!o&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[p])return this.currentContainer.containerCache.over||(this.containers[p]._trigger("over",e,this._uiHash()),this.currentContainer.containerCache.over=1),void 0;o?this._rearrange(e,o,null,!0):this._rearrange(e,null,this.containers[p].element,!0),this._trigger("change",e,this._uiHash()),this.containers[p]._trigger("change",e,this._uiHash(this)),this.currentContainer=this.containers[p],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[p]._trigger("over",e,this._uiHash(this)),this.containers[p].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===this.document[0].body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,"document"===n.containment?this.document.width():this.window.width()-this.helperProportions.width-this.margins.left,("document"===n.containment?this.document.height()||document.body.parentNode.scrollHeight:this.window.height()||this.document[0].body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n=this.options,o=e.pageX,a=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,l=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==this.document[0]&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.leftthis.containment[2]&&(o=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(a=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((a-this.originalPageY)/n.grid[1])*n.grid[1],a=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((o-this.originalPageX)/n.grid[0])*n.grid[0],o=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:a-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():l?0:r.scrollTop()),left:o-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():l?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){function i(t,e,i){return function(s){i._trigger(t,s,e._uiHash(e))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&n.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||n.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(n.push(function(t){this._trigger("remove",t,this._uiHash())}),n.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)e||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!e){for(s=0;n.length>s;s++)n[s].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!this.cancelHelperRemoval},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}});var o=/ui-corner-([a-z]){2,6}/g;t.widget("ui.controlgroup",{version:"1.12.1",defaultElement:"
    ",options:{direction:"horizontal",disabled:null,onlyVisible:!0,items:{button:"input[type=button], input[type=submit], input[type=reset], button, a",controlgroupLabel:".ui-controlgroup-label",checkboxradio:"input[type='checkbox'], input[type='radio']",selectmenu:"select",spinner:".ui-spinner-input"}},_create:function(){this._enhance()},_enhance:function(){this.element.attr("role","toolbar"),this.refresh()},_destroy:function(){this._callChildMethod("destroy"),this.childWidgets.removeData("ui-controlgroup-data"),this.element.removeAttr("role"),this.options.items.controlgroupLabel&&this.element.find(this.options.items.controlgroupLabel).find(".ui-controlgroup-label-contents").contents().unwrap()},_initWidgets:function(){var e=this,i=[];t.each(this.options.items,function(s,n){var o,a={};return n?"controlgroupLabel"===s?(o=e.element.find(n),o.each(function(){var e=t(this);e.children(".ui-controlgroup-label-contents").length||e.contents().wrapAll("")}),e._addClass(o,null,"ui-widget ui-widget-content ui-state-default"),i=i.concat(o.get()),void 0):(t.fn[s]&&(a=e["_"+s+"Options"]?e["_"+s+"Options"]("middle"):{classes:{}},e.element.find(n).each(function(){var n=t(this),o=n[s]("instance"),r=t.widget.extend({},a);if("button"!==s||!n.parent(".ui-spinner").length){o||(o=n[s]()[s]("instance")),o&&(r.classes=e._resolveClassesValues(r.classes,o)),n[s](r);var l=n[s]("widget");t.data(l[0],"ui-controlgroup-data",o?o:n[s]("instance")),i.push(l[0])}})),void 0):void 0}),this.childWidgets=t(t.unique(i)),this._addClass(this.childWidgets,"ui-controlgroup-item")},_callChildMethod:function(e){this.childWidgets.each(function(){var i=t(this),s=i.data("ui-controlgroup-data");s&&s[e]&&s[e]()})},_updateCornerClass:function(t,e){var i="ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all",s=this._buildSimpleOptions(e,"label").classes.label;this._removeClass(t,null,i),this._addClass(t,null,s)},_buildSimpleOptions:function(t,e){var i="vertical"===this.options.direction,s={classes:{}};return s.classes[e]={middle:"",first:"ui-corner-"+(i?"top":"left"),last:"ui-corner-"+(i?"bottom":"right"),only:"ui-corner-all"}[t],s},_spinnerOptions:function(t){var e=this._buildSimpleOptions(t,"ui-spinner");return e.classes["ui-spinner-up"]="",e.classes["ui-spinner-down"]="",e},_buttonOptions:function(t){return this._buildSimpleOptions(t,"ui-button")},_checkboxradioOptions:function(t){return this._buildSimpleOptions(t,"ui-checkboxradio-label")},_selectmenuOptions:function(t){var e="vertical"===this.options.direction;return{width:e?"auto":!1,classes:{middle:{"ui-selectmenu-button-open":"","ui-selectmenu-button-closed":""},first:{"ui-selectmenu-button-open":"ui-corner-"+(e?"top":"tl"),"ui-selectmenu-button-closed":"ui-corner-"+(e?"top":"left")},last:{"ui-selectmenu-button-open":e?"":"ui-corner-tr","ui-selectmenu-button-closed":"ui-corner-"+(e?"bottom":"right")},only:{"ui-selectmenu-button-open":"ui-corner-top","ui-selectmenu-button-closed":"ui-corner-all"}}[t]}},_resolveClassesValues:function(e,i){var s={};return t.each(e,function(n){var a=i.options.classes[n]||"";a=t.trim(a.replace(o,"")),s[n]=(a+" "+e[n]).replace(/\s+/g," ")}),s},_setOption:function(t,e){return"direction"===t&&this._removeClass("ui-controlgroup-"+this.options.direction),this._super(t,e),"disabled"===t?(this._callChildMethod(e?"disable":"enable"),void 0):(this.refresh(),void 0)},refresh:function(){var e,i=this;this._addClass("ui-controlgroup ui-controlgroup-"+this.options.direction),"horizontal"===this.options.direction&&this._addClass(null,"ui-helper-clearfix"),this._initWidgets(),e=this.childWidgets,this.options.onlyVisible&&(e=e.filter(":visible")),e.length&&(t.each(["first","last"],function(t,s){var n=e[s]().data("ui-controlgroup-data");if(n&&i["_"+n.widgetName+"Options"]){var o=i["_"+n.widgetName+"Options"](1===e.length?"only":s);o.classes=i._resolveClassesValues(o.classes,n),n.element[n.widgetName](o)}else i._updateCornerClass(e[s](),s)}),this._callChildMethod("refresh"))}}),t.widget("ui.checkboxradio",[t.ui.formResetMixin,{version:"1.12.1",options:{disabled:null,label:null,icon:!0,classes:{"ui-checkboxradio-label":"ui-corner-all","ui-checkboxradio-icon":"ui-corner-all"}},_getCreateOptions:function(){var e,i,s=this,n=this._super()||{};return this._readType(),i=this.element.labels(),this.label=t(i[i.length-1]),this.label.length||t.error("No label found for checkboxradio widget"),this.originalLabel="",this.label.contents().not(this.element[0]).each(function(){s.originalLabel+=3===this.nodeType?t(this).text():this.outerHTML}),this.originalLabel&&(n.label=this.originalLabel),e=this.element[0].disabled,null!=e&&(n.disabled=e),n},_create:function(){var t=this.element[0].checked;this._bindFormResetHandler(),null==this.options.disabled&&(this.options.disabled=this.element[0].disabled),this._setOption("disabled",this.options.disabled),this._addClass("ui-checkboxradio","ui-helper-hidden-accessible"),this._addClass(this.label,"ui-checkboxradio-label","ui-button ui-widget"),"radio"===this.type&&this._addClass(this.label,"ui-checkboxradio-radio-label"),this.options.label&&this.options.label!==this.originalLabel?this._updateLabel():this.originalLabel&&(this.options.label=this.originalLabel),this._enhance(),t&&(this._addClass(this.label,"ui-checkboxradio-checked","ui-state-active"),this.icon&&this._addClass(this.icon,null,"ui-state-hover")),this._on({change:"_toggleClasses",focus:function(){this._addClass(this.label,null,"ui-state-focus ui-visual-focus")},blur:function(){this._removeClass(this.label,null,"ui-state-focus ui-visual-focus")}})},_readType:function(){var e=this.element[0].nodeName.toLowerCase();this.type=this.element[0].type,"input"===e&&/radio|checkbox/.test(this.type)||t.error("Can't create checkboxradio on element.nodeName="+e+" and element.type="+this.type)},_enhance:function(){this._updateIcon(this.element[0].checked)},widget:function(){return this.label},_getRadioGroup:function(){var e,i=this.element[0].name,s="input[name='"+t.ui.escapeSelector(i)+"']";return i?(e=this.form.length?t(this.form[0].elements).filter(s):t(s).filter(function(){return 0===t(this).form().length}),e.not(this.element)):t([])},_toggleClasses:function(){var e=this.element[0].checked;this._toggleClass(this.label,"ui-checkboxradio-checked","ui-state-active",e),this.options.icon&&"checkbox"===this.type&&this._toggleClass(this.icon,null,"ui-icon-check ui-state-checked",e)._toggleClass(this.icon,null,"ui-icon-blank",!e),"radio"===this.type&&this._getRadioGroup().each(function(){var e=t(this).checkboxradio("instance");e&&e._removeClass(e.label,"ui-checkboxradio-checked","ui-state-active")})},_destroy:function(){this._unbindFormResetHandler(),this.icon&&(this.icon.remove(),this.iconSpace.remove())},_setOption:function(t,e){return"label"!==t||e?(this._super(t,e),"disabled"===t?(this._toggleClass(this.label,null,"ui-state-disabled",e),this.element[0].disabled=e,void 0):(this.refresh(),void 0)):void 0},_updateIcon:function(e){var i="ui-icon ui-icon-background ";this.options.icon?(this.icon||(this.icon=t(""),this.iconSpace=t(" "),this._addClass(this.iconSpace,"ui-checkboxradio-icon-space")),"checkbox"===this.type?(i+=e?"ui-icon-check ui-state-checked":"ui-icon-blank",this._removeClass(this.icon,null,e?"ui-icon-blank":"ui-icon-check")):i+="ui-icon-blank",this._addClass(this.icon,"ui-checkboxradio-icon",i),e||this._removeClass(this.icon,null,"ui-icon-check ui-state-checked"),this.icon.prependTo(this.label).after(this.iconSpace)):void 0!==this.icon&&(this.icon.remove(),this.iconSpace.remove(),delete this.icon)},_updateLabel:function(){var t=this.label.contents().not(this.element[0]);this.icon&&(t=t.not(this.icon[0])),this.iconSpace&&(t=t.not(this.iconSpace[0])),t.remove(),this.label.append(this.options.label)},refresh:function(){var t=this.element[0].checked,e=this.element[0].disabled;this._updateIcon(t),this._toggleClass(this.label,"ui-checkboxradio-checked","ui-state-active",t),null!==this.options.label&&this._updateLabel(),e!==this.options.disabled&&this._setOptions({disabled:e})}}]),t.ui.checkboxradio,t.widget("ui.button",{version:"1.12.1",defaultElement:"").button({label:t("").text(this.options.closeText).html(),icon:"ui-icon-closethick",showLabel:!1}).appendTo(this.uiDialogTitlebar),this._addClass(this.uiDialogTitlebarClose,"ui-dialog-titlebar-close"),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),e=t("").uniqueId().prependTo(this.uiDialogTitlebar),this._addClass(e,"ui-dialog-title"),this._title(e),this.uiDialogTitlebar.prependTo(this.uiDialog),this.uiDialog.attr({"aria-labelledby":e.attr("id")})},_title:function(t){this.options.title?t.text(this.options.title):t.html(" ")},_createButtonPane:function(){this.uiDialogButtonPane=t("
    "),this._addClass(this.uiDialogButtonPane,"ui-dialog-buttonpane","ui-widget-content ui-helper-clearfix"),this.uiButtonSet=t("
    ").appendTo(this.uiDialogButtonPane),this._addClass(this.uiButtonSet,"ui-dialog-buttonset"),this._createButtons()},_createButtons:function(){var e=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),t.isEmptyObject(i)||t.isArray(i)&&!i.length?(this._removeClass(this.uiDialog,"ui-dialog-buttons"),void 0):(t.each(i,function(i,s){var n,o;s=t.isFunction(s)?{click:s,text:i}:s,s=t.extend({type:"button"},s),n=s.click,o={icon:s.icon,iconPosition:s.iconPosition,showLabel:s.showLabel,icons:s.icons,text:s.text},delete s.click,delete s.icon,delete s.iconPosition,delete s.showLabel,delete s.icons,"boolean"==typeof s.text&&delete s.text,t("",s).button(o).appendTo(e.uiButtonSet).on("click",function(){n.apply(e.element[0],arguments)})}),this._addClass(this.uiDialog,"ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),void 0)},_makeDraggable:function(){function e(t){return{position:t.position,offset:t.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){i._addClass(t(this),"ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,e(n))},drag:function(t,s){i._trigger("drag",t,e(s))},stop:function(n,o){var a=o.offset.left-i.document.scrollLeft(),r=o.offset.top-i.document.scrollTop();s.position={my:"left top",at:"left"+(a>=0?"+":"")+a+" "+"top"+(r>=0?"+":"")+r,of:i.window},i._removeClass(t(this),"ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,e(o))}})},_makeResizable:function(){function e(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}var i=this,s=this.options,n=s.resizable,o=this.uiDialog.css("position"),a="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:a,start:function(s,n){i._addClass(t(this),"ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,e(n))},resize:function(t,s){i._trigger("resize",t,e(s))},stop:function(n,o){var a=i.uiDialog.offset(),r=a.left-i.document.scrollLeft(),l=a.top-i.document.scrollTop();s.height=i.uiDialog.height(),s.width=i.uiDialog.width(),s.position={my:"left top",at:"left"+(r>=0?"+":"")+r+" "+"top"+(l>=0?"+":"")+l,of:i.window},i._removeClass(t(this),"ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,e(o))}}).css("position",o)},_trackFocus:function(){this._on(this.widget(),{focusin:function(e){this._makeFocusTarget(),this._focusedElement=t(e.target)}})},_makeFocusTarget:function(){this._untrackInstance(),this._trackingInstances().unshift(this)},_untrackInstance:function(){var e=this._trackingInstances(),i=t.inArray(this,e);-1!==i&&e.splice(i,1)},_trackingInstances:function(){var t=this.document.data("ui-dialog-instances");return t||(t=[],this.document.data("ui-dialog-instances",t)),t},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(e){var i=this,s=!1,n={};t.each(e,function(t,e){i._setOption(t,e),t in i.sizeRelatedOptions&&(s=!0),t in i.resizableRelatedOptions&&(n[t]=e)}),s&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",n)},_setOption:function(e,i){var s,n,o=this.uiDialog;"disabled"!==e&&(this._super(e,i),"appendTo"===e&&this.uiDialog.appendTo(this._appendTo()),"buttons"===e&&this._createButtons(),"closeText"===e&&this.uiDialogTitlebarClose.button({label:t("").text(""+this.options.closeText).html()}),"draggable"===e&&(s=o.is(":data(ui-draggable)"),s&&!i&&o.draggable("destroy"),!s&&i&&this._makeDraggable()),"position"===e&&this._position(),"resizable"===e&&(n=o.is(":data(ui-resizable)"),n&&!i&&o.resizable("destroy"),n&&"string"==typeof i&&o.resizable("option","handles",i),n||i===!1||this._makeResizable()),"title"===e&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var e=t(this);return t("
    ").css({position:"absolute",width:e.outerWidth(),height:e.outerHeight()}).appendTo(e.parent()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(e){return t(e.target).closest(".ui-dialog").length?!0:!!t(e.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var e=!0;this._delay(function(){e=!1}),this.document.data("ui-dialog-overlays")||this._on(this.document,{focusin:function(t){e||this._allowInteraction(t)||(t.preventDefault(),this._trackingInstances()[0]._focusTabbable())}}),this.overlay=t("
    ").appendTo(this._appendTo()),this._addClass(this.overlay,null,"ui-widget-overlay ui-front"),this._on(this.overlay,{mousedown:"_keepFocus"}),this.document.data("ui-dialog-overlays",(this.document.data("ui-dialog-overlays")||0)+1)}},_destroyOverlay:function(){if(this.options.modal&&this.overlay){var t=this.document.data("ui-dialog-overlays")-1;t?this.document.data("ui-dialog-overlays",t):(this._off(this.document,"focusin"),this.document.removeData("ui-dialog-overlays")),this.overlay.remove(),this.overlay=null}}}),t.uiBackCompat!==!1&&t.widget("ui.dialog",t.ui.dialog,{options:{dialogClass:""},_createWrapper:function(){this._super(),this.uiDialog.addClass(this.options.dialogClass)},_setOption:function(t,e){"dialogClass"===t&&this.uiDialog.removeClass(this.options.dialogClass).addClass(e),this._superApply(arguments)}}),t.ui.dialog}); diff --git a/libs/seedrandom.min.js b/libs/seedrandom.min.js new file mode 100644 index 00000000..d3e05383 --- /dev/null +++ b/libs/seedrandom.min.js @@ -0,0 +1 @@ +!function(a,b){var l,c=eval("this"),d=256,g="random",h=b.pow(d,6),i=b.pow(2,52),j=2*i,k=d-1;function m(r,t,e){var u=[],f=q(function n(r,t){var e,o=[],i=typeof r;if(t&&"object"==i)for(e in r)try{o.push(n(r[e],t-1))}catch(n){}return o.length?o:"string"==i?r:r+"\0"}((t=1==t?{entropy:!0}:t||{}).entropy?[r,s(a)]:null==r?function(){try{var n;return l&&(n=l.randomBytes)?n=n(d):(n=new Uint8Array(d),(c.crypto||c.msCrypto).getRandomValues(n)),s(n)}catch(n){var r=c.navigator,t=r&&r.plugins;return[+new Date,c,t,c.screen,s(a)]}}():r,3),u),p=new n(u),m=function(){for(var n=p.g(6),r=h,t=0;n>>=1;return(n+t)/r};return m.int32=function(){return 0|p.g(4)},m.quick=function(){return p.g(4)/4294967296},m.double=m,q(s(p.S),a),(t.pass||e||function(n,r,t,e){return e&&(e.S&&o(e,p),n.state=function(){return o(p,{})}),t?(b[g]=n,r):n})(m,f,"global"in t?t.global:this==b,t.state)}function n(n){var r,t=n.length,u=this,e=0,o=u.i=u.j=0,i=u.S=[];for(t||(n=[t++]);e 2.6 ? "url(#blurFilter)" : "url(#dropShadow)"; - if (scale > 1.5 && scale <= 2.6) {filter = null;} + let filter = scale > 2.6 ? "url(#blurFilter)" : "url(#dropShadow)"; + if (scale > 1.5 && scale <= 2.6) filter = null; coastline.attr("filter", filter); // rescale lables on zoom (active zooming) labels.selectAll("g").each(function(d) { - var el = d3.select(this); + const el = d3.select(this); if (el.attr("id") === "burgLabels") return; - var desired = +el.attr("data-size"); - var relative = rn((desired + (desired / scale)) / 2, 2); + const desired = +el.attr("data-size"); + let relative = rn((desired + (desired / scale)) / 2, 2); if (relative < 2) {relative = 2;} el.attr("font-size", relative); - el.classed("hidden", hideLabels.checked && relative * scale < 6); + if (hideLabels.checked) { + el.classed("hidden", relative * scale < 6); + updateLabelGroups(); + } }); if (ruler.size()) { if (ruler.style("display") !== "none") { if (ruler.selectAll("g").size() < 1) {return;} - var factor = rn(1 / Math.pow(scale, 0.3), 1); + const factor = rn(1 / Math.pow(scale, 0.3), 1); ruler.selectAll("circle:not(.center)").attr("r", 2 * factor).attr("stroke-width", 0.5 * factor); ruler.selectAll("circle.center").attr("r", 1.2 * factor).attr("stroke-width", 0.3 * factor); ruler.selectAll("text").attr("font-size", 10 * factor); @@ -175,22 +195,22 @@ function fantasyMap() { // Changelog dialog window var storedVersion = localStorage.getItem("version"); // show message on load if (storedVersion != version) { - alertMessage.innerHTML = `2018-07-28: + alertMessage.innerHTML = `2018-08-28: The Fantasy Map Generator is updated up to version ${version}. Main changes:

    -
  • Cultures editor
  • -
  • Namesbase editor
  • -
  • Reworked lakes
  • -
  • Options preservation
  • -
  • New filters
  • -
  • Non-island maps (wip)
  • +
  • Random seed support
  • +
  • New heightmap templates
  • +
  • Integration with Medieval Fantasy City Generator
  • +
  • Relocate Burg option
  • +
  • Dialogs style changes, optional transparency
  • +
  • Ability to toggle Label groups separately
  • Bug fixes
  • -
    See
    changelog for older versions. - Please report bugs here. -

    Join our Reddit community +
    See a dedecated post for the details. + Please report bugs here. + Join our Reddit community to share created maps, discuss the Generator, ask questions and propose new features.`; $("#alert").dialog( - {resizable: false, title: "Fantasy Map Generator update", width: 280, + {resizable: false, title: "Fantasy Map Generator update", width: 320, buttons: { "Don't show again": function() { localStorage.setItem("version", version); @@ -202,8 +222,9 @@ function fantasyMap() { }); } + getSeed(); // get and set random generator seed applyNamesData(); // apply default namesbase on load - generate(); // genarate map on load + generate(); // generate map on load applyDefaultStyle(); // apply style on load invokeActiveZooming(); // to hide what need to be hidden @@ -217,7 +238,6 @@ function fantasyMap() { drawScaleBar(); defineHeightmap(); markFeatures(); - //reduceClosedLakes(); drawOcean(); elevateLakes(); resolveDepressionsPrimary(); @@ -230,11 +250,38 @@ function fantasyMap() { drawRelief(); generateCultures(); manorsAndRegions(); + // focus on burg from MFCG + if (from === "MFCG") findBurgForMFCG(); cleanData(); console.timeEnd("TOTAL"); console.groupEnd("Random map"); } + // get or generate map seed + function getSeed() { + const url = new URL(window.location.href); + const s = url.searchParams.get("seed"); + seed = s || Math.floor(Math.random() * 1e9); + console.log(" seed: " + seed); + optionsSeed.value = seed; + Math.seedrandom(seed); + from = url.searchParams.get("from"); + } + + // generate new map seed + function changeSeed() { + seed = Math.floor(Math.random() * 1e9); + console.log(" seed: " + seed); + optionsSeed.value = seed; + Math.seedrandom(seed); + } + + function updateURL() { + const url = new URL(window.location.href); + url.searchParams.set("seed", seed); + if (url.protocol !== "file:") window.history.pushState({seed}, "", "url.search"); + } + // load options from LocalStorage is any function applyStoredOptions() { if (localStorage.getItem("mapWidth") && localStorage.getItem("mapHeight")) { @@ -271,6 +318,11 @@ function fantasyMap() { lockPowerInput.className = "icon-lock"; } if (localStorage.getItem("neutral")) neutralInput.value = neutralOutput.value = localStorage.getItem("neutral"); + if (localStorage.getItem("names")) { + namesInput.value = localStorage.getItem("names"); + lockNamesInput.setAttribute("data-locked", 1) + lockNamesInput.className = "icon-lock"; + } if (localStorage.getItem("cultures")) { culturesInput.value = culturesOutput.value = localStorage.getItem("cultures"); lockCulturesInput.setAttribute("data-locked", 1) @@ -287,10 +339,14 @@ function fantasyMap() { pngResolutionInput.value = localStorage.getItem("pngResolution"); pngResolutionOutput.value = pngResolutionInput.value + "x"; } + if (localStorage.getItem("transparency")) { + transparencyInput.value = transparencyOutput.value = localStorage.getItem("transparency"); + changeDialogsTransparency(transparencyInput.value); + } else {changeDialogsTransparency(0);} } function restoreDefaultOptions() { - // remove saved options from LocalStorage + // remove ALL saved data from LocalStorage localStorage.clear(); // set defaut values mapWidthInput.value = window.innerWidth; @@ -308,6 +364,8 @@ function fantasyMap() { neutralInput.value = neutralOutput.value = 200; swampinessInput.value = swampinessOutput.value = 10; outlineLayersInput.value = "-6,-3,-1"; + transparencyInput.value = transparencyOutput.value = 0; + changeDialogsTransparency(0); pngResolutionInput.value = 5; pngResolutionOutput.value = "5x"; randomizeOptions(); @@ -315,15 +373,9 @@ function fantasyMap() { // apply names data from localStorage if available function applyNamesData() { - const storedNameBases = localStorage.getItem("nameBases"); - const storedNameBase = localStorage.getItem("nameBase"); - if (storedNameBases && storedNameBase) { - nameBases = JSON.parse(storedNameBases); - nameBase = JSON.parse(storedNameBase); - } else { - applyDefaultNamesData(); - } - defaultCultures = [{name:"Shwazen", color:"#b3b3b3", base:0}, + applyDefaultNamesData(); + defaultCultures = [ + {name:"Shwazen", color:"#b3b3b3", base:0}, {name:"Angshire", color:"#fca463", base:1}, {name:"Luari", color:"#99acfb", base:2}, {name:"Tallian", color:"#a6d854", base:3}, @@ -383,6 +435,7 @@ function fantasyMap() { } if (lockPowerInput.getAttribute("data-locked") == 0) powerInput.value = powerOutput.value = rand(2, 8); if (lockNeutralInput.getAttribute("data-locked") == 0) neutralInput.value = neutralOutput.value = rand(100, 300); + if (lockNamesInput.getAttribute("data-locked") == 0) namesInput.value = rand(0, 1); if (lockCulturesInput.getAttribute("data-locked") == 0) culturesInput.value = culturesOutput.value = rand(5, 10); if (lockPrecInput.getAttribute("data-locked") == 0) precInput.value = precOutput.value = rand(10, 25); if (lockSwampinessInput.getAttribute("data-locked") == 0) swampinessInput.value = swampinessOutput.value = rand(100); @@ -392,13 +445,15 @@ function fantasyMap() { function placePoints() { console.time("placePoints"); points = []; - var radius = 5.9 / graphSize; // 5.9 is a radius to get 8k cells - var sampler = poissonDiscSampler(graphWidth, graphHeight, radius); + const mod = rn((graphWidth + graphHeight) / 1500, 2); // screen size modifier + const radius = rn(5.2 * mod / graphSize, 2); // 5.2 is a radius to get 10k cells on 960 x 540 screen and size 1 + const sampler = poissonDiscSampler(graphWidth, graphHeight, radius); while (sample = sampler()) { - var x = rn(sample[0], 2); - var y = rn(sample[1], 2); + const x = rn(sample[0], 2); + const y = rn(sample[1], 2); points.push([x, y]); } + heights = new Uint8Array(points.length); console.timeEnd("placePoints"); } @@ -430,7 +485,8 @@ function fantasyMap() { infoY.innerHTML = rn(point[1]); infoCell.innerHTML = i; infoArea.innerHTML = ifDefined(p.area, "n/a", 2); - infoHeight.innerHTML = ifDefined(p.height, "n/a", 2); + if (customization === 1) {infoHeight.innerHTML = heights[i];} + else {infoHeight.innerHTML = ifDefined(p.height, "n/a");} infoFlux.innerHTML = ifDefined(p.flux, "n/a", 2); let country = p.region === undefined ? "n/a" : p.region === "neutral" ? "neutral" : states[p.region].name + " (" + p.region + ")"; infoCountry.innerHTML = country; @@ -442,6 +498,8 @@ function fantasyMap() { if (feature !== undefined) { const fType = feature.land ? "Island" : feature.border ? "Ocean" : "Lake"; infoFeature.innerHTML = fType + " (" + p.fn + ")"; + } else { + infoFeature.innerHTML = "n/a"; } } @@ -483,7 +541,7 @@ function fantasyMap() { if (customization === 1) { radius = brushRadius.value; if (brushId === "brushHill" || brushId === "brushPit") { - radius = Math.pow(brushPower.value * 400, .5); + radius = Math.pow(brushPower.value * 4, .5); } } else if (customization === 2) radius = countriesManuallyBrush.value; @@ -645,7 +703,7 @@ function fantasyMap() { let radius = r; let selection = [center]; if (radius > 1) selection = selection.concat(cells[center].neighbors); - selection = $.grep(selection, function(e) {return cells[e].height >= 0.2;}); + selection = $.grep(selection, function(e) {return cells[e].height >= 20;}); if (radius === 2) return selection; let frontier = cells[center].neighbors; while (radius > 2) { @@ -654,14 +712,14 @@ function fantasyMap() { cycle.map(function(s) { cells[s].neighbors.forEach(function(e) { if (selection.indexOf(e) !== -1) return; - // if (cells[e].height < 0.2) return; + // if (cells[e].height < 20) return; selection.push(e); frontier.push(e); }); }); radius--; } - selection = $.grep(selection, function(e) {return cells[e].height >= 0.2;}); + selection = $.grep(selection, function(e) {return cells[e].height >= 20;}); return selection; } @@ -712,7 +770,7 @@ function fantasyMap() { if ($("#brushesButtons > .pressed").hasClass("feature")) {return;} // define selection besed on radius let selection = [cell]; - if (radius > 1) {selection = selection.concat(cells[cell].neighbors);} + if (radius > 1) selection = selection.concat(cells[cell].neighbors); if (radius > 2) { let frontier = cells[cell].neighbors; while (radius > 2) { @@ -729,19 +787,23 @@ function fantasyMap() { } } // change each cell in the selection - const sourceHeight = cells[source].height; + const sourceHeight = heights[source]; selection.map(function(s) { // calculate changes if (brush === "brushElevate") { - if (cells[s].height < 0.2) {cells[s].height = 0.2} - else {cells[s].height += power;} + if (heights[s] < 20) {heights[s] = 20;} + else {heights[s] += power;} + if (heights[s] > 100) heights[s] = 100; } - if (brush === "brushDepress") {cells[s].height -= power;} - if (brush === "brushAlign") {cells[s].height = sourceHeight;} + if (brush === "brushDepress") { + heights[s] -= power; + if (heights[s] > 100) heights[s] = 0; + } + if (brush === "brushAlign") {heights[s] = sourceHeight;} if (brush === "brushSmooth") { - let heights = [cells[s].height]; - cells[s].neighbors.forEach(function(e) {heights.push(cells[e].height);}); - cells[s].height = (cells[s].height + d3.mean(heights)) / 2; + let hs = [heights[s]]; + cells[s].neighbors.forEach(function(e) {hs.push(heights[e]);}); + heights[s] = (heights[s] + d3.mean(hs)) / 2; } }); updateHeightmapSelection(selection); @@ -768,14 +830,14 @@ function fantasyMap() { // turn D3 polygons array into cell array, define neighbors for each cell function detectNeighbors(withGrid) { console.time("detectNeighbors"); - var gridPath = ""; // store grid as huge single path string + let gridPath = ""; // store grid as huge single path string cells = []; polygons.map(function(i, d) { - var neighbors = []; - var type; // define cell type + const neighbors = []; + let type; // define cell type if (withGrid) {gridPath += "M" + i.join("L") + "Z";} // grid path diagram.cells[d].halfedges.forEach(function(e) { - var edge = diagram.edges[e], ea; + const edge = diagram.edges[e]; if (edge.left && edge.right) { const ea = edge.left.index === d ? edge.right.index : edge.left.index; neighbors.push(ea); @@ -798,114 +860,146 @@ function fantasyMap() { else if (rnd > 0.7) {templateInput.value = "High Island";} else if (rnd > 0.5) {templateInput.value = "Low Island";} else if (rnd > 0.35) {templateInput.value = "Continents";} - else if (rnd > 0.01) {templateInput.value = "Archipelago";} + else if (rnd > 0.05) {templateInput.value = "Archipelago";} + else if (rnd > 0.03) {templateInput.value = "Mainland";} + else if (rnd > 0.01) {templateInput.value = "Peninsulas";} else {templateInput.value = "Atoll";} } const mapTemplate = templateInput.value; - addMountain(); - const mod = rn((graphWidth + graphHeight) / 1500, 2); // add mod for big screens - if (mapTemplate === "Volcano") {templateVolcano(mod);} - if (mapTemplate === "High Island") {templateHighIsland(mod);} - if (mapTemplate === "Low Island") {templateLowIsland(mod);} - if (mapTemplate === "Continents") {templateContinents(mod);} - if (mapTemplate === "Archipelago") {templateArchipelago(mod);} - if (mapTemplate === "Atoll") {templateAtoll(mod);} + if (mapTemplate === "Volcano") templateVolcano(); + if (mapTemplate === "High Island") templateHighIsland(); + if (mapTemplate === "Low Island") templateLowIsland(); + if (mapTemplate === "Continents") templateContinents(); + if (mapTemplate === "Archipelago") templateArchipelago(); + if (mapTemplate === "Atoll") templateAtoll(); + if (mapTemplate === "Mainland") templateMainland(); + if (mapTemplate === "Peninsulas") templatePeninsulas(); console.log(" template: " + mapTemplate); console.timeEnd('defineHeightmap'); } // Heighmap Template: Volcano function templateVolcano(mod) { - modifyHeights("all", 0.05, 1.1); - addHill(rn(4 * mod), 0.4); - addHill(rn(4 * mod), 0.15); - addRange(rn(4 * mod)); - addRange(rn(-10 * mod)); + addMountain(); + modifyHeights("all", 10, 1); + addHill(5, 0.35); + addRange(3); + addRange(-4); } // Heighmap Template: High Island function templateHighIsland(mod) { - modifyHeights("all", 0.05, 0.9); - addRange(rn(4 * mod)); - addHill(rn(12 * mod), 0.25); - addRange(rn(-8 * mod)); + addMountain(); + modifyHeights("all", 10, 1); + addRange(6); + addHill(12, 0.25); + addRange(-3); modifyHeights("land", 0, 0.75); - addHill(rn(3 * mod), 0.15); + addPit(1); + addHill(3, 0.15); } // Heighmap Template: Low Island function templateLowIsland(mod) { + addMountain(); + modifyHeights("all", 10, 1); smoothHeights(2); - addRange(rn(5 * mod)); - addHill(rn(6 * mod), 0.4); - addHill(rn(14 * mod), 0.2); - addRange(rn(-10 * mod)); + addRange(2); + addHill(4, 0.4); + addHill(12, 0.2); + addRange(-8); modifyHeights("land", 0, 0.35); } // Heighmap Template: Continents function templateContinents(mod) { - addHill(rn(24 * mod), 0.25); - addRange(rn(4 * mod)); - addHill(rn(3 * mod), 0.18); - modifyHeights("land", 0, 0.7); - var count = Math.ceil(Math.random() * 6 + 2); + addMountain(); + modifyHeights("all", 10, 1); + addHill(30, 0.25); + const count = Math.ceil(Math.random() * 4 + 4); addStrait(count); - smoothHeights(3); - addPit(rn(18 * mod)); - addRange(rn(-14 * mod)); - modifyHeights("land", 0, 0.8); - modifyHeights("all", 0.02, 1); + addPit(10); + addRange(-10); + modifyHeights("land", 0, 0.6); + smoothHeights(2); + addRange(3); } // Heighmap Template: Archipelago function templateArchipelago(mod) { - modifyHeights("land", -0.2, 1); - addHill(rn(16 * mod), 0.17); - addRange(rn(8 * mod)); - var count = Math.ceil(Math.random() * 2 + 2); + addMountain(); + modifyHeights("all", 10, 1); + addHill(12, 0.15); + addRange(8); + const count = Math.ceil(Math.random() * 2 + 2); addStrait(count); - addRange(rn(-18 * mod)); - addPit(rn(10 * mod)); - modifyHeights("land", -0.05, 0.7); - smoothHeights(4); + addRange(-15); + addPit(10); + modifyHeights("land", -5, 0.7); + smoothHeights(3); } // Heighmap Template: Atoll function templateAtoll(mod) { - addHill(rn(2 * mod), 0.35); - addRange(rn(2 * mod)); - modifyHeights("all", 0.07, 1); + addMountain(); + modifyHeights("all", 10, 1); + addHill(2, 0.35); + addRange(2); smoothHeights(1); - modifyHeights("0.27-10", 0, 0.1); + modifyHeights("27-100", 0, 0.1); + } + + // Heighmap Template: Mainland + function templateMainland(mod) { + addMountain(); + modifyHeights("all", 10, 1); + addHill(30, 0.2); + addRange(10); + addPit(20); + addHill(10, 0.15); + addRange(-10); + modifyHeights("land", 0, 0.4); + addRange(10); + smoothHeights(3); + } + + // Heighmap Template: Peninsulas + function templatePeninsulas(mod) { + addMountain(); + modifyHeights("all", 15, 1); + addHill(30, 0); + addRange(5); + addPit(15); + const count = Math.ceil(Math.random() * 5 + 15); + addStrait(count); } function addMountain() { - var x = Math.floor(Math.random() * graphWidth / 3 + graphWidth / 3); - var y = Math.floor(Math.random() * graphHeight * 0.2 + graphHeight * 0.4); - var rnd = diagram.find(x, y).index; - var height = Math.random() * 0.1 + 0.9; - add(rnd, "mountain", height); + const x = Math.floor(Math.random() * graphWidth / 3 + graphWidth / 3); + const y = Math.floor(Math.random() * graphHeight * 0.2 + graphHeight * 0.4); + const cell = diagram.find(x, y).index; + const height = Math.random() * 10 + 90; // 90-99 + add(cell, "mountain", height); } + // place with shift 0-0.5 function addHill(count, shift) { - // shift from 0 to 0.5 - for (c = 0; c < count; c++) { - var limit = 0; + for (let c = 0; c < count; c++) { + let limit = 0, cell, height; do { - var height = Math.random() * 0.4 + 0.1; - var x = Math.floor(Math.random() * graphWidth * (1-shift*2) + graphWidth * shift); - var y = Math.floor(Math.random() * graphHeight * (1-shift*2) + graphHeight * shift); - var rnd = diagram.find(x, y).index; - limit ++; - } while (cells[rnd].height + height > 0.9 && limit < 100) - add(rnd, "hill", height); + height = Math.random() * 40 + 10; // 10-50 + const x = Math.floor(Math.random() * graphWidth * (1 - shift * 2) + graphWidth * shift); + const y = Math.floor(Math.random() * graphHeight * (1 - shift * 2) + graphHeight * shift); + cell = diagram.find(x, y).index; + limit++; + } while (heights[cell] + height > 90 && limit < 100) + add(cell, "hill", height); } } function add(start, type, height) { - var session = Math.ceil(Math.random() * 1e5); - var radius, hRadius, mRadius; + const session = Math.ceil(Math.random() * 1e5); + let radius, hRadius, mRadius; switch (+graphSize) { case 1: hRadius = 0.991; mRadius = 0.91; break; case 2: hRadius = 0.9967; mRadius = 0.951; break; @@ -914,18 +1008,15 @@ function fantasyMap() { } radius = type === "mountain" ? mRadius : hRadius; var queue = [start]; - if (type === "mountain") {cells[start].height = height;} - for (i = 0; i < queue.length && height >= 0.01; i++) { - if (type == "mountain") { - height = +cells[queue[i]].height * radius - height / 100; - } else { - height *= radius; - } + if (type === "mountain") heights[start] = height; + for (let i=0; i < queue.length && height >= 1; i++) { + if (type === "mountain") {height = heights[queue[i]] * radius - height / 100;} + else {height *= radius;} cells[queue[i]].neighbors.forEach(function(e) { - if (cells[e].used === session) {return;} - var mod = Math.random() * 0.2 + 0.9; - cells[e].height += height * mod; - if (cells[e].height > 1) {cells[e].height = 1;} + if (cells[e].used === session) return; + const mod = Math.random() * 0.2 + 0.9; // 0.9-1.1 random factor + heights[e] += height * mod; + if (heights[e] > 100) heights[e] = 100; cells[e].used = session; queue.push(e); }); @@ -936,7 +1027,7 @@ function fantasyMap() { var session = Math.ceil(Math.random() * 100000); var count = Math.abs(mod); let range = []; - for (c = 0; c < count; c++) { + for (let c = 0; c < count; c++) { range = []; var diff = 0, start = from, end = to; if (!start || !end) { @@ -951,31 +1042,30 @@ function fantasyMap() { } while (diff < 150 / graphSize || diff > 300 / graphSize) } if (start && end) { - for (var l = 0; start != end && l < 10000; l++) { + for (let l = 0; start != end && l < 10000; l++) { var min = 10000; cells[start].neighbors.forEach(function(e) { diff = Math.hypot(cells[end].data[0] - cells[e].data[0], cells[end].data[1] - cells[e].data[1]); - if (Math.random() > 0.8) {diff = diff / 2} + if (Math.random() > 0.8) diff = diff / 2; if (diff < min) {min = diff, start = e;} }); range.push(start); } } - var change = height ? height : Math.random() * 0.1 + 0.1; + var change = height ? height : Math.random() * 10 + 10; range.map(function(r) { - var rnd = Math.random() * 0.4 + 0.8; - if (mod > 0) {cells[r].height += change * rnd;} - else if (cells[r].height >= 0.1) {cells[r].height -= change * rnd;} + let rnd = Math.random() * 0.4 + 0.8; + if (mod > 0) heights[r] += change * rnd; + else if (heights[r] >= 10) {heights[r] -= change * rnd;} cells[r].neighbors.forEach(function(e) { - if (cells[e].used === session) {return;} + if (cells[e].used === session) return; cells[e].used = session; rnd = Math.random() * 0.4 + 0.8; - if (mod > 0) { - cells[e].height += change / 2 * rnd; - } else if (cells[e].height >= 0.1) { - cells[e].height -= change / 2 * rnd; - } + const ch = change / 2 * rnd; + if (mod > 0) {heights[e] += ch;} else if (heights[e] >= 10) {heights[e] -= ch;} + if (heights[e] > 100) heights[e] = mod > 0 ? 100 : 5; }); + if (heights[r] > 100) heights[r] = mod > 0 ? 100 : 5; }); } return range; @@ -985,10 +1075,10 @@ function fantasyMap() { var session = Math.ceil(Math.random() * 100000); var top = Math.floor(Math.random() * graphWidth * 0.35 + graphWidth * 0.3); var bottom = Math.floor((graphWidth - top) - (graphWidth * 0.1) + (Math.random() * graphWidth * 0.2)); - var start = diagram.find(top, graphHeight * 0.2).index; - var end = diagram.find(bottom, graphHeight * 0.8).index; + var start = diagram.find(top, graphHeight * 0.1).index; + var end = diagram.find(bottom, graphHeight * 0.9).index; var range = []; - for (var l = 0; start !== end && l < 1000; l++) { + for (let l = 0; start !== end && l < 1000; l++) { var min = 10000; // dummy value cells[start].neighbors.forEach(function(e) { diff = Math.hypot(cells[end].data[0] - cells[e].data[0], cells[end].data[1] - cells[e].data[1]); @@ -1004,8 +1094,8 @@ function fantasyMap() { if (cells[e].used === session) {return;} cells[e].used = session; query.push(e); - var height = cells[e].height * 0.23; - cells[e].height = rn(height, 2); + heights[e] *= 0.23; + if (heights[e] > 100 || heights[e] < 5) heights[e] = 5; }); range = query.slice(); }); @@ -1013,33 +1103,33 @@ function fantasyMap() { } function addPit(count, height, cell) { - var session = Math.ceil(Math.random() * 100000); - for (c = 0; c < count; c++) { - var change = height ? height + 0.1 : Math.random() * 0.1 + 0.2; - var start = cell; + const session = Math.ceil(Math.random() * 1e5); + for (let c = 0; c < count; c++) { + let change = height ? height + 10 : Math.random() * 10 + 20; + let start = cell; if (!start) { - var lowlands = $.grep(cells, function(e) {return (e.height >= 0.2);}); - if (lowlands.length == 0) {return;} - var rnd = Math.floor(Math.random() * lowlands.length); + const lowlands = $.grep(cells, function(e) {return (heights[e.index] >= 20);}); + if (!lowlands.length) return; + const rnd = Math.floor(Math.random() * lowlands.length); start = lowlands[rnd].index; } - var query = [start], newQuery= []; + let query = [start], newQuery= []; // depress pit center - cells[start].height -= change; - if (cells[start].height < 0.05) {cells[start].height = 0.05;} + heights[start] -= change; + if (heights[start] < 5 || heights[start] > 100) heights[start] = 5; cells[start].used = session; - for (var i = 1; i < 10000; i++) { - var rnd = Math.random() * 0.4 + 0.8; - change -= i / 60 * rnd; - if (change < 0.01) {return;} + for (let i = 1; i < 10000; i++) { + const rnd = Math.random() * 0.4 + 0.8; + change -= i / 0.6 * rnd; + if (change < 1) break; query.map(function(p) { cells[p].neighbors.forEach(function(e) { - if (cells[e].used === session) {return;} + if (cells[e].used === session) return; cells[e].used = session; - if (Math.random() > 0.8) {return;} + if (Math.random() > 0.8) return; newQuery.push(e); - cells[e].height -= change; - if (cells[e].height < 0.05) {cells[e].height = 0.05;} + heights[e] -= change; + if (heights[e] < 5 || heights[e] > 100) heights[e] = 5; }); }); query = newQuery.slice(); @@ -1048,55 +1138,46 @@ function fantasyMap() { } } - // Modify heights multiplying/adding by value - function modifyHeights(type, add, mult) { - cells.map(function(i) { - if (type === "land") { - if (i.height >= 0.2) { - i.height += add; - var dif = i.height - 0.2; - var factor = mult; - if (mult == "^2") {factor = dif} - if (mult == "^3") {factor = dif * dif;} - i.height = 0.2 + dif * factor; - } - } else if (type === "all") { - if (i.height > 0) { - i.height += add; - i.height *= mult; - } - } else { - var interval = type.split("-"); - if (i.height >= +interval[0] && i.height <= +interval[1]) { - i.height += add; - if ($.isNumeric(mult)) {i.height *= mult; return;} - if (mult.slice(0,1) === "^") { - pow = mult.slice(1); - i.height = Math.pow(i.height, pow); - } - } + // Modify heights adding or multiplying by value + function modifyHeights(range, add, mult) { + function modify(v) { + if (add) v += add; + if (mult !== 1) { + if (mult === "^2") mult = (v - 20) / 100; + if (mult === "^3") mult = ((v - 20) * (v - 20)) / 100; + if (range === "land") {v = 20 + (v - 20) * mult;} + else {v *= mult;} } - }); + if (v < 0) v = 0; + if (v > 100) v = 100; + return v; + } + const limMin = range === "land" ? 20 : range === "all" ? 0 : +range.split("-")[0]; + const limMax = range === "land" || range === "all" ? 100 : +range.split("-")[1]; + + for (let i=0; i < heights.length; i++) { + if (heights[i] < limMin || heights[i] > limMax) continue; + heights[i] = modify(heights[i]); + } } // Smooth heights using mean of neighbors function smoothHeights(fraction) { - var fraction = fraction || 2; - cells.map(function(i) { - var heights = [i.height]; - i.neighbors.forEach(function(e) {heights.push(cells[e].height);}); - i.height = (i.height * (fraction - 1) + d3.mean(heights)) / fraction; - }); + const fr = fraction || 2; + for (let i=0; i < heights.length; i++) { + const nHeights = [heights[i]]; + cells[i].neighbors.forEach(function(e) {nHeights.push(heights[e]);}); + heights[i] = (heights[i] * (fr - 1) + d3.mean(nHeights)) / fr; + } } // Randomize heights a bit function disruptHeights() { - cells.map(function(i) { - if (i.height < 0.18) {return;} - if (Math.random() > 0.5) {return;} - var rnd = rn(2 - Math.random() * 4) / 100; - i.height = rn(i.height + rnd, 2); - }); + for (let i=0; i < heights.length; i++) { + if (heights[i] < 18) continue; + if (Math.random() < 0.5) continue; + heights[i] += 2 - Math.random() * 4; + } } // Mark features (ocean, lakes, islands) @@ -1106,7 +1187,7 @@ function fantasyMap() { for (let i=0, queue=[0]; queue.length > 0; i++) { const cell = cells[queue[0]]; cell.fn = i; // feature number - const land = cell.height >= 0.2; + const land = heights[queue[0]] >= 20; let border = cell.type === "border"; if (border && land) cell.ctype = 2; @@ -1118,7 +1199,7 @@ function fantasyMap() { } cells[q].neighbors.forEach(function(e) { - const eLand = cells[e].height >= 0.2; + const eLand = heights[e] >= 20; if (land === eLand && cells[e].fn === undefined) { cells[e].fn = i; queue.push(e); @@ -1152,12 +1233,12 @@ function fantasyMap() { }, 0); for (let c=0; c < cells.length && lakesNow > 0; c++) { - if (cells[c].height < 0.2) continue; // not land + if (heights[c] < 20) continue; // not land if (cells[c].ctype !== 2) continue; // not near water let ocean = null, lake = null; // find land cells with lake and ocean nearby cells[c].neighbors.forEach(function(n) { - if (cells[n].height >= 0.2) return; + if (heights[n] >= 20) return; const fn = cells[n].fn; if (features[fn].border !== false) ocean = fn; if (fs[fn].border === false) lake = fn; @@ -1167,16 +1248,16 @@ function fantasyMap() { //debug.append("circle").attr("cx", cells[c].data[0]).attr("cy", cells[c].data[1]).attr("r", 2).attr("fill", "red"); lakesNow --; fs[lake].border = ocean; - cells[c].height = 0.19; + heights[c] = 19; cells[c].fn = ocean; cells[c].ctype = -1; - cells[c].neighbors.forEach(function(e) {if (cells[e].height >= 0.2) cells[e].ctype = 2;}); + cells[c].neighbors.forEach(function(e) {if (heights[e] >= 20) cells[e].ctype = 2;}); } } if (lakesInit === lakesNow) return; // nothing was changed for (let i=0; i < cells.length; i++) { - if (cells[i].height >= 0.2) continue; // not water + if (heights[i] >= 20) continue; // not water const fn = cells[i].fn; if (fs[fn].border !== features[fn].border) { cells[i].fn = fs[fn].border; @@ -1243,11 +1324,12 @@ function fantasyMap() { const smallLakesMax = 500; let smallLakes = 0; const evaporation = 2; - cells.map(function(i) { - let height = Math.trunc(i.height * 100) / 100; + cells.map(function(i, d) { + const height = heights[d]; + if (height > 100) console.log(height, d); const pit = i.pit; const ctype = i.ctype; - if (ctype !== -1 && ctype !== -2 && height < 0.2) return; // exclude all depp ocean points + if (ctype !== -1 && ctype !== -2 && height < 20) return; // exclude all depp ocean points const x = rn(i.data[0], 1), y = rn(i.data[1], 1); const fn = i.fn; const harbor = i.harbor; @@ -1258,8 +1340,6 @@ function fantasyMap() { lake = 2; smallLakes++; } - if (height > 1) height = 1; - if (height < 0) height = 0; const region = i.region; // handle value for edit heightmap mode only const culture = i.culture; // handle value for edit heightmap mode only let copy = $.grep(newPoints, function(e) {return (e[0] == x && e[1] == y);}); @@ -1304,7 +1384,7 @@ function fantasyMap() { calculateVoronoi(newPoints); // recalculate Voronoi diagram using new points let gridPath = ""; // store grid as huge single path string cells.map(function(i, d) { - if (i.height >= 0.2) { + if (i.height >= 20) { // calc cell area i.area = rn(Math.abs(d3.polygonArea(polygons[d])), 2); const prec = rn(avPrec * i.area, 2); @@ -1314,12 +1394,12 @@ function fantasyMap() { diagram.cells[d].halfedges.forEach(function(e) { const edge = diagram.edges[e]; if (edge.left === undefined || edge.right === undefined) { - if (i.height >= 0.2) i.ctype = 99; // border cell + if (i.height >= 20) i.ctype = 99; // border cell return; } const ea = edge.left.index === d ? edge.right.index : edge.left.index; neighbors.push(ea); - if (d < ea && i.height >= 0.2 && i.lake !== 1 && cells[ea].height >= 0.2 && cells[ea].lake !== 1) { + if (d < ea && i.height >= 20 && i.lake !== 1 && cells[ea].height >= 20 && cells[ea].lake !== 1) { gridPath += "M" + edge[0][0] + "," + edge[0][1] + "L" + edge[1][0] + "," + edge[1][1]; } }); @@ -1333,55 +1413,51 @@ function fantasyMap() { // redraw all cells for Customization 1 mode function mockHeightmap() { - let heights = []; let landCells = 0; $("#landmass").empty(); - const limit = renderOcean.checked ? -1 : 0.2; - cells.map(function(i) { - if (i.height < limit) return; - const clr = color(1 - i.height); - landmass.append("path").attr("id", "cell"+i.index) - .attr("d", "M" + polygons[i.index].join("L") + "Z") + const limit = renderOcean.checked ? 1 : 20; + for (let i=0; i < heights.length; i++) { + if (heights[i] < limit) continue; + if (heights[i] > 100) heights[i] = 100; + const clr = color(1 - heights[i] / 100); + landmass.append("path").attr("id", "cell"+i) + .attr("d", "M" + polygons[i].join("L") + "Z") .attr("fill", clr).attr("stroke", clr); - }); + } } $("#renderOcean").click(mockHeightmap); // draw or update all cells function updateHeightmap() { - cells.map(function(c) { - let height = c.height; - if (height > 1) height = 1; - if (height < 0) height = 0; - c.height = height; - let cell = landmass.select("#cell"+c.index); - const clr = color(1 - height); + const limit = renderOcean.checked ? 1 : 20; + for (let i=0; i < heights.length; i++) { + if (heights[i] > 100) heights[i] = 100; + let cell = landmass.select("#cell"+i); + const clr = color(1 - heights[i] / 100); if (cell.size()) { - if (height < 0.2) {cell.remove();} + if (heights[i] < limit) {cell.remove();} else {cell.attr("fill", clr).attr("stroke", clr);} - } else if (height >= 0.2) { - cell = landmass.append("path").attr("id", "cell"+c.index) - .attr("d", "M" + polygons[c.index].join("L") + "Z") + } else if (heights[i] >= limit) { + cell = landmass.append("path").attr("id", "cell"+i) + .attr("d", "M" + polygons[i].join("L") + "Z") .attr("fill", clr).attr("stroke", clr); } - }); + } } // draw or update cells from the selection function updateHeightmapSelection(selection) { - if (selection === undefined) {selection = cells;} + if (selection === undefined) return; + const limit = renderOcean.checked ? 1 : 20; selection.map(function(s) { - let height = cells[s].height; - if (height > 1) {height = 1;} - if (height < 0) {height = 0;} - cells[s].height = height; + if (heights[s] > 100) heights[s] = 100; let cell = landmass.select("#cell"+s); - const clr = color(1 - height); + const clr = color(1 - heights[s] / 100); if (cell.size()) { - if (height < 0.2) {cell.remove();} + if (heights[s] < limit) {cell.remove();} else {cell.attr("fill", clr).attr("stroke", clr);} - } else if (height >= 0.2) { + } else if (heights[s] >= limit) { cell = landmass.append("path").attr("id", "cell"+s) .attr("d", "M" + polygons[s].join("L") + "Z") .attr("fill", clr).attr("stroke", clr); @@ -1390,22 +1466,24 @@ function fantasyMap() { } function updateHistory() { - let heights = []; - let landCells = 0; - cells.map(function(c) { - heights.push(c.height); - if (c.height >= 0.2) landCells++; - }); + let landCells = 0; // count number of land cells + if (renderOcean.checked) { + landCells = heights.reduce(function(s, v) {if (v >= 20) {return s + 1;} else {return s;}}, 0); + } else { + landCells = landmass.selectAll("*").size(); + } history = history.slice(0, historyStage); - history[historyStage] = heights; + history[historyStage] = heights.slice(); historyStage++; undo.disabled = templateUndo.disabled = historyStage > 1 ? false : true; redo.disabled = templateRedo.disabled = true; - var elevationAverage = rn(d3.mean(heights), 2); - var landRatio = rn(landCells / cells.length * 100); - landmassCounter.innerHTML = landCells + " (" + landRatio + "%); Average Elevation: " + elevationAverage; - // if perspective is displayed, update it - if ($("#perspectivePanel").is(":visible")) {drawPerspective();} + const landMean = Math.trunc(d3.mean(heights)); + const landRatio = rn(landCells / heights.length * 100); + landmassCounter.innerHTML = landCells; + landmassRatio.innerHTML = landRatio; + landmassAverage.innerHTML = landMean; + // if perspective view dialog is opened, update it + if ($("#perspectivePanel").is(":visible")) drawPerspective(); } // restoreHistory @@ -1413,9 +1491,8 @@ function fantasyMap() { historyStage = step; redo.disabled = templateRedo.disabled = historyStage < history.length ? false : true; undo.disabled = templateUndo.disabled = historyStage > 1 ? false : true; - let heights = history[historyStage - 1]; - if (heights === undefined) {return;} - cells.map(function(i, d) {i.height = heights[d];}); + if (history[historyStage - 1] === undefined) return; + heights = history[historyStage - 1].slice(); updateHeightmap(); } @@ -1439,7 +1516,7 @@ function fantasyMap() { for (let i=0; i < land.length; i++) { const id = land[i].index, cell = diagram.cells[id]; const f = land[i].fn; - land[i].height = Math.trunc(land[i].height * 100) / 100; + land[i].height = Math.trunc(land[i].height); if (!oceanEdges[f]) {oceanEdges[f] = []; lakeEdges[f] = [];} cell.halfedges.forEach(function(e) { const edge = diagram.edges[e]; @@ -1447,8 +1524,8 @@ function fantasyMap() { const end = edge[1].join(" "); if (edge.left && edge.right) { const ea = edge.left.index === id ? edge.right.index : edge.left.index; - cells[ea].height = Math.trunc(cells[ea].height * 100) / 100; - if (cells[ea].height < 0.2) { + cells[ea].height = Math.trunc(cells[ea].height); + if (cells[ea].height < 20) { cells[ea].ctype = -1; if (land[i].ctype !== 1) { land[i].ctype = 1; // mark coastal land cells @@ -1532,7 +1609,7 @@ function fantasyMap() { scaleBar.append("line").attr("x1", x).attr("y1", y).attr("x2", x+l+size).attr("y2", y) .attr("stroke-width", rn(size * 3, 2)).attr("stroke-dasharray", dash).attr("stroke", "#3d3d3d"); // big scale - for (var b = 0; b < 6; b++) { + for (let b = 0; b < 6; b++) { var value = rn(b * l / 5, 2); var label = rn(value * dScale / scale); if (b === 5) { @@ -1577,12 +1654,11 @@ function fantasyMap() { function elementDrag() { const el = d3.select(this); const tr = parseTransform(el.attr("transform")); - const x = d3.event.x, y = d3.event.y; - const dx = +tr[0] - x, dy = +tr[1] - y; + const dx = +tr[0] - d3.event.x, dy = +tr[1] - d3.event.y; d3.event.on("drag", function() { const x = d3.event.x, y = d3.event.y; - const transform = `translate(${(dx+x)},${(dy+y)})`; + const transform = `translate(${(dx+x)},${(dy+y)}) rotate(${tr[2]} ${tr[3]} ${tr[4]})`; el.attr("transform", transform); const pp = this.parentNode.parentNode.id; if (pp === "burgIcons" || pp === "burgLabels") { @@ -1765,13 +1841,13 @@ function fantasyMap() { // temporary elevate lakes to min neighbors heights to correctly flux the water function elevateLakes() { console.time('elevateLakes'); - const lakes = $.grep(cells, function(e) {return e.height < 0.2 && !features[e.fn].border;}); + const lakes = $.grep(cells, function(e, d) {return heights[d] < 20 && !features[e.fn].border;}); lakes.sort(function(a, b) {return b.height - a.height;}); for (let i=0; i < lakes.length; i++) { - const heights = []; - lakes[i].neighbors.forEach(function(n) {if (cells[n].height >= 0.2) heights.push(cells[n].height)}); - if (heights.length) lakes[i].height = Math.trunc((d3.min(heights) - 0.01) * 100) / 100; - if (cells[i].height < 0.2) lakes[i].height = 0.2; + const hs = [], id = lakes[i].index; + lakes[i].neighbors.forEach(function(n) {if (cells[n].height >= 20) hs.push(cells[n].height)}); + if (hs.length) heights[id] = d3.min(hs) - 1; + if (heights[id] < 20) heights[id] = 20; lakes[i].lake = 1; } console.timeEnd('elevateLakes'); @@ -1780,19 +1856,20 @@ function fantasyMap() { // Depression filling algorithm (for a correct water flux modeling; phase1) function resolveDepressionsPrimary() { console.time('resolveDepressionsPrimary'); - land = $.grep(cells, function(e) {return e.height >= 0.2;}); - land.sort(function(a, b) {return b.height - a.height;}); + land = $.grep(cells, function(e, d) {return heights[d] >= 20;}); + land.sort(function(a, b) {return heights[b.index] - heights[a.index];}); const limit = 10; for (let l = 0, depression = 1; depression > 0 && l < limit; l++) { depression = 0; for (let i = 0; i < land.length; i++) { + const id = land[i].index; if (land[i].type === "border") continue; - const heights = land[i].neighbors.map(function(n) {return cells[n].height}); - const minHigh = d3.min(heights); - if (land[i].height <= minHigh) { + const hs = land[i].neighbors.map(function(n) {return heights[n];}); + const minHigh = d3.min(hs); + if (heights[id] <= minHigh) { depression++; land[i].pit = land[i].pit ? land[i].pit + 1 : 1; - land[i].height = Math.trunc((minHigh + 0.02) * 100) / 100; + heights[id] = minHigh + 2; } } if (l === 0) console.log(" depressions init: " + depression); @@ -1803,7 +1880,7 @@ function fantasyMap() { // Depression filling algorithm (for a correct water flux modeling; phase2) function resolveDepressionsSecondary() { console.time('resolveDepressionsSecondary'); - land = $.grep(cells, function(e) {return e.height >= 0.2;}); + land = $.grep(cells, function(e) {return e.height >= 20;}); land.sort(function(a, b) {return b.height - a.height;}); const limit = 100; for (let l = 0, depression = 1; depression > 0 && l < limit; l++) { @@ -1815,7 +1892,7 @@ function fantasyMap() { if (land[i].height <= minHigh) { depression++; land[i].pit = land[i].pit ? land[i].pit + 1 : 1; - land[i].height = Math.trunc((minHigh + 0.02) * 100) / 100; + land[i].height = Math.trunc(minHigh + 2); } } if (l === 0) console.log(" depressions reGraphed: " + depression); @@ -1827,8 +1904,8 @@ function fantasyMap() { function restoreCustomHeights() { land.forEach(function(l) { if (l.pit) { - l.height = Math.trunc(l.height * 100 - l.pit * 2) / 100; - if (l.height < 0.2) l.height = 0.2; + l.height = Math.trunc(l.height - l.pit * 2); + if (l.height < 20) l.height = 20; } }); } @@ -1861,7 +1938,7 @@ function fantasyMap() { land[i].flux = 0; } } - let minHeight = 10, min; + let minHeight = 1000, min; land[i].neighbors.forEach(function(e) { if (cells[e].height < minHeight) { minHeight = cells[e].height; @@ -1892,7 +1969,7 @@ function fantasyMap() { minRiverL -= 1; } // mark confluences - if (cells[min].height >= 0.2 && iRiverL > 1 && minRiverL > 1) { + if (cells[min].height >= 20 && iRiverL > 1 && minRiverL > 1) { if (!cells[min].confluence) { cells[min].confluence = minRiverL-1; } else { @@ -1905,7 +1982,7 @@ function fantasyMap() { if (land[i].river !== undefined) { const px = cells[min].data[0]; const py = cells[min].data[1]; - if (cells[min].height < 0.2) { + if (cells[min].height < 20) { // pour water to the sea const x = (px + sx) / 2 + (px - sx) / 10; const y = (py + sy) / 2 + (py - sy) / 10; @@ -1926,7 +2003,7 @@ function fantasyMap() { function drawRiverLines(riverNext) { console.time('drawRiverLines'); - for (var i = 0; i < riverNext; i++) { + for (let i = 0; i < riverNext; i++) { var dataRiver = $.grep(riversData, function(e) {return e.river === i;}); if (dataRiver.length > 1) { var riverAmended = amendRiver(dataRiver, 1); @@ -1943,7 +2020,7 @@ function fantasyMap() { // add more river points on 1/3 and 2/3 of length function amendRiver(dataRiver, rndFactor) { var riverAmended = [], side = 1; - for (var r = 0; r < dataRiver.length; r++) { + for (let r = 0; r < dataRiver.length; r++) { var dX = dataRiver[r].x; var dY = dataRiver[r].y; var cell = dataRiver[r].cell; @@ -2007,7 +2084,7 @@ function fantasyMap() { riverPointsRight.unshift({scX:xRight, scY:yRight}); // middle points - for (var p = 1; p < last; p ++) { + for (let p = 1; p < last; p ++) { x = points[p][0], y = points[p][1], c = points[p][2]; if (c) {extraOffset += Math.atan(c * 10 / widening);} // confluence var xPrev = points[p-1][0], yPrev = points[p-1][1]; @@ -2088,13 +2165,13 @@ function fantasyMap() { for (let i=0; i < land.length; i++) { // elavate all big lakes if (land[i].lake === 1) { - land[i].height = 0.19; + land[i].height = 19; land[i].ctype = -1; } // define eligible small lakes if (land[i].lake === 2 && smallLakes < 100) { if (land[i].river !== undefined) { - land[i].height = 0.19; + land[i].height = 19; land[i].ctype = -1; land[i].fn = -1; smallLakes++; @@ -2103,7 +2180,7 @@ function fantasyMap() { land[i].neighbors.forEach(function(n) { if (cells[n].lake !== 1 && cells[n].river !== undefined) { cells[n].lake = 2; - cells[n].height = 0.19; + cells[n].height = 19; cells[n].ctype = -1; cells[n].fn = -1; smallLakes++; @@ -2140,12 +2217,12 @@ function fantasyMap() { unmarked = $.grep(land, function(e) {return e.fn === -1}); } - land = $.grep(cells, function(e) {return e.height >= 0.2;}); + land = $.grep(cells, function(e) {return e.height >= 20;}); console.timeEnd('addLakes'); } function editRiver() { - if (customization) {return;} + if (customization) return; if (elSelected) { const self = d3.select(this).attr("id") === elSelected.attr("id"); const point = d3.mouse(this); @@ -2221,7 +2298,7 @@ function fantasyMap() { let inc = l / parts; // increment if (inc === Infinity) {inc = l;} // 2 control points for short rivers // draw control points - for (var i = l, c = l; i > 0; i -= inc, c += inc) { + for (let i = l, c = l; i > 0; i -= inc, c += inc) { const p1 = node.getPointAtLength(i); const p2 = node.getPointAtLength(c); const p = [(p1.x + p2.x) / 2, (p1.y + p2.y) / 2]; @@ -2286,7 +2363,7 @@ function fantasyMap() { const parts = (l / 8) >> 0; // number of points let inc = l / parts; // increment if (inc === Infinity) {inc = l;} // 2 control points for short rivers - for (var i = l, e = l; i > 0; i -= inc, e += inc) { + for (let i = l, e = l; i > 0; i -= inc, e += inc) { p1 = node.getPointAtLength(i); p2 = node.getPointAtLength(e); x = (p1.x + p2.x) / 2, y = (p1.y + p2.y) / 2; @@ -2299,7 +2376,7 @@ function fantasyMap() { points.push([x, y]); // amend points const rndFactor = 0.3 + Math.random() * 1.4; // random factor in range 0.2-1.8 - for (var i = 0; i < points.length; i++) { + for (let i = 0; i < points.length; i++) { x = points[i][0], y = points[i][1]; amended.push([x, y]); // add additional semi-random point @@ -2534,7 +2611,7 @@ function fantasyMap() { let inc = l / parts; // increment if (inc === Infinity) {inc = l;} // 2 control points for short routes // draw control points - for (var i = 0; i <= l; i += inc) { + for (let i = 0; i <= l; i += inc) { const p = node.getPointAtLength(i); addRoutePoint(p); } @@ -2584,8 +2661,8 @@ function fantasyMap() { if (!elSelected) { const index = getIndex(point); const height = cells[index].height; - if (height < 0.2) routeType = "searoutes"; - if (routeType === "searoutes" && height >= 0.2) routeType = "roads"; + if (height < 20) routeType = "searoutes"; + if (routeType === "searoutes" && height >= 20) routeType = "roads"; } const group = routes.select("#"+routeType); addRoutePoint({x, y}); @@ -2619,7 +2696,7 @@ function fantasyMap() { const node = elSelected.node(); const l = node.getTotalLength(); let pathCells = []; - for (var i = 0; i <= l; i ++) { + for (let i = 0; i <= l; i ++) { const p = node.getPointAtLength(i); const cell = diagram.find(p.x, p.y); if (!cell) {return;} @@ -2867,7 +2944,7 @@ function fantasyMap() { const cx = bbox.x; const cy = bbox.y + bbox.height / 2; const cell = diagram.find(cx, cy).index; - const height = cell !== undefined ? cells[cell].height : 0.5; + const height = cell !== undefined ? cells[cell].height : 50; elSelected.remove(); elSelected = addReliefIcon(height, type, cx, cy); elSelected.call(d3.drag().on("start", elementDrag)); @@ -2949,10 +3026,9 @@ function fantasyMap() { burgSetLabelSize.value = labelGroup.attr("data-size"); burgLabelColorInput.value = toHEX(labelGroup.attr("fill")); burgLabelOpacity.value = labelGroup.attr("opacity") === undefined ? 1 : +labelGroup.attr("opacity"); - const matrix = elSelected.attr("transform"); - const rotation = matrix ? matrix.split('(')[1].split(')')[0].split(' ')[0] : 0; - burgLabelAngle.value = rotation; - burgLabelAngleOutput.innerHTML = rotation + "°"; + const tr = parseTransform(elSelected.attr("transform")); + burgLabelAngle.value = tr[2]; + burgLabelAngleOutput.innerHTML = Math.abs(+tr[2]) + "°"; burgIconSize.value = iconGroup.attr("size"); burgIconFillOpacity.value = iconGroup.attr("fill-opacity") === undefined ? 1 : +iconGroup.attr("fill-opacity"); burgIconFillColor.value = iconGroup.attr("fill"); @@ -3046,6 +3122,7 @@ function fantasyMap() { burgSelectGroup.add(opt); $("#burgSelectGroup").val(newGroup).change(); $("#burgSelectGroup, #burgInputGroup").toggle(); + updateLabelGroups(); }); $("#burgAddGroup").click(function() { @@ -3163,13 +3240,15 @@ function fantasyMap() { group.attr("opacity", +this.value); }); - $("#burgLabelAngle").on("input", function() { + $("#burgLabelAngle").change(function() { const id = +elSelected.attr("data-id"); const el = burgLabels.select("[data-id='"+ id +"']"); + const tr = parseTransform(el.attr("transform")); const c = el.node().getBBox(); - const rotate = `rotate(${this.value} ${(c.x+c.width/2)} ${(c.y+c.height/2)})`; - el.attr("transform", rotate); burgLabelAngleOutput.innerHTML = Math.abs(+this.value) + "°"; + const angle = +this.value; + const transform = `translate(${tr[0]},${tr[1]}) rotate(${angle} ${(c.x+c.width/2)} ${(c.y+c.height/2)})`; + el.attr("transform", transform); }); $("#burgIconSize").on("input", function() { @@ -3274,7 +3353,7 @@ function fantasyMap() { const i = +$("#burgRelocate").attr("data-id"); if (isNaN(i) || !manors[i]) return; - if (cells[index].height < 0.2) { + if (cells[index].height < 20) { tip("Cannot place burg in the water! Select a land cell", null, "error"); return; } @@ -3288,7 +3367,7 @@ function fantasyMap() { let region = cells[index].region; const oldRegion = manors[i].region; - // relocating capital to other country you "conqure" thid cell + // relocating capital to other country you "conquer" target cell if (states[oldRegion] && states[oldRegion].capital === i) { if (region !== oldRegion) { tip("Capital cannot be moved to another country!", null, "error"); @@ -3322,6 +3401,25 @@ function fantasyMap() { manors[i].x = x, manors[i].y = y, manors[i].region = region, manors[i].cell = index; } + // open in MFCG + $("#burgSeeInMFCG").click(function() { + const id = +elSelected.attr("data-id"); + const cell = manors[id].cell; + const pop = rn(manors[id].population); + const size = pop > 65 ? 65 : pop < 6 ? 6 : pop; + const s = seed + "" + id; + const hub = cells[cell].crossroad > 2 ? 1 : 0; + const river = cells[cell].river ? 1 : 0; + const coast = cells[cell].port !== undefined ? 1 : 0; + const sec = pop > 40 ? 1 : Math.random() < pop / 100 ? 1 : 0; + const thr = sec && Math.random() < 0.8 ? 1 : 0; + const url = "http://fantasycities.watabou.ru/"; + let params = `?size=${size}&seed=${s}&hub=${hub}&random=0&continuous=0` + params += `&river=${river}&coast=${coast}&citadel=${id&1}&plaza=${sec}&temple=${thr}&walls=${sec}&shantytown=${sec}`; + const win = window.open(url+params, '_blank'); + win.focus(); + }); + $("#burgAddfromEditor").click(function() { clickToAdd(); // to load on click event function $("#addBurg").click(); @@ -3392,15 +3490,16 @@ function fantasyMap() { generateMainRoads(); rankPlacesEconomy(); locateTowns(); + getNames(); shiftSettlements(); checkAccessibility(); - defineRegions(); - drawManors(); - drawRegions(); + defineRegions("withCultures"); generatePortRoads(); generateSmallRoads(); generateOceanRoutes(); calculatePopulation(); + drawManors(); + drawRegions(); console.groupEnd('manorsAndRegions'); } @@ -3409,30 +3508,26 @@ function fantasyMap() { console.time('rankPlacesGeography'); land.map(function(c) { let score = 0; - // truncate decimals to keep data clear - c.height = Math.trunc(c.height * 100) / 100; c.flux = rn(c.flux, 2); // get base score from height (will be biom) - if (c.height <= 0.4) score = 2; - else if (c.height <= 0.5) score = 1.8; - else if (c.height <= 0.6) score = 1.6; - else if (c.height <= 0.8) score = 1.4; - score += (1 - c.height) / 3; + if (c.height <= 40) score = 2; + else if (c.height <= 50) score = 1.8; + else if (c.height <= 60) score = 1.6; + else if (c.height <= 80) score = 1.4; + score += (1 - c.height / 100) / 3; if (c.ctype && Math.random() < 0.8 && !c.river) { c.score = 0; // ignore 80% of extended cells } else { if (c.harbor) { if (c.harbor === 1) {score += 1;} else {score -= 0.3;} // good sea harbor is valued } + if (c.river) score += 1; // coastline is valued if (c.river && c.ctype === 1) score += 1; // estuary is valued if (c.flux > 1) score += Math.pow(c.flux, 0.3); // riverbank is valued if (c.confluence) score += Math.pow(c.confluence, 0.7); // confluence is valued; - const neighbEv = c.neighbors.map(function(n) {if (cells[n].height >= 0.2) return cells[n].height;}) + const neighbEv = c.neighbors.map(function(n) {if (cells[n].height >= 20) return cells[n].height;}) const difEv = c.height - d3.mean(neighbEv); - if (!isNaN(difEv)) { - score += difEv * 10 * (1 - c.height); // local height maximums are valued - //debug.append("text").attr("x", c.data[0]).attr("y", c.data[1]).attr("font-size", 1).text(rn(difEv * 10 * (1 - c.height), 1)); - } + // if (!isNaN(difEv)) score += difEv * 10 * (1 - c.height / 100); // local height maximums are valued } c.score = rn(Math.random() * score + score, 3); // add random factor }); @@ -3481,7 +3576,7 @@ function fantasyMap() { const graphSizeAdj = 90 / Math.sqrt(cells.length, 2); // adjust to different graphSize land.map(function(l) { let population = 0; - const elevationFactor = Math.pow(1 - l.height, 3); + const elevationFactor = Math.pow(1 - l.height / 100, 3); population = elevationFactor * l.area * graphSizeAdj; if (l.region === "neutral") population *= ruralFactor; l.pop = rn(population, 1); @@ -3542,8 +3637,7 @@ function fantasyMap() { const cell = land[l].index; const closest = cultureTree.find(x, y); const culture = getCultureId(closest); - const name = generateName(culture); - manors.push({i: region, cell, x, y, region, culture, name}); + manors.push({i: region, cell, x, y, region, culture}); } if (l === land.length - 1) { console.error("Cannot place capitals with current spacing. Trying again with reduced spacing"); @@ -3558,7 +3652,6 @@ function fantasyMap() { const power = rn(Math.random() * mod / 2 + 1, 1); const color = scheme(i / count); states.push({i, color, power, capital: i}); - states[i].name = generateStateName(i); const p = cells[m.cell]; p.manor = i; p.region = i; @@ -3593,11 +3686,10 @@ function fantasyMap() { } else { culture = manors[region].culture; } - const name = generateName(culture); land[l].manor = manors.length; land[l].culture = culture; land[l].region = region; - manors.push({i: manors.length, cell, x, y, region, culture, name}); + manors.push({i: manors.length, cell, x, y, region, culture}); manorTree.add([x, y]); } if (manors.length < count) { @@ -3846,8 +3938,8 @@ function fantasyMap() { if (next === end) {break;} var pol = cells[next]; pol.neighbors.forEach(function(e) { - if (cells[e].height >= 0.2) { - var cost = cells[e].height * 2; + if (cells[e].height >= 20) { + var cost = cells[e].height / 100 * 2; if (cells[e].path && type === "main") { cost = 0.15; } else { @@ -3881,8 +3973,8 @@ function fantasyMap() { const next = queue.dequeue().e; const pol = cells[next]; pol.neighbors.forEach(function(e) { - if (cells[e].height < 0.2) return; - let cost = cells[e].height * 2; + if (cells[e].height < 20) return; + let cost = cells[e].height / 100 * 2; if (e.river !== undefined) cost -= 0.2; if (pol.region !== cells[e].region) cost += 1; if (cells[e].region === "neutral") cost += 1; @@ -3960,7 +4052,7 @@ function fantasyMap() { var prev = cells[end]; if (type === "ocean" || !prev.path) {path.push({scX: prev.data[0], scY: prev.data[1], i: end});} if (!prev.path) {prev.path = 1;} - for (var i = 0; i < limit; i++) { + for (let i = 0; i < limit; i++) { current = from[current]; var cur = cells[current]; if (!cur) {break;} @@ -4040,6 +4132,38 @@ function fantasyMap() { console.timeEnd('drawManors'); } + // get settlement and country names based on option selected + function getNames() { + console.time('getNames'); + // if names source is an external resource + if (namesInput.value === "1") { + const request = new XMLHttpRequest(); + const url = "https://archivist.xalops.com/archivist-core/api/name/settlement?count="; + request.open("GET", url+manors.length, true); + request.onload = function() { + const names = JSON.parse(request.responseText); + for (let i=0; i < manors.length; i++) { + manors[i].name = names[i]; + burgLabels.select("[data-id='" + i + "']").text(names[i]); + if (i < states.length) { + states[i].name = generateStateName(i); + labels.select("#countries").select("#regionLabel"+i).text(states[i].name); + } + } + console.log(names); + } + request.send(null); + } + + if (namesInput.value !== "0") return; + for (let i=0; i < manors.length; i++) { + const culture = manors[i].culture; + manors[i].name = generateName(culture); + if (i < states.length) states[i].name = generateStateName(i); + } + console.timeEnd('getNames'); + } + function calculateChains() { for (let c=0; c < nameBase.length; c++) { chain[c] = calculateChain(c); @@ -4087,9 +4211,7 @@ function fantasyMap() { } if (!nameBases[base]) { console.error("nameBase " + base + " is not defined. Will load default names data and first base"); - localStorage.removeItem("nameBase"); - localStorage.removeItem("nameBases"); - applyDefaultNamesData(); + if (!nameBases[0]) applyDefaultNamesData(); base = 0; } const method = nameBases[base].method; @@ -4168,16 +4290,16 @@ function fantasyMap() { } // Define areas based on the closest manor to a polygon - function defineRegions() { + function defineRegions(withCultures) { console.time('defineRegions'); const manorTree = d3.quadtree(); manors.forEach(function(m) {if (m.region !== "removed") manorTree.add([m.x, m.y]);}); const neutral = +neutralInput.value; land.forEach(function(i) { - if (i.manor !== undefined) { + if (i.manor !== undefined && manors[i.manor].region !== "removed") { i.region = manors[i.manor].region; - i.culture = manors[i.manor].culture; + if (withCultures && manors[i.manor].culture !== undefined) i.culture = manors[i.manor].culture; return; } const x = i.data[0], y = i.data[1]; @@ -4190,8 +4312,10 @@ function fantasyMap() { } if (dist > neutral / 2 || manor === null) { i.region = "neutral"; - const closestCulture = cultureTree.find(x, y); - i.culture = getCultureId(closestCulture); + if (withCultures) { + const closestCulture = cultureTree.find(x, y); + i.culture = getCultureId(closestCulture); + } } else { const cell = manors[manor].cell; if (cells[cell].fn !== i.fn) { @@ -4205,7 +4329,7 @@ function fantasyMap() { }); } i.region = manors[manor].region; - i.culture = manors[manor].culture; + if (withCultures) i.culture = manors[manor].culture; } }); console.timeEnd('defineRegions'); @@ -4280,7 +4404,7 @@ function fantasyMap() { edgesOrdered.push({scX: spl[0], scY: spl[1]}); spl = end.split(" "); edgesOrdered.push({scX: spl[0], scY: spl[1]}); - for (var i = 0; end !== start && i < 2000; i++) { + for (let i = 0; end !== start && i < 2000; i++) { var next = $.grep(edges, function(e) {return (e.start == end || e.end == end);}); if (next.length > 0) { if (next[0].start == end) { @@ -4468,16 +4592,21 @@ function fantasyMap() { manors.forEach(function(m) { if (m.region === "removed") return; manorTree.add([m.x, m.y]); - if (m.region !== "neutral") { - const c = states[m.region].capital; + if (m.region === "neutral") { + const culture = cultureTree.find(m.x, m.y); + m.culture = getCultureId(culture); + return; + } + const c = states[m.region].capital; + if (c !== "neutral" && c !== "select") { const dist = Math.hypot(m.x - manors[c].x, m.y - manors[c].y); if (dist <= neutral / 5) { m.culture = manors[c].culture; return; } } - const c = cultureTree.find(m.x, m.y); - m.culture = getCultureId(c); + const culture = cultureTree.find(m.x, m.y); + m.culture = getCultureId(culture); }); // For each land cell if distance to closest manor > neutral / 2, @@ -4529,6 +4658,49 @@ function fantasyMap() { } } + // find burg from MFCG and focus on it + function findBurgForMFCG() { + if (!manors.length) {console.error("No burgs generated. Cannot select a burg for MFCG"); return;} + const url = new URL(window.location.href); + const size = +url.searchParams.get("size"); + let coast = +url.searchParams.get("coast"); + let river = +url.searchParams.get("river"); + let selection = defineSelection(coast, river); + if (!selection.length) selection = defineSelection(coast, !river); + if (!selection.length) selection = defineSelection(!coast, !river); + if (!selection.length) {console.error("Cannot find a burg for MFCG"); return;} + + function defineSelection(coast, river) { + let selection = []; + if (coast && river) selection = $.grep(manors, function(e) {return cells[e.cell].port !== undefined && cells[e.cell].river !== undefined;}); + if (!coast && !river) selection = $.grep(manors, function(e) {return cells[e.cell].port === undefined && cells[e.cell].river === undefined;}); + if (!coast && river) selection = $.grep(manors, function(e) {return cells[e.cell].port === undefined && cells[e.cell].river !== undefined;}); + if (coast && !river) selection = $.grep(manors, function(e) {return cells[e.cell].port !== undefined && cells[e.cell].river === undefined;}); + return selection; + } + + // select a burg with closes population from selection + const selected = d3.scan(selection, function(a, b) {return Math.abs(a.population - size) - Math.abs(b.population - size);}); + console.log(selection) + const burg = selection[selected].i; + console.log(selected, size) + if (size && burg !== undefined) {manors[burg].population = size;} else {return;} + + // focus on found burg + const label = burgLabels.select("[data-id='" + burg + "']"); + if (!label.size()) { + console.error("Cannot find a label for MFCG burg "+burg); + return; + } + tip("Here stands the glorious city of "+manors[burg].name, true); + label.classed("drag", true).on("mouseover", function() { + d3.select(this).classed("drag", false); + tip("", true); + }); + const x = +label.attr("x"), y = +label.attr("y"); + zoomTo(x, y, 8, 1600); + } + // draw the Heightmap function toggleHeight() { const scheme = styleSchemeInput.value; @@ -4539,15 +4711,15 @@ function fantasyMap() { if (!terrs.selectAll("path").size()) { cells.map(function(i, d) { let height = i.height; - if (height < 0.2 && !i.lake) return; + if (height < 20 && !i.lake) return; if (i.lake) { - const heights = i.neighbors.map(function(e) {if (cells[e].height >= 0.2) return cells[e].height;}) + const heights = i.neighbors.map(function(e) {if (cells[e].height >= 20) return cells[e].height;}) const mean = d3.mean(heights); if (!mean) return; - height = Math.trunc(mean * 100) / 100; - if (height < 0.2 || isNaN(height)) height = 0.2; + height = Math.trunc(mean); + if (height < 20 || isNaN(height)) height = 20; } - const clr = hColor(1 - height); + const clr = hColor((100 - height) / 100); terrs.append("path") .attr("d", "M" + polygons[d].join("L") + "Z") .attr("fill", clr).attr("stroke", clr); @@ -4613,8 +4785,8 @@ function fantasyMap() { delete c.coastY; if (c.ctype === undefined) delete c.ctype; if (c.lake === undefined) delete c.lake; - c.height = Math.trunc(c.height * 100) / 100; - if (c.height >= 0.2) c.flux = rn(c.flux, 2); + c.height = Math.trunc(c.height); + if (c.height >= 20) c.flux = rn(c.flux, 2); }); // restore layers if they was turned on if (!$("#toggleHeight").hasClass("buttonoff") && !terrs.selectAll("path").size()) toggleHeight(); @@ -4632,6 +4804,16 @@ function fantasyMap() { }); } + // change transparency for modal windowa + function changeDialogsTransparency(v) { + localStorage.setItem("transparency", v); + const alpha = (100 - +v) / 100; + const optionsColor = "rgba(164, 139, 149, " + alpha + ")"; // purple-red + const dialogsColor = "rgba(255, 255, 255, " + alpha + ")"; // white + document.getElementById("options").style.backgroundColor = optionsColor; + document.getElementById("dialogs").style.backgroundColor = dialogsColor; + } + // Draw the water flux system (for dubugging) function toggleFlux() { var colorFlux = d3.scaleSequential(d3.interpolateBlues); @@ -4649,8 +4831,8 @@ function fantasyMap() { // Draw the Relief (need to create more beautiness) function drawRelief() { - let h, count, rnd, cx, cy, swampCount = 0; console.time('drawRelief'); + let h, count, rnd, cx, cy, swampCount = 0; const hills = terrain.select("#hills"); const mounts = terrain.select("#mounts"); const swamps = terrain.select("#swamps"); @@ -4658,20 +4840,28 @@ function fantasyMap() { terrain.selectAll("g").selectAll("g").remove(); // sort the land to Draw the top element first (reduce the elements overlapping) land.sort(compareY); - for (i = 0; i < land.length; i++) { - const x = land[i].data[0]; - const y = land[i].data[1]; + for (let i = 0; i < land.length; i++) { + if (land[i].river) continue; // no icons on rivers + const cell = land[i].index; + const p = d3.polygonCentroid(polygons[cell]); // polygon centroid point + if (p === undefined) continue; // something is wrong with data const height = land[i].height; - if (height >= 0.7 && !land[i].river) { + const area = land[i].area; + if (height >= 70) { // mount icon - h = (height - 0.55) * 12; - count = height < 0.8 ? 2 : 1; - if (land[i].ctype === 1) count = 0; - rnd = Math.random() * 0.8 + 0.2; - for (let c = 0; c < count; c++) { + h = (height - 55) * 0.12; + for (let c = 0, a = area; Math.random() < a / 50; c++, a -= 50) { + if (polygons[cell][c] === undefined) break; const g = mounts.append("g"); - cx = x - h * 0.9 - c; - cy = y + h / 4 + c / 2; + if (c < 2) { + cx = p[0] - h / 100 * (1 - c / 10) - c * 2; + cy = p[1] + h / 400 + c; + } else { + const p2 = polygons[cell][c]; + cx = (p[0] * 1.2 + p2[0] * 0.8) / 2; + cy = (p[1] * 1.2 + p2[1] * 0.8) / 2; + } + rnd = Math.random() * 0.8 + 0.2; let mount = "M" + cx + "," + cy + " L" + (cx + h / 3 + rnd) + "," + (cy - h / 4 - rnd * 1.2) + " L" + (cx + h / 1.1) + "," + (cy - h) + " L" + (cx + h + rnd) + "," + (cy - h / 1.2 + rnd) + " L" + (cx + h * 2) + "," + cy; let shade = "M" + cx + "," + cy + " L" + (cx + h / 3 + rnd) + "," + (cy - h / 4 - rnd * 1.2) + " L" + (cx + h / 1.1) + "," + (cy - h) + " L" + (cx + h / 1.5) + "," + cy; let dash = "M" + (cx - 0.1) + "," + (cy + 0.3) + " L" + (cx + 2 * h + 0.1) + "," + (cy + 0.3); @@ -4680,16 +4870,22 @@ function fantasyMap() { g.append("path").attr("d", round(shade, 1)).attr("fill", "#999999"); g.append("path").attr("d", round(dash, 1)).attr("class", "strokes"); } - } else if (height > 0.5 && !land[i].river) { + } else if (height > 50) { // hill icon - h = (height - 0.4) * 10; - count = Math.floor(4 - h); - if (land[i].ctype === 1) count = Math.random() < 0.2 ? 1 : 0; - if (h > 1.8) h = 1.8; - for (let c = 0; c < count; c++) { + h = (height - 40) / 10; + if (h > 1.7) h = 1.7; + for (let c = 0, a = area; Math.random() < a / 30; c++, a -= 30) { + if (land[i].ctype === 1 && c > 0) break; + if (polygons[cell][c] === undefined) break; const g = hills.append("g"); - cx = x - h - c; - cy = y + h / 4 + c / 2; + if (c < 2) { + cx = p[0] - h - c * 1.2; + cy = p[1] + h / 4 + c / 1.6; + } else { + const p2 = polygons[cell][c]; + cx = (p[0] * 1.2 + p2[0] * 0.8) / 2; + cy = (p[1] * 1.2 + p2[1] * 0.8) / 2; + } let hill = "M" + cx + "," + cy + " Q" + (cx + h) + "," + (cy - h) + " " + (cx + 2 * h) + "," + cy; let shade = "M" + (cx + 0.6 * h) + "," + (cy + 0.1) + " Q" + (cx + h * 0.95) + "," + (cy - h * 0.91) + " " + (cx + 2 * h * 0.97) + "," + cy; let dash = "M" + (cx - 0.1) + "," + (cy + 0.2) + " L" + (cx + 2 * h + 0.1) + "," + (cy + 0.2); @@ -4701,13 +4897,13 @@ function fantasyMap() { } // swamp icons - if (height >= 0.21 && height < 0.22 && !land[i].river && swampCount < +swampinessInput.value && land[i].used != 1) { + if (height >= 21 && height < 22 && swampCount < +swampinessInput.value && land[i].used != 1) { const g = swamps.append("g"); swampCount++; land[i].used = 1; - let swamp = drawSwamp(x, y); + let swamp = drawSwamp(p[0], p[1]); land[i].neighbors.forEach(function(e) { - if (cells[e].height >= 0.2 && cells[e].height < 0.3 && !cells[e].river && cells[e].used != 1) { + if (cells[e].height >= 20 && cells[e].height < 30 && !cells[e].river && cells[e].used != 1) { cells[e].used = 1; swamp += drawSwamp(cells[e].data[0], cells[e].data[1]); } @@ -4716,17 +4912,23 @@ function fantasyMap() { } // forest icons - if (Math.random() < height && height >= 0.22 && height < 0.48 && !land[i].river) { - count = Math.floor(height * 8); - if (land[i].ctype === 1) count = 1; - for (let c = 0; c < count; c++) { + if (Math.random() < height / 100 && height >= 22 && height < 48) { + for (let c = 0, a = area; Math.random() < a / 15; c++, a -= 15) { + if (land[i].ctype === 1 && c > 0) break; + if (polygons[cell][c] === undefined) break; const g = forests.append("g"); - rnd = Math.random(); - h = 1 * rnd * 0.4 + 0.6; - cx = c === 1 ? x + h + Math.random() : x - h - Math.random(); - cy = c === 1 ? y + h + rnd : c === 2 ? y + 2 * h + rnd : y - h - rnd; - cx = rn(cx, 1); - cy = rn(cy, 1); + if (c === 0) { + cx = rn(p[0] - 1 - Math.random(), 1); + cy = p[1] - 2; + } else { + const p2 = polygons[cell][c]; + if (c > 1) { + const dist = Math.hypot(p2[0] - polygons[cell][c-1][0], p2[1] - polygons[cell][c-1][1]); + if (dist < 2) continue; + } + cx = (p[0] * 0.5 + p2[0] * 1.5) / 2; + cy = (p[1] * 0.5 + p2[1] * 1.5) / 2 - 1; + } const forest = "M" + cx + "," + cy + " q-1,0.8 -0.05,1.25 v0.75 h0.1 v-0.75 q0.95,-0.47 -0.05,-1.25 z "; const light = "M" + cx + "," + cy + " q-1,0.8 -0.05,1.25 h0.1 q0.95,-0.47 -0.05,-1.25 z "; const shade = "M" + cx + "," + cy + " q-1,0.8 -0.05,1.25 q-0.2,-0.55 0,-1.1 z "; @@ -4790,7 +4992,7 @@ function fantasyMap() { function drawSwamp(x, y) { var h = 0.6, line = ""; - for (c = 0; c < 3; c++) { + for (let c = 0; c < 3; c++) { if (c == 0) { cx = x; cy = y - 0.5 - Math.random(); @@ -4835,11 +5037,10 @@ function fantasyMap() { // Complete the map for the "customize" mode function getMap() { if (customization !== 1) { - tip('Nothing to complete! Click on "Edit" or "Clear all" to enter a heightmap customizaton mode', null, "error"); + tip('Nothing to complete! Click on "Edit" or "Clear all" to enter a heightmap customization mode', null, "error"); return; } - land = $.grep(cells, function(e) {return e.height >= 0.2;}); - if (land.length < 100) { + if (+landmassCounter.innerHTML < 150) { tip("Insufficient land area! Please add more land cells to complete the map", null, "error"); return; } @@ -4937,7 +5138,7 @@ function fantasyMap() { const culture = cultureTree.data().indexOf(closest) || 0; const name = generateName(culture); - if (cells[index].height < 0.2) { + if (cells[index].height < 20) { tip("Cannot place burg in the water! Select a land cell", null, "error"); return; } @@ -5004,7 +5205,7 @@ function fantasyMap() { var point = d3.mouse(this); var index = diagram.find(point[0], point[1]).index; var cell = cells[index]; - if (cell.river || cell.height < 0.2) {return;} + if (cell.river || cell.height < 20) return; var dataRiver = []; // to store river points const last = $("#rivers > path").last(); const river = last.length ? +last.attr("id").slice(5) + 1 : 0; @@ -5018,7 +5219,7 @@ function fantasyMap() { var minId = heights.indexOf(d3.min(heights)); var min = cell.neighbors[minId]; var tx = cells[min].data[0], ty = cells[min].data[1]; - if (cells[min].height < 0.2) { + if (cells[min].height < 20) { var px = (x + tx) / 2; var py = (y + ty) / 2; dataRiver.push({x: px, y: py, cell:index}); @@ -5091,14 +5292,14 @@ function fantasyMap() { const point = d3.mouse(this); const index = getIndex(point); const height = cells[index].height; - if (height < 0.2) { + if (height < 20) { tip("Cannot place icon in the water! Select a land cell"); return; } const x = rn(point[0], 2), y = rn(point[1], 2); const type = reliefGroup.value; - addReliefIcon(height, type, x, y); + addReliefIcon(height / 100, type, x, y); if (d3.event.shiftKey === false) { $("#addRelief").removeClass("pressed"); @@ -5148,7 +5349,7 @@ function fantasyMap() { if (customization) {return;} closeDialogs("#labelEditor, .stable"); elSelected = d3.select(this); - elSelected.call(d3.drag().on("drag", dragged).on("end", dragended)).classed("draggable", true); + elSelected.call(d3.drag().on("start", elementDrag)).classed("draggable", true); var group = d3.select(this.parentNode); updateGroupOptions(); @@ -5158,10 +5359,9 @@ function fantasyMap() { editColor.value = toHEX(group.attr("fill")); editOpacity.value = group.attr("opacity"); editText.value = elSelected.text(); - var matrix = elSelected.attr("transform"); - var rotation = matrix ? matrix.split('(')[1].split(')')[0].split(' ')[0] : 0; - editAngle.value = rotation; - editAngleValue.innerHTML = rotation + "°"; + const tr = parseTransform(elSelected.attr("transform")); + editAngle.value = tr[2]; + editAngleValue.innerHTML = Math.abs(+tr[2]) + "°"; $("#labelEditor").dialog({ title: "Edit Label: " + editText.value, @@ -5179,7 +5379,7 @@ function fantasyMap() { function changeSelectedOnClick() { const point = d3.mouse(this); const index = diagram.find(point[0], point[1]).index; - if (cells[index].height < 0.2) return; + if (cells[index].height < 20) return; $(".selected").removeClass("selected"); let color; @@ -5249,9 +5449,10 @@ function fantasyMap() { return; } if (this.id == "editGroupRemove") { - var count = group.selectAll("text").size() + var count = group.selectAll("text").size(); if (count < 2) { group.remove(); + updateLabelGroups(); $("#labelEditor").dialog("close"); return; } @@ -5262,6 +5463,7 @@ function fantasyMap() { Remove: function() { $(this).dialog("close"); group.remove(); + updateLabelGroups(); $("#labelEditor").dialog("close"); }, Cancel: function() {$(this).dialog("close");} @@ -5300,7 +5502,7 @@ function fantasyMap() { } return; } - if (this.id == "editTextRandom") { + if (this.id === "editTextRandom") { var name; // check if label is country name if (group.attr("id") === "countries") { @@ -5350,10 +5552,12 @@ function fantasyMap() { // on editAngle change $("#editAngle").on("input", function() { - var c = elSelected.node().getBBox(); - var rotate = `rotate(${this.value} ${(c.x+c.width/2)} ${(c.y+c.height/2)})`; - elSelected.attr("transform", rotate); + const tr = parseTransform(elSelected.attr("transform")); editAngleValue.innerHTML = Math.abs(+this.value) + "°"; + const c = elSelected.node().getBBox(); + const angle = +this.value; + const transform = `translate(${tr[0]},${tr[1]}) rotate(${angle} ${(c.x+c.width/2)} ${(c.y+c.height/2)})`; + elSelected.attr("transform", transform); }); $("#editFontInput").change(function() { @@ -5414,18 +5618,22 @@ function fantasyMap() { if (fonts.indexOf(font) == -1) {fonts.push(font); fetched++}; }; let fetched = 0; - for (var r of styleSheet.cssRules) {FontRule(r);} + for (let r of styleSheet.cssRules) {FontRule(r);} document.head.removeChild(s); return fetched; }) .catch(function() {return}); } - // on any Editor input change - $("#labelEditor .editTrigger").change(function() { - if (!elSelected) {return;} + // on name input + $("#editText").on("input", function() { $(this).attr("title", $(this).val()); elSelected.text(editText.value); // change Label text + }); + + // on any Editor input change + $("#labelEditor .editTrigger").change(function() { + if (!elSelected) return; // check if Group was changed var group = d3.select(elSelected.node().parentNode); var groupOld = group.attr("id"); @@ -5459,6 +5667,7 @@ function fantasyMap() { } group.append(function() {return removed.node();}); editGroupSelect.value = group.attr("id"); + updateLabelGroups(); } // update Group attributes var size = +editSize.value; @@ -5668,7 +5877,7 @@ function fantasyMap() { }; let fontRules = [], fontProms = []; - for (var r of styleSheet.cssRules) { + for (let r of styleSheet.cssRules) { let fR = FontRule(r) fontRules.push(fR); fontProms.push( @@ -5695,7 +5904,8 @@ function fantasyMap() { function saveMap() { console.time("saveMap"); // data convention: 0 - version; 1 - all points; 2 - cells; 3 - manors; 4 - states; - // 5 - svg; 6 - options (see below); 7 - cultures; 8 - nameBase; 9 - nameBases; + // 5 - svg; 6 - options (see below); 7 - cultures; + // 8 - empty (former nameBase); 9 - empty (former nameBases); 10 - heights; // size stats: points = 6%, cells = 36%, manors and states = 2%, svg = 56%; const options = customization + "|" + distanceUnit.value + "|" + distanceScale.value + "|" + areaUnit.value + "|" + @@ -5714,7 +5924,7 @@ function fantasyMap() { var line = "\r\n"; var data = version + line + JSON.stringify(points) + line + JSON.stringify(cells) + line; data += JSON.stringify(manors) + line + JSON.stringify(states) + line + svg_xml + line + options + line; - data += JSON.stringify(cultures) + line + JSON.stringify(nameBase) + line + JSON.stringify(nameBases) + line; + data += JSON.stringify(cultures) + line + "" + line + "" + line + heights + line; var dataBlob = new Blob([data], {type:"text/plain"}); var dataURL = window.URL.createObjectURL(dataBlob); var link = document.createElement("a"); @@ -5748,7 +5958,7 @@ function fantasyMap() { var dataLoaded = fileLoadedEvent.target.result; var data = dataLoaded.split("\r\n"); // data convention: 0 - version; 1 - all points; 2 - cells; 3 - manors; 4 - states; - // 5 - svg; 6 - options; 7 - cultures; 8 - nameBase; 9 - nameBases; + // 5 - svg; 6 - options; 7 - cultures; 8 - none; 9 - none; 10 - heights; var mapVersion = data[0]; if (mapVersion !== version) { var message = `The Map version `; @@ -5950,30 +6160,59 @@ function fantasyMap() { // update data newPoints = [], riversData = [], queue = [], elSelected = ""; points = JSON.parse(data[1]); + if (data[10]) {heights = new Uint8Array(data[10].split(","));} + else { + heights = new Uint8Array(points.length); + for (let i=0; i < points.length; i++) { + const cell = diagram.find(points[i][0], points[i][1]).index; + heights[i] = cells[cell].height; + } + } cells = JSON.parse(data[2]); - land = $.grep(cells, function(e) {return (e.height >= 0.2);}); + manors = JSON.parse(data[3]); - cells.map(function(e) {newPoints.push(e.data);}); - calculateVoronoi(newPoints); - if(data[7]) cultures = JSON.parse(data[7]); + if (data[7]) cultures = JSON.parse(data[7]); if (data[7] === undefined) generateCultures(); - if(data[8]) nameBase = JSON.parse(data[8]); - if(data[8]) nameBases = JSON.parse(data[9]); + + // ensure each culure has a valid namesbase assigned, if not assign first base + if (!nameBase[0]) applyDefaultNamesData(); + cultures.forEach(function(c) { + const b = c.base; + if (b === undefined) c.base = 0; + if (!nameBase[b] || !nameBases[b]) c.base = 0; + }); + + // cells validations + cells.forEach(function(c) { + // collect points + newPoints.push(c.data); + + // update old 0-1 height range to new 0-100 range + if (c.height > 1) return; + if (c.height === 1 && c.region === undefined && c.flux === undefined) return; + c.height = Math.trunc(c.height * 100); + + // check if there unavailable cultures + if (c.culture > cultures.length - 1) cultures.push({name:"AUTO_"+c.culture, color:"#ff0000", base:0}); + }); + + land = $.grep(cells, function(e) {return (e.height >= 20);}); + calculateVoronoi(newPoints); // calculate areas / population for old maps const graphSizeAdj = 90 / Math.sqrt(cells.length, 2); // adjust to different graphSize land.forEach(function(i) { const p = i.index; + if (!polygons[p] || !polygons[p].length) return; + const area = d3.polygonArea(polygons[p]); + i.area = rn(Math.abs(area), 2); if (i.pop === undefined) { let population = 0; - const elevationFactor = Math.pow(1 - i.height, 3); + const elevationFactor = Math.pow((100 - i.height) / 100, 3); population = elevationFactor * i.area * graphSizeAdj; if (i.region === "neutral") population *= 0.5; i.pop = rn(population, 1); } - if (!polygons[p] || !polygons[p].length) return; - const area = d3.polygonArea(polygons[p]); - i.area = rn(Math.abs(area), 2); }); // restore Heightmap customization mode @@ -6036,7 +6275,7 @@ function fantasyMap() { var i = Math.random() * queueSize | 0, s = queue[i]; // Make a new candidate between [radius, 2 * radius] from the existing sample. - for (var j = 0; j < k; ++j) { + for (let j = 0; j < k; ++j) { var a = 2 * Math.PI * Math.random(), r = Math.sqrt(Math.random() * R + radius2), x = s[0] + r * Math.cos(a), @@ -6191,6 +6430,7 @@ function fantasyMap() { if (id === "toggleFlux") {toggleFlux();} if (parent === "mapLayers" || parent === "styleContent") {$(this).toggleClass("buttonoff");} if (id === "randomMap" || id === "regenerate") { + changeSeed(); exitCustomization(); undraw(); resetZoom(1000); @@ -6494,7 +6734,6 @@ function fantasyMap() { alertMessage.innerHTML = "Are you sure you want to clear the map? All progress will be lost"; $("#alert").dialog({resizable: false, title: "Clear map", buttons: { - Cancel: function() {$(this).dialog("close");}, Clear: function() { closeDialogs(); undraw(); @@ -6505,7 +6744,8 @@ function fantasyMap() { customizeHeightmap(); openBrushesPanel(); $(this).dialog("close"); - } + }, + Cancel: function() {$(this).dialog("close");} } }); } @@ -6575,49 +6815,10 @@ function fantasyMap() { if (id === "convertImageGrid") {$("#grid").fadeToggle();} if (id === "convertImageHeights") {$("#landmass").fadeToggle();} if (id === "perspectiveView") { - // Inputs control - if ($("#perspectivePanel").is(":visible")) {return;} - const line = +$("#lineHandle0").attr("data-value"); - const grad = +$("#lineHandle1").attr("data-value"); - $("#lineSlider").slider({ - min: 10, max: 320, step: 1, values: [line, grad], - create: function() { - $("#lineHandle0").text("x:"+line); - $("#lineHandle1").text("y:"+grad); - }, - slide: function(event, ui) { - $("#lineHandle0").text("x:"+ui.values[0]).attr("data-value", ui.values[0]); - $("#lineHandle1").text("y:"+ui.values[1]).attr("data-value", ui.values[1]); - drawPerspective(); - } - }); - $("#ySlider").slider({ - min: 1, max: 5, step: 0.1, value: +$("#yHandle").attr("data-value"), - create: function() {$("#yHandle").text($("#yHandle").attr("data-value"));}, - slide: function(event, ui) { - $("#yHandle").text(ui.value).attr("data-value", ui.value); - drawPerspective(); - } - }); - $("#scaleSlider").slider({ - min: 0.5, max: 2, step: 0.1, value: +$("#scaleHandle").attr("data-value"), - create: function() {$("#scaleHandle").text($("#scaleHandle").attr("data-value"));}, - slide: function(event, ui) { - $("#scaleHandle").text(ui.value).attr("data-value", ui.value); - drawPerspective(); - } - }); - $("#heightSlider").slider({ - min: 1, max: 50, step: 1, value: +$("#heightHandle").attr("data-value"), - create: function() {$("#heightHandle").text($("#heightHandle").attr("data-value"));}, - slide: function(event, ui) { - $("#heightHandle").text(ui.value).attr("data-value", ui.value); - drawPerspective(); - } - }); + if ($("#perspectivePanel").is(":visible")) return; $("#perspectivePanel").dialog({ title: "Perspective View", - width: 520, height: 360, + width: 520, height: 190, position: {my: "center center", at: "center center", of: "svg"} }); drawPerspective(); @@ -6697,7 +6898,7 @@ function fantasyMap() { viewbox.style("cursor", "crosshair").call(drag); landmassCounter.innerHTML = "0"; $("#landmass").empty(); - cells.map(function(i) {i.height = 0;}); + heights = new Uint8Array(heights.length); // clear history history = []; historyStage = 0; @@ -6772,22 +6973,21 @@ function fantasyMap() { function editHeightmap(type) { closeDialogs(); - const heights = [], regionData = [], cultureData = []; - for (let i = 0; i < points.length; i++) { - const cell = diagram.find(points[i][0], points[i][1]).index; - heights.push(cells[cell].height); - let region = cells[cell].region; - if (region === undefined) region = -1; - regionData.push(region); - let culture = cells[cell].culture; - if (culture === undefined) culture = -1; - cultureData.push(culture); - } - if (type === "clean") undraw(); + const regionData = [], cultureData = []; + if (type !== "clean") { + for (let i = 0; i < points.length; i++) { + const cell = diagram.find(points[i][0], points[i][1]).index; + let region = cells[cell].region; + if (region === undefined) region = -1; + regionData.push(region); + let culture = cells[cell].culture; + if (culture === undefined) culture = -1; + cultureData.push(culture); + } + } else {undraw();} calculateVoronoi(points); detectNeighbors("grid"); drawScaleBar(); - for (let i = 0; i < points.length; i++) {cells[i].height = heights[i];} if (type === "keep") { svg.selectAll("#lakes, #coastline, #terrain, #rivers, #grid, #terrs, #landmass, #ocean, #regions") .selectAll("path, circle, line").remove(); @@ -6840,12 +7040,11 @@ function fantasyMap() { console.time("drawPerspective"); const width = 320, height = 180; const wRatio = graphWidth / width, hRatio = graphHeight / height; - const lineCount = +$("#lineHandle0").attr("data-value"); - const lineGranularity = +$("#lineHandle1").attr("data-value"); + const lineCount = 320, lineGranularity = 90; const perspective = document.getElementById("perspective"); const pContext = perspective.getContext("2d"); const lines = []; - let i = Math.floor(lineCount); + let i = lineCount; while (i--) { const x = i / lineCount * width | 0; const canvasPoints = []; @@ -6853,8 +7052,8 @@ function fantasyMap() { let j = Math.floor(lineGranularity); while (j--) { const y = j / lineGranularity * height | 0; - let h = getHeightInPoint(x * wRatio, y * hRatio) - 0.2; - if (h < 0) {h = 0;} + let h = getHeightInPoint(x * wRatio, y * hRatio) - 20; + if (h < 1) h = 0; canvasPoints.push([x, y, h]); } } @@ -6863,7 +7062,7 @@ function fantasyMap() { for (let i = 0; i < canvasPoints.length - 1; i++) { const pt1 = canvasPoints[i]; const pt2 = canvasPoints[i + 1]; - const avHeight = (pt1[2] + pt2[2]) / 2; + const avHeight = (pt1[2] + pt2[2]) / 200; pContext.beginPath(); pContext.moveTo(...transformPt(pt1)); pContext.lineTo(...transformPt(pt2)); @@ -6872,6 +7071,9 @@ function fantasyMap() { pContext.strokeStyle = clr; pContext.stroke(); } + for (let i = 0; i < canvasPoints.length - 1; i++) { + + } } console.timeEnd("drawPerspective"); } @@ -6883,15 +7085,13 @@ function fantasyMap() { } function transformPt(pt) { - const width = 320; - const maxHeight = +$("#heightHandle").attr("data-value"); + const width = 320, maxHeight = 0.2; var [x, y] = projectIsometric(pt[0], pt[1]); return [x + width / 2 + 10, y + 10 - pt[2] * maxHeight]; } function projectIsometric(x, y) { - const scale = $("#scaleHandle").attr("data-value"); - const yProj = $("#yHandle").attr("data-value"); + const scale = 1, yProj = 4; return [(x - y) * scale, (x + y) / yProj * scale]; } @@ -6901,7 +7101,7 @@ function fantasyMap() { id = id.replace("template", ""); if (id === "Mountain") { var steps = $("#templateBody > div").length; - if (steps > 0) {return;} + if (steps > 0) return; } $("#templateBody").attr("data-changed", 1); $("#templateBody").append('
    ' + id + '
    '); @@ -6910,13 +7110,13 @@ function fantasyMap() { var count = ''; } if (id === "Hill") { - var dist = ''; + var dist = ''; } if (id === "Add" || id === "Multiply") { var dist = ''; } if (id === "Add") { - var count = ''; + var count = ''; } if (id === "Multiply") { var count = ''; @@ -6929,8 +7129,8 @@ function fantasyMap() { } el.append(''); $("#templateBody .icon-trash-empty").on("click", function() {$(this).parent().remove();}); - if (dist) {el.append(dist);} - if (count) {el.append(count);} + if (dist) el.append(dist); + if (count) el.append(count); el.find("select.templateElDist").on("input", fireTemplateElDist); $("#templateBody").attr("data-changed", 1); }); @@ -6938,7 +7138,7 @@ function fantasyMap() { // fireTemplateElDist selector handlers function fireTemplateElDist() { if (this.value === "interval") { - var interval = prompt("Populate a height interval (e.g. from 0.17 to 0.2), without space, but with hyphen", "0.17-0.2"); + var interval = prompt("Populate a height interval (e.g. from 17 to 20), without space, but with hyphen", "17-20"); if (interval) { var option = ''; $(this).append(option).val(interval); @@ -6967,87 +7167,109 @@ function fantasyMap() { } }); } - if (steps === 0 || changed === 0) {changeTemplate(template);} + if (steps === 0 || changed === 0) changeTemplate(template); }); function changeTemplate(template) { $("#templateBody").empty(); $("#templateSelect").attr("data-prev", template); - addStep("Mountain"); if (template === "templateVolcano") { - addStep("Add", 0.05); - addStep("Multiply", 1.1); - addStep("Hill", 5, 0.4); - addStep("Hill", 2, 0.15); + addStep("Mountain"); + addStep("Add", 10); + addStep("Hill", 5, 0.35); addStep("Range", 3); - addStep("Trough", 3); + addStep("Trough", -4); } if (template === "templateHighIsland") { - addStep("Add", 0.05); - addStep("Multiply", 0.9); - addStep("Range", 4); + addStep("Mountain"); + addStep("Add", 10); + addStep("Range", 6); addStep("Hill", 12, 0.25); addStep("Trough", 3); addStep("Multiply", 0.75, "land"); + addStep("Pit", 1); addStep("Hill", 3, 0.15); } if (template === "templateLowIsland") { + addStep("Mountain"); + addStep("Add", 10); addStep("Smooth", 2); - addStep("Range", 1); + addStep("Range", 2); addStep("Hill", 4, 0.4); addStep("Hill", 12, 0.2); addStep("Trough", 8); addStep("Multiply", 0.35, "land"); } if (template === "templateContinents") { - addStep("Hill", 24, 0.25); - addStep("Range", 4); - addStep("Hill", 3, 0.18); - addStep("Multiply", 0.7, "land"); - addStep("Strait", "2-7"); + addStep("Mountain"); + addStep("Add", 10); + addStep("Hill", 30, 0.25); + addStep("Strait", "4-7"); + addStep("Pit", 10); + addStep("Trough", 10); + addStep("Multiply", 0.6, "land"); addStep("Smooth", 2); - addStep("Pit", 7); - addStep("Trough", 8); - addStep("Multiply", 0.8, "land"); - addStep("Add", 0.02, "all"); + addStep("Range", 3); } if (template === "templateArchipelago") { - addStep("Add", -0.2, "land"); - addStep("Hill", 14, 0.17); - addStep("Range", 5); - addStep("Strait", "2-4"); - addStep("Trough", 12); - addStep("Pit", 8); - addStep("Add", -0.05, "land"); + addStep("Mountain"); + addStep("Add", 10); + addStep("Hill", 12, 0.15); + addStep("Range", 8); + addStep("Strait", "2-3"); + addStep("Trough", 15); + addStep("Pit", 10); + addStep("Add", -5, "land"); addStep("Multiply", 0.7, "land"); - addStep("Smooth", 4); + addStep("Smooth", 3); } + if (template === "templateAtoll") { + addStep("Mountain"); + addStep("Add", 10, "all"); addStep("Hill", 2, 0.35); addStep("Range", 2); - addStep("Add", 0.07, "all"); addStep("Smooth", 1); - addStep("Multiply", 0.1, "0.27-10"); + addStep("Multiply", 0.1, "27-100"); + } + if (template === "templateMainland") { + addStep("Mountain"); + addStep("Add", 10, "all"); + addStep("Hill", 30, 0.2); + addStep("Range", 10); + addStep("Pit", 20); + addStep("Hill", 10, 0.15); + addStep("Trough", 10); + addStep("Multiply", 0.4, "land"); + addStep("Range", 10); + addStep("Smooth", 3); + } + if (template === "templatePeninsulas") { + addStep("Add", 15); + addStep("Hill", 30, 0); + addStep("Range", 5); + addStep("Pit", 15); + addStep("Strait", "15-20"); } $("#templateBody").attr("data-changed", 0); } // interprete template function function addStep(feature, count, dist) { - if (!feature) {return;} - if (feature === "Mountain") {templateMountain.click();} - if (feature === "Hill") {templateHill.click();} - if (feature === "Pit") {templatePit.click();} - if (feature === "Range") {templateRange.click();} - if (feature === "Trough") {templateTrough.click();} - if (feature === "Strait") {templateStrait.click();} - if (feature === "Add") {templateAdd.click();} - if (feature === "Multiply") {templateMultiply.click();} - if (feature === "Smooth") {templateSmooth.click();} + if (!feature) return; + if (feature === "Mountain") templateMountain.click(); + if (feature === "Hill") templateHill.click(); + if (feature === "Pit") templatePit.click(); + if (feature === "Range") templateRange.click(); + if (feature === "Trough") templateTrough.click(); + if (feature === "Strait") templateStrait.click(); + if (feature === "Add") templateAdd.click(); + if (feature === "Multiply") templateMultiply.click(); + if (feature === "Smooth") templateSmooth.click(); if (count) {$("#templateBody div:last-child .templateElCount").val(count);} - if (dist) { + if (dist !== undefined) { if (dist !== "land") { - var option = ''; + const option = ''; $("#templateBody div:last-child .templateElDist").append(option); } $("#templateBody div:last-child .templateElDist").val(dist); @@ -7056,18 +7278,18 @@ function fantasyMap() { // Execute custom template $("#templateRun").on("click", function() { - if (customization !== 1) {return;} + if (customization !== 1) return; var steps = $("#templateBody > div").length; - if (steps) {cells.map(function(i) {i.height = 0;});} - for (var step=1; step <= steps; step++) { - var element = $("#templateBody div:nth-child(" + step + ")"); - var type = element.attr("data-type"); + if (!steps) return; + heights = new Uint8Array(heights.length); // clean all heights + for (let step=1; step <= steps; step++) { + const type = $("#templateBody div:nth-child(" + step + ")").attr("data-type"); if (type === "Mountain") {addMountain(); continue;} - var count = $("#templateBody div:nth-child(" + step + ") .templateElCount").val(); - var dist = $("#templateBody div:nth-child(" + step + ") .templateElDist").val(); + let count = $("#templateBody div:nth-child(" + step + ") .templateElCount").val(); + const dist = $("#templateBody div:nth-child(" + step + ") .templateElDist").val(); if (count) { if (count[0] !== "-" && count.includes("-")) { - var lim = count.split("-"); + const lim = count.split("-"); count = Math.floor(Math.random() * (+lim[1] - +lim[0] + 1) + +lim[0]); } else { count = +count; // parse string @@ -7082,14 +7304,15 @@ function fantasyMap() { if (type === "Multiply") {modifyHeights(dist, 0, count);} if (type === "Smooth") {smoothHeights(count);} } - if (steps) {mockHeightmap(); updateHistory();} + mockHeightmap(); + updateHistory(); }); // Save custom template as text file $("#templateSave").on("click", function() { var steps = $("#templateBody > div").length; var stepsData = ""; - for (var step=1; step <= steps; step++) { + for (let step=1; step <= steps; step++) { var element = $("#templateBody div:nth-child(" + step + ")"); var type = element.attr("data-type"); var count = $("#templateBody div:nth-child(" + step + ") .templateElCount").val(); @@ -7121,7 +7344,7 @@ function fantasyMap() { $("#templateBody").attr("data-changed", 1); $("#templateSelect").attr("data-prev", "templateCustom").val("templateCustom"); } - for (var i=0; i < data.length; i++) { + for (let i=0; i < data.length; i++) { var line = data[i].split(" "); addStep(line[0], line[1], line[2]); } @@ -7138,9 +7361,9 @@ function fantasyMap() { restoreDefaultEvents(); var div = d3.select("#colorScheme"); if (div.selectAll("*").size() === 0) { - for (var i = 0; i <= 100; i++) { + for (let i = 0; i <= 100; i++) { var width = i < 20 || i > 70 ? "1px" : "3px"; - if (i === 0) {width = "4px";} + if (i === 0) width = "4px"; var clr = color(1-i/100); var style = "background-color: " + clr + "; width: " + width; div.append("div").attr("data-color", i/100).attr("style", style); @@ -7304,7 +7527,7 @@ function fantasyMap() { heights.push(normalized); var rgb = color(1 - normalized); var hex = toHEX(rgb); - cells[d].height = normalized; + cells[d].height = normalized * 100; landmass.append("path").attr("d", "M" + i.join("L") + "Z").attr("data-i", d).attr("fill", hex).attr("stroke", hex); }); heights.sort(function(a, b) {return a - b;}); @@ -7388,7 +7611,7 @@ function fantasyMap() { var totalArea = 0, totalBurgs = 0, unit, areaConv; if (areaUnit.value === "square") {unit = " " + distanceUnit.value + "²";} else {unit = " " + areaUnit.value;} var totalPopulation = 0; - for (var s = 0; s < states.length; s++) { + for (let s = 0; s < states.length; s++) { $("#countriesBody").append('
    '); var el = $("#countriesBody div:last-child"); var burgsCount = states[s].burgs; @@ -7427,8 +7650,8 @@ function fantasyMap() { } el.append(''); el.append('
    ' + states[s].cells + '
    '); - el.append(''); - el.append('
    ' + burgsCount + '
    '); + el.append(''); + el.append('
    ' + burgsCount + '
    '); el.append(''); el.append('
    ' + areaConv + '
    '); el.append(''); @@ -7536,7 +7759,7 @@ function fantasyMap() { var index = getIndex(point); var x = rn(point[0], 2), y = rn(point[1], 2); - if (cells[index].height < 0.2) { + if (cells[index].height < 20) { tip("Cannot place capital on the water! Select a land cell"); return; } @@ -7578,7 +7801,7 @@ function fantasyMap() { } cells[index].region = state; cells[index].neighbors.map(function(n) { - if (cells[n].height < 0.2) {return;} + if (cells[n].height < 20) {return;} if (cells[n].manor !== undefined) {return;} cells[n].region = state; }); @@ -7656,7 +7879,7 @@ function fantasyMap() { editCountries(); } - $("#countriesNeutral").on("change", regenerateCountries); + $("#countriesNeutral, #countriesNeutralNumber").on("change", regenerateCountries); } // burgs list + editor @@ -7671,7 +7894,7 @@ function fantasyMap() { burgs.map(function(b) { $("#burgsBody").append('
    '); var el = $("#burgsBody div:last-child"); - el.append(''); + el.append(''); el.append(''); el.append(''); el.append('
    ' + cultures[b.culture].name + '
    '); @@ -7707,7 +7930,7 @@ function fantasyMap() { burgsFooterCulture.innerHTML = $("#burgsBody div:first-child .burgCulture").text(); var avPop = rn(d3.mean(populationArray), -1); burgsFooterPopulation.value = avPop; - $(".enlange").click(function() { + $(".enlarge").click(function() { var b = +(this.parentNode.id).slice(5); var l = labels.select("[data-id='" + b + "']"); var x = +l.attr("x"), y = +l.attr("y"); @@ -7886,6 +8109,7 @@ function fantasyMap() { urbPops[c] = urbPops[c] ? urbPops[c] + m.population : m.population; }); + if (!nameBases[0]) applyDefaultNamesData(); for (let c = 0; c < cultures.length; c++) { $("#culturesBody").append('
    '); if (cellsC[c] === undefined) { @@ -7901,7 +8125,9 @@ function fantasyMap() { const population = (urban + rural) * 1000; const populationConv = si(population); const title = '\'Total population: '+populationConv+'; Rural population: '+rural+'K; Urban population: '+urban+'K\''; - const base = nameBases[cultures[c].base].name; + const b = cultures[c].base; + if (b >= nameBases.length) b = 0; + const base = nameBases[b].name; const el = $("#culturesBody div:last-child"); el.append(''); el.append(''); @@ -8205,11 +8431,7 @@ function fantasyMap() { $("#namesbaseEditor").dialog({ title: "Namesbase Editor", minHeight: "auto", minWidth: Math.min(svgWidth, 400), - position: {my: "center", at: "center", of: "svg"}, - close: function() { - localStorage.setItem("nameBase", JSON.stringify(nameBase)); - localStorage.setItem("nameBases", JSON.stringify(nameBases)); - } + position: {my: "center", at: "center", of: "svg"} }); if (modules.editNamesbase) return; @@ -8316,8 +8538,6 @@ function fantasyMap() { document.getElementById("namesbaseTextarea").value = ""; document.getElementById("namesbaseTextarea").setAttribute("data-base", 0); document.getElementById("namesbaseExamples").innerHTML === ""; - localStorage.removeItem("nameBases"); - localStorage.removeItem("nameBase"); applyDefaultNamesData(); const baseMax = nameBases.length - 1; cultures.forEach(function(c) {if (c.base > baseMax) c.base = baseMax;}); @@ -8439,7 +8659,7 @@ function fantasyMap() { labels.select("#countries").selectAll("text").remove(); manors.map(function(m) { const cell = diagram.find(m.x, m.y).index; - if (cells[cell].height < 0.2) { + if (cells[cell].height < 20) { // remove manor in ocean m.region = "removed"; m.cell = cell; @@ -8451,7 +8671,7 @@ function fantasyMap() { } }); cells.map(function(c) { - if (c.height < 0.2) { + if (c.height < 20) { // no longer a land cell delete c.region; delete c.culture; @@ -8594,7 +8814,7 @@ function fantasyMap() { let change = []; let message = `Burgs will be renamed as below. Please confirm`; message += `
    `; - for (var i=0; i < data.length && i < manors.length; i++) { + for (let i=0; i < data.length && i < manors.length; i++) { const v = data[i]; if (v === "" || v === undefined) {continue;} if (v === manors[i].name) {continue;} @@ -8607,7 +8827,7 @@ function fantasyMap() { buttons: { Cancel: function() {$(this).dialog("close");}, Confirm: function() { - for (var i=0; i < change.length; i++) { + for (let i=0; i < change.length; i++) { const id = change[i].i; manors[id].name = change[i].name; labels.select("[data-id='" + id + "']").text(change[i].name); @@ -8711,134 +8931,164 @@ function fantasyMap() { icons.select("#town-anchors").attr("fill", "#ffffff").attr("stroke", "#3e3e4b").attr("stroke-width", 1.2).attr("size", 1); } - // Options handlers - $("input, select").on("input change", function() { - var id = this.id; - if (id === "hideLabels") {invokeActiveZooming();} - if (id === "styleElementSelect") { - const sel = this.value; - let el = viewbox.select("#"+sel); - if (sel == "ocean") el = oceanLayers.select("rect"); - $("#styleInputs div").hide(); - // opacity - $("#styleOpacity, #styleFilter").css("display", "block"); - var opacity = el.attr("opacity") || 1; - styleOpacityInput.value = styleOpacityOutput.value = opacity; - // filter - if (sel == "ocean") el = oceanLayers; - styleFilterInput.value = el.attr("filter") || ""; - if (sel === "rivers" || sel === "lakes" || sel === "landmass") { - $("#styleFill").css("display", "inline-block"); - styleFillInput.value = styleFillOutput.value = el.attr("fill"); - } - if (sel === "roads" || sel === "trails" || sel === "searoutes" || sel === "lakes" || sel === "stateBorders" || sel === "neutralBorders" || sel === "grid" || sel === "overlay" || sel === "coastline") { - $("#styleStroke").css("display", "inline-block"); - styleStrokeInput.value = styleStrokeOutput.value = el.attr("stroke"); - $("#styleStrokeWidth").css("display", "block"); - var width = el.attr("stroke-width") || ""; - styleStrokeWidthInput.value = styleStrokeWidthOutput.value = width; - } - if (sel === "roads" || sel === "trails" || sel === "searoutes" || sel === "stateBorders" || sel === "neutralBorders" || sel === "overlay") { - $("#styleStrokeDasharray, #styleStrokeLinecap").css("display", "block"); - styleStrokeDasharrayInput.value = el.attr("stroke-dasharray") || ""; - styleStrokeLinecapInput.value = el.attr("stroke-linecap") || "inherit"; - } - if (sel === "terrs") {$("#styleScheme").css("display", "block");} - if (sel === "heightmap") {$("#styleScheme").css("display", "block");} - if (sel === "labels") { - $("#styleFill, #styleFontSize").css("display", "inline-block"); - styleFillInput.value = styleFillOutput.value = el.select("g").attr("fill"); - } - if (sel === "overlay") { - $("#styleOverlay").css("display", "block"); - } - if (sel === "ocean") { - $("#styleOcean").css("display", "block"); - styleOceanBack.value = styleOceanBackOutput.value = svg.style("background-color"); - styleOceanFore.value = styleOceanForeOutput.value = oceanLayers.select("rect").attr("fill"); - } - return; - } - if (id === "styleFillInput") { - styleFillOutput.value = this.value; - var el = svg.select("#"+styleElementSelect.value); - if (styleElementSelect.value !== "labels") { - el.attr('fill', this.value); - } else { - el.selectAll("g").attr('fill', this.value); - } - return; - } - if (id === "styleStrokeInput") { - styleStrokeOutput.value = this.value; - var el = svg.select("#"+styleElementSelect.value); - el.attr('stroke', this.value); - return; - } - if (id === "styleStrokeWidthInput") { - styleStrokeWidthOutput.value = this.value; - var sel = styleElementSelect.value; - svg.select("#"+sel).attr('stroke-width', +this.value); - return; - } - if (id === "styleStrokeDasharrayInput") { - var sel = styleElementSelect.value; - svg.select("#"+sel).attr('stroke-dasharray', this.value); - return; - } - if (id === "styleStrokeLinecapInput") { - var sel = styleElementSelect.value; - svg.select("#"+sel).attr('stroke-linecap', this.value); - return; - } - if (id === "styleOpacityInput") { - styleOpacityOutput.value = this.value; - var sel = styleElementSelect.value; - svg.select("#"+sel).attr('opacity', this.value); - return; - } - if (id === "styleFilterInput") { - let sel = styleElementSelect.value; - if (sel == "ocean") sel = "oceanLayers"; - const el = svg.select("#"+sel); - el.attr('filter', this.value); - zoom.scaleBy(svg, 1.00001); // enforce browser re-draw - return; - } - if (id === "styleSchemeInput") { - terrs.selectAll("path").remove(); - toggleHeight(); - return; - } - if (id === "styleOverlayType") { - overlay.selectAll("*").remove(); - if (!$("#toggleOverlay").hasClass("buttonoff")) { - toggleOverlay(); - } - } - if (id === "styleOverlaySize") { - styleOverlaySizeOutput.value = this.value; - overlay.selectAll("*").remove(); - if (!$("#toggleOverlay").hasClass("buttonoff")) { - toggleOverlay(); - } - } - if (id === "styleOceanBack") { - svg.style("background-color", this.value); - styleOceanBackOutput.value = this.value; - } - if (id === "styleOceanFore") { - oceanLayers.select("rect").attr("fill", this.value); - styleOceanForeOutput.value = this.value; - } - if (id === "styleOceanPattern") { - oceanPattern.attr("opacity", +this.checked); - } - if (id === "styleOceanLayers") { - const display = this.checked ? "block" : "none"; - oceanLayers.selectAll("path").attr("display", display); + // Style options + $("#styleElementSelect").on("change", function() { + const sel = this.value; + let el = viewbox.select("#"+sel); + if (sel == "ocean") el = oceanLayers.select("rect"); + $("#styleInputs > div").hide(); + + // opacity + $("#styleOpacity, #styleFilter").css("display", "block"); + var opacity = el.attr("opacity") || 1; + styleOpacityInput.value = styleOpacityOutput.value = opacity; + + // filter + if (sel == "ocean") el = oceanLayers; + styleFilterInput.value = el.attr("filter") || ""; + if (sel === "rivers" || sel === "lakes" || sel === "landmass") { + $("#styleFill").css("display", "inline-block"); + styleFillInput.value = styleFillOutput.value = el.attr("fill"); } + if (sel === "roads" || sel === "trails" || sel === "searoutes" || sel === "lakes" || sel === "stateBorders" || sel === "neutralBorders" || sel === "grid" || sel === "overlay" || sel === "coastline") { + $("#styleStroke").css("display", "inline-block"); + styleStrokeInput.value = styleStrokeOutput.value = el.attr("stroke"); + $("#styleStrokeWidth").css("display", "block"); + var width = el.attr("stroke-width") || ""; + styleStrokeWidthInput.value = styleStrokeWidthOutput.value = width; + } + + if (sel === "roads" || sel === "trails" || sel === "searoutes" || sel === "stateBorders" || sel === "neutralBorders" || sel === "overlay") { + $("#styleStrokeDasharray, #styleStrokeLinecap").css("display", "block"); + styleStrokeDasharrayInput.value = el.attr("stroke-dasharray") || ""; + styleStrokeLinecapInput.value = el.attr("stroke-linecap") || "inherit"; + } + + if (sel === "terrs") $("#styleScheme").css("display", "block"); + if (sel === "heightmap") $("#styleScheme").css("display", "block"); + if (sel === "overlay") $("#styleOverlay").css("display", "block"); + + if (sel === "labels") { + $("#styleFill, #styleFontSize").css("display", "inline-block"); + styleFillInput.value = styleFillOutput.value = el.select("g").attr("fill") || "#3e3e4b"; + $("#styleLabelGroups").css("display", "inline-block"); + updateLabelGroups(); + } + + if (sel === "ocean") { + $("#styleOcean").css("display", "block"); + styleOceanBack.value = styleOceanBackOutput.value = svg.style("background-color"); + styleOceanFore.value = styleOceanForeOutput.value = oceanLayers.select("rect").attr("fill"); + } + }); + + // update Label Groups displayed on Style tab + function updateLabelGroups() { + if (styleElementSelect.value !== "labels") return; + const cont = d3.select("#styleLabelGroupItems"); + cont.selectAll("button").remove(); + labels.selectAll("g").each(function() { + const el = d3.select(this); + const id = el.attr("id"); + const name = id.charAt(0).toUpperCase() + id.substr(1); + const state = el.classed("hidden"); + if (id === "burgLabels") return; + cont.append("button").attr("id", id).text(name).classed("buttonoff", state).on("click", function() { + // toggle label group on click + if (hideLabels.checked) hideLabels.click(); + const el = d3.select("#"+this.id); + const state = !el.classed("hidden"); + el.classed("hidden", state); + d3.select(this).classed("buttonoff", state); + }); + }); + } + + $("#styleFillInput").on("input", function() { + styleFillOutput.value = this.value; + var el = svg.select("#"+styleElementSelect.value); + if (styleElementSelect.value !== "labels") { + el.attr('fill', this.value); + } else { + el.selectAll("g").attr('fill', this.value); + } + }); + + $("#styleStrokeInput").on("input", function() { + styleStrokeOutput.value = this.value; + const el = svg.select("#"+styleElementSelect.value); + el.attr('stroke', this.value); + }); + + $("#styleStrokeWidthInput").on("input", function() { + styleStrokeWidthOutput.value = this.value; + const el = svg.select("#"+styleElementSelect.value); + el.attr('stroke-width', +this.value); + }); + + $("#styleStrokeDasharrayInput").on("input", function() { + const sel = styleElementSelect.value; + svg.select("#"+sel).attr('stroke-dasharray', this.value); + }); + + $("#styleStrokeLinecapInput").on("change", function() { + const sel = styleElementSelect.value; + svg.select("#"+sel).attr('stroke-linecap', this.value); + }); + + $("#styleOpacityInput").on("input", function() { + styleOpacityOutput.value = this.value; + const sel = styleElementSelect.value; + svg.select("#"+sel).attr('opacity', this.value); + + }); + + $("#styleFilterInput").on("change", function() { + let sel = styleElementSelect.value; + if (sel == "ocean") sel = "oceanLayers"; + const el = svg.select("#"+sel); + el.attr('filter', this.value); + zoom.scaleBy(svg, 1.00001); // enforce browser re-draw + }); + + $("#styleSchemeInput").on("change", function() { + terrs.selectAll("path").remove(); + toggleHeight(); + }); + + $("#styleOverlayType").on("change", function() { + overlay.selectAll("*").remove(); + if (!$("#toggleOverlay").hasClass("buttonoff")) toggleOverlay(); + }); + + $("#styleOverlaySize").on("input", function() { + styleOverlaySizeOutput.value = this.value; + overlay.selectAll("*").remove(); + if (!$("#toggleOverlay").hasClass("buttonoff")) toggleOverlay(); + }); + + $("#styleOceanBack").on("input", function() { + svg.style("background-color", this.value); + styleOceanBackOutput.value = this.value; + }); + + $("#styleOceanFore").on("input", function() { + oceanLayers.select("rect").attr("fill", this.value); + styleOceanForeOutput.value = this.value; + }); + + $("#styleOceanPattern").on("click", function() {oceanPattern.attr("opacity", +this.checked);}); + + $("#styleOceanLayers").on("click", function() { + const display = this.checked ? "block" : "none"; + oceanLayers.selectAll("path").attr("display", display); + }); + + // Other Options handlers + $("input, select").on("input change", function() { + var id = this.id; + if (id === "hideLabels") invokeActiveZooming(); if (id === "mapWidthInput" || id === "mapHeightInput") { changeMapSize(); autoResize = false; @@ -8869,8 +9119,9 @@ function fantasyMap() { if (id === "culturesInput") {culturesOutput.value = this.value; localStorage.setItem("cultures", this.value);} if (id === "precInput") {precOutput.value = +precInput.value; localStorage.setItem("prec", this.value);} if (id === "swampinessInput") {swampinessOutput.value = this.value; localStorage.setItem("swampiness", this.value);} - if (id === "outlineLayersInput") {localStorage.setItem("outlineLayers", this.value);} - if (id === "pngResolutionInput") {localStorage.setItem("pngResolution", this.value);} + if (id === "outlineLayersInput") localStorage.setItem("outlineLayers", this.value); + if (id === "transparencyInput") changeDialogsTransparency(this.value); + if (id === "pngResolutionInput") localStorage.setItem("pngResolution", this.value); if (id === "zoomExtentMin" || id === "zoomExtentMax") { zoom.scaleExtent([+zoomExtentMin.value, +zoomExtentMax.value]); zoom.scaleTo(svg, +this.value); @@ -8983,7 +9234,7 @@ function fantasyMap() { $("#optionsReset").click(restoreDefaultOptions); $("#rescaler").change(function() { - var change = rn((+this.value - 5) / 10, 2); + const change = rn((+this.value - 5), 2); modifyHeights("all", change, 1); updateHeightmap(); updateHistory(); @@ -9034,7 +9285,7 @@ function fantasyMap() { $(".tabcontent").hide(); $(".tab > button").removeClass("active"); $(this).addClass("active"); - var id = this.id; + const id = this.id; if (id === "layoutTab") {$("#layoutContent").show();} if (id === "styleTab") {$("#styleContent").show();} if (id === "optionsTab") {$("#optionsContent").show();} @@ -9042,6 +9293,18 @@ function fantasyMap() { if (id === "aboutTab") {$("#aboutContent").show();} }); + // Generate map from provided seed + $("#optionsSeedGenerate").on("click", function() { + if (optionsSeed.value == seed) return; + seed = optionsSeed.value; + console.log(" seed: " + seed); + Math.seedrandom(seed); + exitCustomization(); + undraw(); + resetZoom(1000); + generate(); + }); + // Pull request from @evyatron // https://github.com/Azgaar/Fantasy-Map-Generator/pull/49 function addDragToUpload() { From f3e36dc4557b886777053ad8df0b0885da20eb4d Mon Sep 17 00:00:00 2001 From: Azgaar Date: Wed, 29 Aug 2018 00:14:41 +0300 Subject: [PATCH 19/25] v. 0.59.01b --- index.html | 6 +++--- script.js | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index f083a2e5..714d9b56 100644 --- a/index.html +++ b/index.html @@ -32,8 +32,8 @@ - - + + @@ -1143,5 +1143,5 @@ - + diff --git a/script.js b/script.js index c49b36dd..012e7f94 100644 --- a/script.js +++ b/script.js @@ -205,7 +205,7 @@ function fantasyMap() {
  • Dialogs style changes, optional transparency
  • Ability to toggle Label groups separately
  • Bug fixes
  • -
    See a dedecated post for the details. +
    See a dedicated post for the details. Please report bugs here. Join our Reddit community to share created maps, discuss the Generator, ask questions and propose new features.`; @@ -3404,6 +3404,7 @@ function fantasyMap() { // open in MFCG $("#burgSeeInMFCG").click(function() { const id = +elSelected.attr("data-id"); + const name = manors[id].name; const cell = manors[id].cell; const pop = rn(manors[id].population); const size = pop > 65 ? 65 : pop < 6 ? 6 : pop; @@ -3414,7 +3415,7 @@ function fantasyMap() { const sec = pop > 40 ? 1 : Math.random() < pop / 100 ? 1 : 0; const thr = sec && Math.random() < 0.8 ? 1 : 0; const url = "http://fantasycities.watabou.ru/"; - let params = `?size=${size}&seed=${s}&hub=${hub}&random=0&continuous=0` + let params = `?name=${name}&size=${size}&seed=${s}&hub=${hub}&random=0&continuous=0` params += `&river=${river}&coast=${coast}&citadel=${id&1}&plaza=${sec}&temple=${thr}&walls=${sec}&shantytown=${sec}`; const win = window.open(url+params, '_blank'); win.focus(); From e8801a31cf75780047eb4a56e738c7c324e767d1 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Wed, 29 Aug 2018 13:34:18 +0300 Subject: [PATCH 20/25] v. 0.58.02b Emergency drop to fix the issue 114 --- script.js | 73 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/script.js b/script.js index 012e7f94..80cf201f 100644 --- a/script.js +++ b/script.js @@ -1887,8 +1887,8 @@ function fantasyMap() { depression = 0; for (let i = 0; i < land.length; i++) { if (land[i].ctype === 99) continue; - const heights = land[i].neighbors.map(function(n) {return cells[n].height}); - const minHigh = d3.min(heights); + const nHeights = land[i].neighbors.map(function(n) {return cells[n].height}); + const minHigh = d3.min(nHeights); if (land[i].height <= minHigh) { depression++; land[i].pit = land[i].pit ? land[i].pit + 1 : 1; @@ -4714,8 +4714,8 @@ function fantasyMap() { let height = i.height; if (height < 20 && !i.lake) return; if (i.lake) { - const heights = i.neighbors.map(function(e) {if (cells[e].height >= 20) return cells[e].height;}) - const mean = d3.mean(heights); + const nHeights = i.neighbors.map(function(e) {if (cells[e].height >= 20) return cells[e].height;}) + const mean = d3.mean(nHeights); if (!mean) return; height = Math.trunc(mean); if (height < 20 || isNaN(height)) height = 20; @@ -5215,9 +5215,9 @@ function fantasyMap() { cell.river = river; var x = cell.data[0], y = cell.data[1]; dataRiver.push({x, y, cell:index}); - var heights = []; - cell.neighbors.forEach(function(e) {heights.push(cells[e].height);}); - var minId = heights.indexOf(d3.min(heights)); + var nHeights = []; + cell.neighbors.forEach(function(e) {nHeights.push(cells[e].height);}); + var minId = nHeights.indexOf(d3.min(nHeights)); var min = cell.neighbors[minId]; var tx = cells[min].data[0], ty = cells[min].data[1]; if (cells[min].height < 20) { @@ -6161,16 +6161,7 @@ function fantasyMap() { // update data newPoints = [], riversData = [], queue = [], elSelected = ""; points = JSON.parse(data[1]); - if (data[10]) {heights = new Uint8Array(data[10].split(","));} - else { - heights = new Uint8Array(points.length); - for (let i=0; i < points.length; i++) { - const cell = diagram.find(points[i][0], points[i][1]).index; - heights[i] = cells[cell].height; - } - } cells = JSON.parse(data[2]); - manors = JSON.parse(data[3]); if (data[7]) cultures = JSON.parse(data[7]); if (data[7] === undefined) generateCultures(); @@ -6182,39 +6173,49 @@ function fantasyMap() { if (b === undefined) c.base = 0; if (!nameBase[b] || !nameBases[b]) c.base = 0; }); + const graphSizeAdj = 90 / Math.sqrt(cells.length, 2); // adjust to different graphSize // cells validations - cells.forEach(function(c) { + cells.forEach(function(c, d) { // collect points newPoints.push(c.data); - // update old 0-1 height range to new 0-100 range - if (c.height > 1) return; - if (c.height === 1 && c.region === undefined && c.flux === undefined) return; - c.height = Math.trunc(c.height * 100); + // update old 0-1 height range to a new 0-100 range + if (c.height < 1) c.height = Math.trunc(c.height * 100); + if (c.height === 1 && c.flux !== undefined) c.height = 100; // check if there unavailable cultures if (c.culture > cultures.length - 1) cultures.push({name:"AUTO_"+c.culture, color:"#ff0000", base:0}); + + // calculate areas / population for old maps + if (c.height >= 20) { + if (!polygons[d] || !polygons[d].length) return; + if (c.area === undefined || isNaN(c.area)) { + const area = d3.polygonArea(polygons[d]); + c.area = rn(Math.abs(area), 2); + } + if (c.pop === undefined || isNaN(c.pop)) { + let population = 0; + const elevationFactor = Math.pow((100 - c.height) / 100, 3); + population = elevationFactor * c.area * graphSizeAdj; + if (c.region === "neutral") population *= 0.5; + c.pop = rn(population, 1); + } + } }); land = $.grep(cells, function(e) {return (e.height >= 20);}); calculateVoronoi(newPoints); - // calculate areas / population for old maps - const graphSizeAdj = 90 / Math.sqrt(cells.length, 2); // adjust to different graphSize - land.forEach(function(i) { - const p = i.index; - if (!polygons[p] || !polygons[p].length) return; - const area = d3.polygonArea(polygons[p]); - i.area = rn(Math.abs(area), 2); - if (i.pop === undefined) { - let population = 0; - const elevationFactor = Math.pow((100 - i.height) / 100, 3); - population = elevationFactor * i.area * graphSizeAdj; - if (i.region === "neutral") population *= 0.5; - i.pop = rn(population, 1); - } - }); + // get heights Uint8Array + if (data[10]) {heights = new Uint8Array(data[10].split(","));} + else { + heights = new Uint8Array(points.length); + for (let i=0; i < points.length; i++) { + const cell = diagram.find(points[i][0], points[i][1]).index; + heights[i] = cells[cell].height; + } + } // restore Heightmap customization mode if (customization === 1) { From 0f79271c7f4dce01f8a7195e51ad522eaf9404bb Mon Sep 17 00:00:00 2001 From: Azgaar Date: Wed, 29 Aug 2018 13:35:06 +0300 Subject: [PATCH 21/25] v. 0.58.03b --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 714d9b56..471381aa 100644 --- a/index.html +++ b/index.html @@ -32,8 +32,8 @@ - - + + @@ -1143,5 +1143,5 @@ - + From efd6a0eda32d54fa805e3490053bf7453d4b6b31 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Wed, 29 Aug 2018 16:10:03 +0300 Subject: [PATCH 22/25] v. 0.59.04b --- script.js | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/script.js b/script.js index 80cf201f..4943c1fc 100644 --- a/script.js +++ b/script.js @@ -6166,12 +6166,20 @@ function fantasyMap() { if (data[7]) cultures = JSON.parse(data[7]); if (data[7] === undefined) generateCultures(); + // place random point + function placePoint() { + const x = Math.floor(Math.random() * graphWidth * 0.8 + graphWidth * 0.1); + const y = Math.floor(Math.random() * graphHeight * 0.8 + graphHeight * 0.1); + return [x, y]; + } + // ensure each culure has a valid namesbase assigned, if not assign first base if (!nameBase[0]) applyDefaultNamesData(); cultures.forEach(function(c) { const b = c.base; if (b === undefined) c.base = 0; if (!nameBase[b] || !nameBases[b]) c.base = 0; + if (c.center === undefined) c.center = placePoint(); }); const graphSizeAdj = 90 / Math.sqrt(cells.length, 2); // adjust to different graphSize @@ -6182,18 +6190,23 @@ function fantasyMap() { // update old 0-1 height range to a new 0-100 range if (c.height < 1) c.height = Math.trunc(c.height * 100); - if (c.height === 1 && c.flux !== undefined) c.height = 100; + if (c.height === 1 && c.region !== undefined && c.flux !== undefined) c.height = 100; + + // check if there are any unavailable cultures + if (c.culture > cultures.length - 1) { + const center = [c.data[0], c.data[1]]; + const cult = {name:"AUTO_"+c.culture, color:"#ff0000", base:0, center}; + cultures.push(cult); + } - // check if there unavailable cultures - if (c.culture > cultures.length - 1) cultures.push({name:"AUTO_"+c.culture, color:"#ff0000", base:0}); - - // calculate areas / population for old maps if (c.height >= 20) { if (!polygons[d] || !polygons[d].length) return; + // calculate area if (c.area === undefined || isNaN(c.area)) { const area = d3.polygonArea(polygons[d]); c.area = rn(Math.abs(area), 2); } + // calculate population if (c.pop === undefined || isNaN(c.pop)) { let population = 0; const elevationFactor = Math.pow((100 - c.height) / 100, 3); @@ -6201,6 +6214,8 @@ function fantasyMap() { if (c.region === "neutral") population *= 0.5; c.pop = rn(population, 1); } + // if culture is undefined, set to 0 + if (c.culture === undefined || isNaN(c.culture)) c.culture = 0; } }); From 5ddbfed1e49c21de3885496ae0d39f3eac8e5ca2 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Wed, 29 Aug 2018 18:19:26 +0300 Subject: [PATCH 23/25] v. 0.59.05b --- script.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/script.js b/script.js index 4943c1fc..364a7af1 100644 --- a/script.js +++ b/script.js @@ -5734,11 +5734,13 @@ function fantasyMap() { // downalod map as SVG or PNG file function saveAsImage(type) { console.time("saveAsImage"); - // get all used fonts + const webSafe = ["Georgia", "Times+New+Roman", "Comic+Sans+MS", "Lucida+Sans+Unicode", "Courier+New", "Verdana", "Arial", "Impact"]; + // get non-standard fonts used for labels to fetch them from web const fontsInUse = []; // to store fonts currently in use labels.selectAll("g").each(function(d) { const font = d3.select(this).attr("data-font"); if (!font) return; + if (webSafe.indexOf(font) !== -1) return; // do not fetch web-safe fonts if (fontsInUse.indexOf(font) === -1) fontsInUse.push(font); }); const fontsToLoad = "https://fonts.googleapis.com/css?family=" + fontsInUse.join("|"); From 73493a791db3b95b6ed6a8f96db6ffdbe6c17854 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sat, 1 Sep 2018 00:32:46 +0300 Subject: [PATCH 24/25] v. 0.50.06b --- index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 471381aa..b85594a1 100644 --- a/index.html +++ b/index.html @@ -32,8 +32,8 @@ - - + + @@ -159,7 +159,7 @@
    Azgaar's
    Fantasy Map Generator
    -
    v. 0.58b
    +
    v. 0.59b

    LOADING...

    @@ -1143,5 +1143,5 @@ - + From d0687ed540ea0ef980481d751cae481ce4f70aad Mon Sep 17 00:00:00 2001 From: Azgaar Date: Sat, 1 Sep 2018 23:32:55 +0300 Subject: [PATCH 25/25] v. 0.59.07b --- index.html | 14 +-- script.js | 304 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 185 insertions(+), 133 deletions(-) diff --git a/index.html b/index.html index 714d9b56..a82db6a4 100644 --- a/index.html +++ b/index.html @@ -32,8 +32,8 @@ - - + + @@ -159,7 +159,7 @@
    Azgaar's
    Fantasy Map Generator
    -
    v. 0.58b
    +
    v. 0.59b

    LOADING...

    @@ -205,8 +205,8 @@ @@ -551,7 +551,7 @@
    - +
    IdCurrent nameNew Name