Fantasy-Map-Generator/src/modules/legend.js
2022-07-05 21:12:55 +03:00

115 lines
3.6 KiB
JavaScript

import * as d3 from "d3";
import {rn} from "../utils/numberUtils";
import {parseTransform} from "utils/stringUtils";
export function drawLegend(name, data) {
legend.selectAll("*").remove(); // fully redraw every time
legend.attr("data", data.join("|")); // store data
const itemsInCol = +styleLegendColItems.value;
const fontSize = +legend.attr("font-size");
const backClr = styleLegendBack.value;
const opacity = +styleLegendOpacity.value;
const lineHeight = Math.round(fontSize * 1.7);
const colorBoxSize = Math.round(fontSize / 1.7);
const colOffset = fontSize;
const vOffset = fontSize / 2;
// append items
const boxes = legend.append("g").attr("stroke-width", 0.5).attr("stroke", "#111111").attr("stroke-dasharray", "none");
const labels = legend.append("g").attr("fill", "#000000").attr("stroke", "none");
const columns = Math.ceil(data.length / itemsInCol);
for (let column = 0, i = 0; column < columns; column++) {
const linesInColumn = Math.ceil(data.length / columns);
const offset = column ? colOffset * 2 + legend.node().getBBox().width : colOffset;
for (let l = 0; l < linesInColumn && data[i]; l++, i++) {
boxes
.append("rect")
.attr("fill", data[i][1])
.attr("x", offset)
.attr("y", lineHeight + l * lineHeight + vOffset)
.attr("width", colorBoxSize)
.attr("height", colorBoxSize);
labels
.append("text")
.text(data[i][2])
.attr("x", offset + colorBoxSize * 1.6)
.attr("y", fontSize / 1.6 + lineHeight + l * lineHeight + vOffset);
}
}
// append label
const offset = colOffset + legend.node().getBBox().width / 2;
labels
.append("text")
.attr("text-anchor", "middle")
.attr("font-weight", "bold")
.attr("font-size", "1.2em")
.attr("id", "legendLabel")
.text(name)
.attr("x", offset)
.attr("y", fontSize * 1.1 + vOffset / 2);
// append box
const bbox = legend.node().getBBox();
const width = bbox.width + colOffset * 2;
const height = bbox.height + colOffset / 2 + vOffset;
legend
.insert("rect", ":first-child")
.attr("id", "legendBox")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr("fill", backClr)
.attr("fill-opacity", opacity);
fitLegendBox();
}
// fit Legend box to canvas size
export function fitLegendBox() {
if (!legend.selectAll("*").size()) return;
const px = isNaN(+legend.attr("data-x")) ? 99 : legend.attr("data-x") / 100;
const py = isNaN(+legend.attr("data-y")) ? 93 : legend.attr("data-y") / 100;
const bbox = legend.node().getBBox();
const x = rn(svgWidth * px - bbox.width),
y = rn(svgHeight * py - bbox.height);
legend.attr("transform", `translate(${x},${y})`);
}
// draw legend with the same data, but using different settings
export function redrawLegend() {
if (!legend.select("rect").size()) return;
const name = legend.select("#legendLabel").text();
const data = legend
.attr("data")
.split("|")
.map(l => l.split(","));
drawLegend(name, data);
}
export function dragLegendBox() {
const tr = parseTransform(this.getAttribute("transform"));
const x = +tr[0] - d3.event.x;
const y = +tr[1] - d3.event.y;
const bbox = legend.node().getBBox();
d3.event.on("drag", function () {
const px = rn(((x + d3.event.x + bbox.width) / svgWidth) * 100, 2);
const py = rn(((y + d3.event.y + bbox.height) / svgHeight) * 100, 2);
const transform = `translate(${x + d3.event.x},${y + d3.event.y})`;
legend.attr("transform", transform).attr("data-x", px).attr("data-y", py);
});
}
export function clearLegend() {
legend.selectAll("*").remove();
legend.attr("data", null);
}