mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2026-03-23 23:57:23 +01:00
feat: integrate label generation into main flow and enhance label data handling
This commit is contained in:
parent
c467f87df5
commit
94b638f3cb
4 changed files with 219 additions and 104 deletions
|
|
@ -650,6 +650,8 @@ async function generate(options) {
|
||||||
Provinces.generate();
|
Provinces.generate();
|
||||||
Provinces.getPoles();
|
Provinces.getPoles();
|
||||||
|
|
||||||
|
Labels.generate();
|
||||||
|
|
||||||
Rivers.specify();
|
Rivers.specify();
|
||||||
Lakes.defineNames();
|
Lakes.defineNames();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,7 @@ export interface StateLabelData {
|
||||||
type: "state";
|
type: "state";
|
||||||
stateId: number;
|
stateId: number;
|
||||||
text: string;
|
text: string;
|
||||||
pathPoints: [number, number][];
|
fontSize?: number;
|
||||||
startOffset: number;
|
|
||||||
fontSize: number;
|
|
||||||
letterSpacing: number;
|
|
||||||
transform: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BurgLabelData {
|
export interface BurgLabelData {
|
||||||
|
|
@ -32,10 +28,10 @@ export interface CustomLabelData {
|
||||||
group: string;
|
group: string;
|
||||||
text: string;
|
text: string;
|
||||||
pathPoints: [number, number][];
|
pathPoints: [number, number][];
|
||||||
startOffset: number;
|
startOffset?: number;
|
||||||
fontSize: number;
|
fontSize?: number;
|
||||||
letterSpacing: number;
|
letterSpacing?: number;
|
||||||
transform: string;
|
transform?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LabelData = StateLabelData | BurgLabelData | CustomLabelData;
|
export type LabelData = StateLabelData | BurgLabelData | CustomLabelData;
|
||||||
|
|
@ -52,6 +48,12 @@ class LabelsModule {
|
||||||
return existingIds[existingIds.length - 1] + 1;
|
return existingIds[existingIds.length - 1] + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generate() : void {
|
||||||
|
this.clear();
|
||||||
|
generateStateLabels();
|
||||||
|
generateBurgLabels();
|
||||||
|
}
|
||||||
|
|
||||||
getAll(): LabelData[] {
|
getAll(): LabelData[] {
|
||||||
return pack.labels;
|
return pack.labels;
|
||||||
}
|
}
|
||||||
|
|
@ -145,4 +147,78 @@ class LabelsModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate state labels data entries for each state.
|
||||||
|
* Only stores essential label data; raycast path calculation happens during rendering.
|
||||||
|
* @param list - Optional array of stateIds to regenerate only those
|
||||||
|
*/
|
||||||
|
export function generateStateLabels(list?: number[]): void {
|
||||||
|
if (!TIME) console.time("generateStateLabels");
|
||||||
|
else TIME && console.time("generateStateLabels");
|
||||||
|
|
||||||
|
const { states } = pack;
|
||||||
|
const labelsModule = window.Labels;
|
||||||
|
|
||||||
|
// Remove existing state labels that need regeneration
|
||||||
|
if (list) {
|
||||||
|
list.forEach((stateId) => labelsModule.removeStateLabel(stateId));
|
||||||
|
} else {
|
||||||
|
labelsModule.removeByType("state");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate new label entries
|
||||||
|
for (const state of states) {
|
||||||
|
if (!state.i || state.removed || state.lock) continue;
|
||||||
|
if (list && !list.includes(state.i)) continue;
|
||||||
|
|
||||||
|
labelsModule.addStateLabel({
|
||||||
|
stateId: state.i,
|
||||||
|
text: state.name!,
|
||||||
|
fontSize: 100,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TIME) console.timeEnd("generateStateLabels");
|
||||||
|
else TIME && console.timeEnd("generateStateLabels");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate burg labels data from burgs.
|
||||||
|
* Populates pack.labels with BurgLabelData for each burg.
|
||||||
|
*/
|
||||||
|
export function generateBurgLabels(): void {
|
||||||
|
if (!TIME) console.time("generateBurgLabels");
|
||||||
|
else TIME && console.time("generateBurgLabels");
|
||||||
|
|
||||||
|
const labelsModule = window.Labels;
|
||||||
|
|
||||||
|
// Remove existing burg labels
|
||||||
|
labelsModule.removeByType("burg");
|
||||||
|
|
||||||
|
// Generate new labels for all active burgs
|
||||||
|
for (const burg of pack.burgs) {
|
||||||
|
if (!burg.i || burg.removed) continue;
|
||||||
|
|
||||||
|
const group = burg.group || "unmarked";
|
||||||
|
|
||||||
|
// Get label group offset attributes if they exist (will be set during rendering)
|
||||||
|
// For now, use defaults - these will be updated during rendering phase
|
||||||
|
const dx = 0;
|
||||||
|
const dy = 0;
|
||||||
|
|
||||||
|
labelsModule.addBurgLabel({
|
||||||
|
burgId: burg.i,
|
||||||
|
group,
|
||||||
|
text: burg.name!,
|
||||||
|
x: burg.x,
|
||||||
|
y: burg.y,
|
||||||
|
dx,
|
||||||
|
dy,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TIME) console.timeEnd("generateBurgLabels");
|
||||||
|
else TIME && console.timeEnd("generateBurgLabels");
|
||||||
|
}
|
||||||
|
|
||||||
window.Labels = new LabelsModule();
|
window.Labels = new LabelsModule();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import type { Burg } from "../modules/burgs-generator";
|
import type { Burg } from "../modules/burgs-generator";
|
||||||
|
import type { BurgLabelData } from "../modules/labels";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
var drawBurgLabels: () => void;
|
var drawBurgLabels: () => void;
|
||||||
|
|
@ -15,31 +16,42 @@ const burgLabelsRenderer = (): void => {
|
||||||
TIME && console.time("drawBurgLabels");
|
TIME && console.time("drawBurgLabels");
|
||||||
createLabelGroups();
|
createLabelGroups();
|
||||||
|
|
||||||
for (const { name } of options.burgs.groups as BurgGroup[]) {
|
// Get all burg labels grouped by group name
|
||||||
const burgsInGroup = pack.burgs.filter(
|
const burgLabelsByGroup = new Map<string, BurgLabelData[]>();
|
||||||
(b) => b.group === name && !b.removed,
|
for (const label of Labels.getByType("burg").map((l) => l as BurgLabelData)) {
|
||||||
);
|
if (!burgLabelsByGroup.has(label.group)) {
|
||||||
if (!burgsInGroup.length) continue;
|
burgLabelsByGroup.set(label.group, []);
|
||||||
|
}
|
||||||
|
burgLabelsByGroup.get(label.group)!.push(label);
|
||||||
|
}
|
||||||
|
|
||||||
const labelGroup = burgLabels.select<SVGGElement>(`#${name}`);
|
// Render each group and update label offsets from SVG attributes
|
||||||
|
for (const [groupName, labels] of burgLabelsByGroup) {
|
||||||
|
const labelGroup = burgLabels.select<SVGGElement>(`#${groupName}`);
|
||||||
if (labelGroup.empty()) continue;
|
if (labelGroup.empty()) continue;
|
||||||
|
|
||||||
const dx = labelGroup.attr("data-dx") || 0;
|
const dxAttr = labelGroup.attr("data-dx");
|
||||||
const dy = labelGroup.attr("data-dy") || 0;
|
const dyAttr = labelGroup.attr("data-dy");
|
||||||
|
const dx = dxAttr ? parseFloat(dxAttr) : 0;
|
||||||
|
const dy = dyAttr ? parseFloat(dyAttr) : 0;
|
||||||
|
|
||||||
labelGroup
|
for (const labelData of labels) {
|
||||||
.selectAll("text")
|
// Update label data with SVG group offsets
|
||||||
.data(burgsInGroup)
|
if (labelData.dx !== dx || labelData.dy !== dy) {
|
||||||
.enter()
|
Labels.updateLabel(labelData.i, { dx, dy });
|
||||||
.append("text")
|
}
|
||||||
.attr("text-rendering", "optimizeSpeed")
|
|
||||||
.attr("id", (d) => `burgLabel${d.i}`)
|
labelGroup
|
||||||
.attr("data-id", (d) => d.i!)
|
.append("text")
|
||||||
.attr("x", (d) => d.x)
|
.attr("text-rendering", "optimizeSpeed")
|
||||||
.attr("y", (d) => d.y)
|
.attr("id", `burgLabel${labelData.burgId}`)
|
||||||
.attr("dx", `${dx}em`)
|
.attr("data-id", labelData.burgId)
|
||||||
.attr("dy", `${dy}em`)
|
.attr("x", labelData.x)
|
||||||
.text((d) => d.name!);
|
.attr("y", labelData.y)
|
||||||
|
.attr("dx", `${dx}em`)
|
||||||
|
.attr("dy", `${dy}em`)
|
||||||
|
.text(labelData.text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TIME && console.timeEnd("drawBurgLabels");
|
TIME && console.timeEnd("drawBurgLabels");
|
||||||
|
|
@ -48,14 +60,40 @@ const burgLabelsRenderer = (): void => {
|
||||||
const drawBurgLabelRenderer = (burg: Burg): void => {
|
const drawBurgLabelRenderer = (burg: Burg): void => {
|
||||||
const labelGroup = burgLabels.select<SVGGElement>(`#${burg.group}`);
|
const labelGroup = burgLabels.select<SVGGElement>(`#${burg.group}`);
|
||||||
if (labelGroup.empty()) {
|
if (labelGroup.empty()) {
|
||||||
drawBurgLabels();
|
burgLabelsRenderer();
|
||||||
return; // redraw all labels if group is missing
|
return; // redraw all labels if group is missing
|
||||||
}
|
}
|
||||||
|
|
||||||
const dx = labelGroup.attr("data-dx") || 0;
|
const dxAttr = labelGroup.attr("data-dx");
|
||||||
const dy = labelGroup.attr("data-dy") || 0;
|
const dyAttr = labelGroup.attr("data-dy");
|
||||||
|
const dx = dxAttr ? parseFloat(dxAttr) : 0;
|
||||||
|
const dy = dyAttr ? parseFloat(dyAttr) : 0;
|
||||||
|
|
||||||
removeBurgLabelRenderer(burg.i!);
|
removeBurgLabelRenderer(burg.i!);
|
||||||
|
|
||||||
|
// Add/update label in data layer
|
||||||
|
const existingLabel = Labels.getBurgLabel(burg.i!);
|
||||||
|
if (existingLabel) {
|
||||||
|
Labels.updateLabel(existingLabel.i, {
|
||||||
|
text: burg.name!,
|
||||||
|
x: burg.x,
|
||||||
|
y: burg.y,
|
||||||
|
dx,
|
||||||
|
dy,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Labels.addBurgLabel({
|
||||||
|
burgId: burg.i!,
|
||||||
|
group: burg.group || "unmarked",
|
||||||
|
text: burg.name!,
|
||||||
|
x: burg.x,
|
||||||
|
y: burg.y,
|
||||||
|
dx,
|
||||||
|
dy,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render to SVG
|
||||||
labelGroup
|
labelGroup
|
||||||
.append("text")
|
.append("text")
|
||||||
.attr("text-rendering", "optimizeSpeed")
|
.attr("text-rendering", "optimizeSpeed")
|
||||||
|
|
@ -71,6 +109,7 @@ const drawBurgLabelRenderer = (burg: Burg): void => {
|
||||||
const removeBurgLabelRenderer = (burgId: number): void => {
|
const removeBurgLabelRenderer = (burgId: number): void => {
|
||||||
const existingLabel = document.getElementById(`burgLabel${burgId}`);
|
const existingLabel = document.getElementById(`burgLabel${burgId}`);
|
||||||
if (existingLabel) existingLabel.remove();
|
if (existingLabel) existingLabel.remove();
|
||||||
|
Labels.removeBurgLabel(burgId);
|
||||||
};
|
};
|
||||||
|
|
||||||
function createLabelGroups(): void {
|
function createLabelGroups(): void {
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,50 @@
|
||||||
import { curveNatural, line, max, select } from "d3";
|
import { curveNatural, line, max, select } from "d3";
|
||||||
import {
|
import {
|
||||||
drawPath,
|
|
||||||
drawPoint,
|
|
||||||
findClosestCell,
|
findClosestCell,
|
||||||
minmax,
|
minmax,
|
||||||
rn,
|
rn,
|
||||||
round,
|
round,
|
||||||
splitInTwo,
|
splitInTwo,
|
||||||
} from "../utils";
|
} from "../utils";
|
||||||
|
import type { StateLabelData } from "../modules/labels";
|
||||||
import {
|
import {
|
||||||
Ray,
|
|
||||||
raycast,
|
raycast,
|
||||||
findBestRayPair,
|
findBestRayPair,
|
||||||
ANGLES
|
ANGLES,
|
||||||
} from "../utils/label-raycast";
|
} from "../utils/label-raycast";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
var drawStateLabels: (list?: number[]) => void;
|
var drawStateLabels: (list?: number[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type PathPoints = [number, number][];
|
/**
|
||||||
|
* Helper function to calculate offset width for raycast based on state size
|
||||||
|
*/
|
||||||
|
function getOffsetWidth(cellsNumber: number): number {
|
||||||
|
if (cellsNumber < 40) return 0;
|
||||||
|
if (cellsNumber < 200) return 5;
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
// list - an optional array of stateIds to regenerate
|
function checkExampleLetterLength(): number {
|
||||||
|
const textGroup = select<SVGGElement, unknown>("g#labels > g#states");
|
||||||
|
const testLabel = textGroup
|
||||||
|
.append("text")
|
||||||
|
.attr("x", 0)
|
||||||
|
.attr("y", 0)
|
||||||
|
.text("Example");
|
||||||
|
const letterLength =
|
||||||
|
(testLabel.node() as SVGTextElement).getComputedTextLength() / 7; // approximate length of 1 letter
|
||||||
|
testLabel.remove();
|
||||||
|
|
||||||
|
return letterLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render state labels from pack.labels data to SVG.
|
||||||
|
* Adjusts and fits labels based on layout constraints.
|
||||||
|
* list - optional array of stateIds to re-render
|
||||||
|
*/
|
||||||
const stateLabelsRenderer = (list?: number[]): void => {
|
const stateLabelsRenderer = (list?: number[]): void => {
|
||||||
TIME && console.time("drawStateLabels");
|
TIME && console.time("drawStateLabels");
|
||||||
|
|
||||||
|
|
@ -29,28 +52,41 @@ const stateLabelsRenderer = (list?: number[]): void => {
|
||||||
const layerDisplay = labels.style("display");
|
const layerDisplay = labels.style("display");
|
||||||
labels.style("display", null);
|
labels.style("display", null);
|
||||||
|
|
||||||
const { cells, states } = pack;
|
const { states } = pack;
|
||||||
const stateIds = cells.state;
|
|
||||||
|
// Get labels to render
|
||||||
|
const labelsToRender = list
|
||||||
|
? Labels.getAll()
|
||||||
|
.filter((l) => l.type === "state" && list.includes((l as StateLabelData).stateId))
|
||||||
|
.map((l) => l as StateLabelData)
|
||||||
|
: Labels.getByType("state").map((l) => l as StateLabelData);
|
||||||
|
|
||||||
const labelPaths = getLabelPaths();
|
|
||||||
const letterLength = checkExampleLetterLength();
|
const letterLength = checkExampleLetterLength();
|
||||||
drawLabelPath(letterLength);
|
drawLabelPath(letterLength, labelsToRender);
|
||||||
|
|
||||||
// restore labels visibility
|
// restore labels visibility
|
||||||
labels.style("display", layerDisplay);
|
labels.style("display", layerDisplay);
|
||||||
|
|
||||||
function getLabelPaths(): [number, PathPoints][] {
|
function drawLabelPath(letterLength: number, labelDataList: StateLabelData[]): void {
|
||||||
const labelPaths: [number, PathPoints][] = [];
|
const mode = options.stateLabelsMode || "auto";
|
||||||
|
const lineGen = line<[number, number]>().curve(curveNatural);
|
||||||
|
|
||||||
for (const state of states) {
|
const textGroup = select<SVGGElement, unknown>("g#labels > g#states");
|
||||||
if (!state.i || state.removed || state.lock) continue;
|
const pathGroup = select<SVGGElement, unknown>(
|
||||||
if (list && !list.includes(state.i)) continue;
|
"defs > g#deftemp > g#textPaths",
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const labelData of labelDataList) {
|
||||||
|
const state = states[labelData.stateId];
|
||||||
|
if (!state.i || state.removed)
|
||||||
|
throw new Error("State must not be neutral or removed");
|
||||||
|
|
||||||
|
// Calculate pathPoints using raycast algorithm (recalculated on each draw)
|
||||||
const offset = getOffsetWidth(state.cells!);
|
const offset = getOffsetWidth(state.cells!);
|
||||||
const maxLakeSize = state.cells! / 20;
|
const maxLakeSize = state.cells! / 20;
|
||||||
const [x0, y0] = state.pole!;
|
const [x0, y0] = state.pole!;
|
||||||
|
|
||||||
const rays: Ray[] = ANGLES.map(({ angle, dx, dy }) => {
|
const rays = ANGLES.map(({ angle, dx, dy }) => {
|
||||||
const { length, x, y } = raycast({
|
const { length, x, y } = raycast({
|
||||||
stateId: state.i,
|
stateId: state.i,
|
||||||
x0,
|
x0,
|
||||||
|
|
@ -64,61 +100,20 @@ const stateLabelsRenderer = (list?: number[]): void => {
|
||||||
});
|
});
|
||||||
const [ray1, ray2] = findBestRayPair(rays);
|
const [ray1, ray2] = findBestRayPair(rays);
|
||||||
|
|
||||||
const pathPoints: PathPoints = [
|
const pathPoints: [number, number][] = [
|
||||||
[ray1.x, ray1.y],
|
[ray1.x, ray1.y],
|
||||||
state.pole!,
|
state.pole!,
|
||||||
[ray2.x, ray2.y],
|
[ray2.x, ray2.y],
|
||||||
];
|
];
|
||||||
if (ray1.x > ray2.x) pathPoints.reverse();
|
if (ray1.x > ray2.x) pathPoints.reverse();
|
||||||
|
|
||||||
if (DEBUG.stateLabels) {
|
textGroup.select(`#stateLabel${labelData.stateId}`).remove();
|
||||||
drawPoint(state.pole!, { color: "black", radius: 1 });
|
pathGroup.select(`#textPath_stateLabel${labelData.stateId}`).remove();
|
||||||
drawPath(pathPoints, { color: "black", width: 0.2 });
|
|
||||||
}
|
|
||||||
|
|
||||||
labelPaths.push([state.i, pathPoints]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return labelPaths;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkExampleLetterLength(): number {
|
|
||||||
const textGroup = select<SVGGElement, unknown>("g#labels > g#states");
|
|
||||||
const testLabel = textGroup
|
|
||||||
.append("text")
|
|
||||||
.attr("x", 0)
|
|
||||||
.attr("y", 0)
|
|
||||||
.text("Example");
|
|
||||||
const letterLength =
|
|
||||||
(testLabel.node() as SVGTextElement).getComputedTextLength() / 7; // approximate length of 1 letter
|
|
||||||
testLabel.remove();
|
|
||||||
|
|
||||||
return letterLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawLabelPath(letterLength: number): void {
|
|
||||||
const mode = options.stateLabelsMode || "auto";
|
|
||||||
const lineGen = line<[number, number]>().curve(curveNatural);
|
|
||||||
|
|
||||||
const textGroup = select<SVGGElement, unknown>("g#labels > g#states");
|
|
||||||
const pathGroup = select<SVGGElement, unknown>(
|
|
||||||
"defs > g#deftemp > g#textPaths",
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const [stateId, pathPoints] of labelPaths) {
|
|
||||||
const state = states[stateId];
|
|
||||||
if (!state.i || state.removed)
|
|
||||||
throw new Error("State must not be neutral or removed");
|
|
||||||
if (pathPoints.length < 2)
|
|
||||||
throw new Error("Label path must have at least 2 points");
|
|
||||||
|
|
||||||
textGroup.select(`#stateLabel${stateId}`).remove();
|
|
||||||
pathGroup.select(`#textPath_stateLabel${stateId}`).remove();
|
|
||||||
|
|
||||||
const textPath = pathGroup
|
const textPath = pathGroup
|
||||||
.append("path")
|
.append("path")
|
||||||
.attr("d", round(lineGen(pathPoints) || ""))
|
.attr("d", round(lineGen(pathPoints) || ""))
|
||||||
.attr("id", `textPath_stateLabel${stateId}`);
|
.attr("id", `textPath_stateLabel${labelData.stateId}`);
|
||||||
|
|
||||||
const pathLength =
|
const pathLength =
|
||||||
(textPath.node() as SVGPathElement).getTotalLength() / letterLength; // path length in letters
|
(textPath.node() as SVGPathElement).getTotalLength() / letterLength; // path length in letters
|
||||||
|
|
@ -129,6 +124,9 @@ const stateLabelsRenderer = (list?: number[]): void => {
|
||||||
pathLength,
|
pathLength,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Update label data with font size
|
||||||
|
Labels.updateLabel(labelData.i, { fontSize: ratio });
|
||||||
|
|
||||||
// prolongate path if it's too short
|
// prolongate path if it's too short
|
||||||
const longestLineLength = max(lines.map((line) => line.length)) || 0;
|
const longestLineLength = max(lines.map((line) => line.length)) || 0;
|
||||||
if (pathLength && pathLength < longestLineLength) {
|
if (pathLength && pathLength < longestLineLength) {
|
||||||
|
|
@ -149,7 +147,7 @@ const stateLabelsRenderer = (list?: number[]): void => {
|
||||||
const textElement = textGroup
|
const textElement = textGroup
|
||||||
.append("text")
|
.append("text")
|
||||||
.attr("text-rendering", "optimizeSpeed")
|
.attr("text-rendering", "optimizeSpeed")
|
||||||
.attr("id", `stateLabel${stateId}`)
|
.attr("id", `stateLabel${labelData.stateId}`)
|
||||||
.append("textPath")
|
.append("textPath")
|
||||||
.attr("startOffset", "50%")
|
.attr("startOffset", "50%")
|
||||||
.attr("font-size", `${ratio}%`)
|
.attr("font-size", `${ratio}%`)
|
||||||
|
|
@ -163,12 +161,16 @@ const stateLabelsRenderer = (list?: number[]): void => {
|
||||||
textElement.insertAdjacentHTML("afterbegin", spans.join(""));
|
textElement.insertAdjacentHTML("afterbegin", spans.join(""));
|
||||||
|
|
||||||
const { width, height } = textElement.getBBox();
|
const { width, height } = textElement.getBBox();
|
||||||
textElement.setAttribute("href", `#textPath_stateLabel${stateId}`);
|
textElement.setAttribute("href", `#textPath_stateLabel${labelData.stateId}`);
|
||||||
|
|
||||||
|
const stateIds = pack.cells.state;
|
||||||
if (mode === "full" || lines.length === 1) continue;
|
if (mode === "full" || lines.length === 1) continue;
|
||||||
|
|
||||||
// check if label fits state boundaries. If no, replace it with short name
|
// check if label fits state boundaries. If no, replace it with short name
|
||||||
const [[x1, y1], [x2, y2]] = [pathPoints.at(0)!, pathPoints.at(-1)!];
|
const [[x1, y1], [x2, y2]] = [
|
||||||
|
pathPoints.at(0)!,
|
||||||
|
pathPoints.at(-1)!,
|
||||||
|
];
|
||||||
const angleRad = Math.atan2(y2 - y1, x2 - x1);
|
const angleRad = Math.atan2(y2 - y1, x2 - x1);
|
||||||
|
|
||||||
const isInsideState = checkIfInsideState(
|
const isInsideState = checkIfInsideState(
|
||||||
|
|
@ -177,7 +179,7 @@ const stateLabelsRenderer = (list?: number[]): void => {
|
||||||
width / 2,
|
width / 2,
|
||||||
height / 2,
|
height / 2,
|
||||||
stateIds,
|
stateIds,
|
||||||
stateId,
|
labelData.stateId,
|
||||||
);
|
);
|
||||||
if (isInsideState) continue;
|
if (isInsideState) continue;
|
||||||
|
|
||||||
|
|
@ -187,6 +189,7 @@ const stateLabelsRenderer = (list?: number[]): void => {
|
||||||
? state.fullName!
|
? state.fullName!
|
||||||
: state.name!;
|
: state.name!;
|
||||||
textElement.innerHTML = `<tspan x="0">${text}</tspan>`;
|
textElement.innerHTML = `<tspan x="0">${text}</tspan>`;
|
||||||
|
Labels.updateLabel(labelData.i, { text });
|
||||||
|
|
||||||
const correctedRatio = minmax(
|
const correctedRatio = minmax(
|
||||||
rn((pathLength / text.length) * 50),
|
rn((pathLength / text.length) * 50),
|
||||||
|
|
@ -194,15 +197,10 @@ const stateLabelsRenderer = (list?: number[]): void => {
|
||||||
130,
|
130,
|
||||||
);
|
);
|
||||||
textElement.setAttribute("font-size", `${correctedRatio}%`);
|
textElement.setAttribute("font-size", `${correctedRatio}%`);
|
||||||
|
Labels.updateLabel(labelData.i, { fontSize: correctedRatio });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOffsetWidth(cellsNumber: number): number {
|
|
||||||
if (cellsNumber < 40) return 0;
|
|
||||||
if (cellsNumber < 200) return 5;
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLinesAndRatio(
|
function getLinesAndRatio(
|
||||||
mode: string,
|
mode: string,
|
||||||
name: string,
|
name: string,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue