Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/(studio)/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ export interface IndividualLabelOverride {
id: string; // Unique identifier: "symbol-{index}" or "choropleth-{featureId}"
x?: number; // Override x position (SVG coordinates)
y?: number; // Override y position (SVG coordinates)
offsetX?: number; // Per-label x offset in pixels
offsetY?: number; // Per-label y offset in pixels
fontFamily?: string;
fontStyle?: 'normal' | 'italic';
fontWeight?: 'normal' | 'bold';
Expand Down
35 changes: 35 additions & 0 deletions components/label-editor-toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ export const LabelEditorToolbar: React.FC<LabelEditorToolbarProps> = ({
};

const alignment = getAlignmentFromOverride();
const offsetX = currentOverride.offsetX ?? 0;
const offsetY = currentOverride.offsetY ?? 0;

const updateOverride = (updates: Partial<IndividualLabelOverride>) => {
const currentOverrides = stylingSettings.individualLabelOverrides || {};
Expand Down Expand Up @@ -437,6 +439,39 @@ export const LabelEditorToolbar: React.FC<LabelEditorToolbarProps> = ({
</div>
</div>
)}

<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="label-offset-x" className="text-sm">
X offset ({offsetX}px)
</Label>
<Slider
id="label-offset-x"
value={[offsetX]}
onValueChange={(value) =>
updateOverride({ offsetX: value[0], x: undefined, y: undefined })
}
min={-50}
max={50}
step={1}
/>
</div>
<div className="space-y-2">
<Label htmlFor="label-offset-y" className="text-sm">
Y offset ({offsetY}px)
</Label>
<Slider
id="label-offset-y"
value={[offsetY]}
onValueChange={(value) =>
updateOverride({ offsetY: value[0], x: undefined, y: undefined })
}
min={-50}
max={50}
step={1}
/>
</div>
</div>
</CardContent>
</Card>
);
Expand Down
28 changes: 20 additions & 8 deletions modules/map-preview/labels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,10 +277,16 @@ export const renderSymbolLabels = ({
});

// Apply position override if exists, otherwise use calculated position
const offsetX = stylingSettings.symbol.labelOffsetX ?? 0;
const offsetY = stylingSettings.symbol.labelOffsetY ?? 0;
const finalX = hasPositionOverride ? override!.x! : projected[0] + position.dx + offsetX;
const finalY = hasPositionOverride ? override!.y! : projected[1] + position.dy + offsetY;
const globalOffsetX = stylingSettings.symbol.labelOffsetX ?? 0;
const globalOffsetY = stylingSettings.symbol.labelOffsetY ?? 0;
const individualOffsetX = override?.offsetX ?? 0;
const individualOffsetY = override?.offsetY ?? 0;
const finalX = hasPositionOverride
? override!.x!
: projected[0] + position.dx + globalOffsetX + individualOffsetX;
const finalY = hasPositionOverride
? override!.y!
: projected[1] + position.dy + globalOffsetY + individualOffsetY;

// Use override textAnchor/dominantBaseline if provided, otherwise use calculated position
const finalTextAnchor = textAnchor ?? position.anchor;
Expand Down Expand Up @@ -513,10 +519,16 @@ export const renderChoroplethLabels = ({
};

// Apply position override if exists, otherwise use centroid
const offsetX = stylingSettings.choropleth.labelOffsetX ?? 0;
const offsetY = stylingSettings.choropleth.labelOffsetY ?? 0;
const finalX = hasPositionOverride ? override!.x! : centroid[0] + offsetX;
const finalY = hasPositionOverride ? override!.y! : centroid[1] + offsetY;
const globalOffsetX = stylingSettings.choropleth.labelOffsetX ?? 0;
const globalOffsetY = stylingSettings.choropleth.labelOffsetY ?? 0;
const individualOffsetX = override?.offsetX ?? 0;
const individualOffsetY = override?.offsetY ?? 0;
const finalX = hasPositionOverride
? override!.x!
: centroid[0] + globalOffsetX + individualOffsetX;
const finalY = hasPositionOverride
? override!.y!
: centroid[1] + globalOffsetY + individualOffsetY;

textElement
.attr('x', finalX)
Expand Down
Loading