"use strict"; function showEPForRoute(node) { const points = []; debug.select("#controlPoints").selectAll("circle").each(function() { const i = findCell(this.getAttribute("cx"), this.getAttribute("cy")); points.push(i); }); const routeLen = node.getTotalLength() * distanceScaleInput.value; showElevationProfile(points, routeLen, false); } function showEPForRiver(node) { const points = []; debug.select("#controlPoints").selectAll("circle").each(function() { const i = findCell(this.getAttribute("cx"), this.getAttribute("cy")); points.push(i); }); const riverLen = (node.getTotalLength() / 2) * distanceScaleInput.value; showElevationProfile(points, riverLen, true); } function showElevationProfile(data, routeLen, isRiver) { // data is an array of cell indexes, routeLen is the distance (in actual metres/feet), isRiver should be true for rivers, false otherwise document.getElementById("epScaleRange").addEventListener("change", draw); document.getElementById("epCurve").addEventListener("change", draw); document.getElementById("epSave").addEventListener("click", downloadCSV); $("#elevationProfile").dialog({ title: "Elevation profile", resizable: false, width: window.width, close: closeElevationProfile, position: {my: "left top", at: "left+20 bottom-500", of: window, collision: "fit"} }); // prevent river graphs from showing rivers as flowing uphill - remember the general slope var slope = 0; if (isRiver) { if (pack.cells.h[data[0]] < pack.cells.h[data[data.length-1]]) { slope = 1; // up-hill } else if (pack.cells.h[data[0]] > pack.cells.h[data[data.length-1]]) { slope = -1; // down-hill } } const chartWidth = window.innerWidth-180; const chartHeight = 300; // height of our land/sea profile, excluding the biomes data below const xOffset = 80; const yOffset = 80; // this is our drawing starting point from top-left (y = 0) of SVG const biomesHeight = 40; let lastBurgIndex = 0; let lastBurgCell = 0; let burgCount = 0; let chartData = {biome:[], burg:[], cell:[], height:[], mi:1000000, ma:0, mih: 100, mah: 0, points:[] } for (let i=0, prevB=0, prevH=-1; i prevH) h = prevH; } } prevH = h; // river up-hill checks stop here let b = pack.cells.burg[cell]; if (b == prevB) b = 0; else prevB = b; if (b) { burgCount++; lastBurgIndex = i; lastBurgCell = cell; } chartData.biome[i] = pack.cells.biome[cell]; chartData.burg[i] = b; chartData.cell[i] = cell; let sh = getHeight(h); chartData.height[i] = parseInt(sh.substr(0, sh.indexOf(' '))); chartData.mih = Math.min(chartData.mih, h); chartData.mah = Math.max(chartData.mah, h); chartData.mi = Math.min(chartData.mi, chartData.height[i]); chartData.ma = Math.max(chartData.ma, chartData.height[i]); } if (lastBurgIndex != 0 && lastBurgCell == chartData.cell[data.length-1] && lastBurgIndex < data.length) { chartData.burg[data.length-1] = chartData.burg[lastBurgIndex]; chartData.burg[lastBurgIndex] = 0; } draw(); function downloadCSV() { let data = "Point,X,Y,Cell,Height,Height value,Population,Burg,Burg population,Biome,Biome color,Culture,Culture color,Religion,Religion color,Province,Province color,State,State color\n"; // headers for (let k=0; k= chartData.mih; k--) { let perc = 1 - (k - chartData.mih) / (chartData.mah - chartData.mih); landdef.append("stop").attr("offset", perc*100 + "%").attr("style", "stop-color:" + getColor(k, colors) + ";stop-opacity:1"); } } // land let curve = d3.line().curve(d3.curveBasis); // see https://github.com/d3/d3-shape#curves let epCurveIndex = parseInt(epCurve.selectedIndex); switch(epCurveIndex) { case 0 : curve = d3.line().curve(d3.curveLinear); break; case 1 : curve = d3.line().curve(d3.curveBasis); break; case 2 : curve = d3.line().curve(d3.curveBundle.beta(1)); break; case 3 : curve = d3.line().curve(d3.curveCatmullRom.alpha(0.5)); break; case 4 : curve = d3.line().curve(d3.curveMonotoneX); break; case 5 : curve = d3.line().curve(d3.curveNatural); break; } // copy the points so that we can add extra straight pieces, else we get curves at the ends of the chart let extra = chartData.points.slice(); var path = curve(extra); // this completes the right-hand side and bottom of our land "polygon" path += " L" + parseInt(xscale(extra.length) + +xOffset) + "," + parseInt(extra[extra.length-1][1]); path += " L" + parseInt(xscale(extra.length) + +xOffset) + "," + parseInt(yscale(0) + +yOffset); path += " L" + parseInt(xscale(0) + +xOffset) +"," + parseInt(yscale(0) + +yOffset); path += "Z"; chart.append("g").attr("id", "epland").append("path").attr("d", path).attr("stroke", "purple").attr("stroke-width", "0").attr("fill", "url(#landdef)"); // biome / heights let g = chart.append("g").attr("id", "epbiomes"); const hu = heightUnit.value; for(var k=0; k 0) { let b = chartData.burg[k]; let x1 = chartData.points[k][0]; // left side of graph by default if (k > 0) x1 += xwidth/2; // center it if not first if (k == chartData.points.length-1) x1 = chartWidth + xOffset; // right part of graph y1+=add; if (y1 >= yOffset) { y1 = add; } var d1 = 0; // burg name g.append("text").attr("id", "ep" + b).attr("class", "epburglabel").attr("x", x1).attr("y", y1).attr("text-anchor", "middle"); document.getElementById("ep" + b).innerHTML = pack.burgs[b].name; // arrow from burg name to graph line g.append("path").attr("id", "eparrow" + b).attr("d", "M" + x1.toString() + "," + (y1+3).toString() + "L" + x1.toString() + "," + parseInt(chartData.points[k][1]-3).toString()).attr("stroke", "darkgray").attr("fill", "lightgray").attr("stroke-width", "1").attr("marker-end", "url(#arrowhead)"); } } } function closeElevationProfile() { document.getElementById("epScaleRange").removeEventListener("change", draw); document.getElementById("epCurve").removeEventListener("change", draw); document.getElementById("epSave").removeEventListener("click", downloadCSV); document.getElementById("elevationGraph").innerHTML = ""; modules.elevation = false; } }