feat: add RotationSignal for reactive marker rotation (#14)
All checks were successful
CI / Build and Test (push) Successful in 37s

This commit was merged in pull request #14.
This commit is contained in:
2026-02-20 21:16:40 +00:00
parent 297808d4cc
commit ae32da77df
4 changed files with 37 additions and 16 deletions

View File

@@ -195,7 +195,9 @@ func markerBodyJS(mapID, markerID string, mk Marker) string {
if mk.Anchor != "" {
opts += fmt.Sprintf(`anchor:%s,`, jsonStr(mk.Anchor))
}
if mk.Rotation != 0 {
if mk.RotationSignal != nil {
opts += fmt.Sprintf(`rotation:%s,`, mk.RotationSignal.String())
} else if mk.Rotation != 0 {
opts += fmt.Sprintf(`rotation:%s,`, formatFloat(mk.Rotation))
}
if mk.Draggable {
@@ -250,14 +252,21 @@ func dragendHandlerJS(mapID, markerID string, mk Marker) string {
func markerEffectExpr(mapID, markerID string, mk Marker) string {
// Read signals before the guard so Datastar tracks them as dependencies
// even when the map/marker hasn't loaded yet on first evaluation.
return fmt.Sprintf(
`var lng=$%s,lat=$%s;`+
`var m=window.__via_maps&&window.__via_maps[%s];`+
`if(m&&m._via_markers[%s]){`+
`m._via_markers[%s].setLngLat([lng,lat])}`,
mk.LngSignal.ID(), mk.LatSignal.ID(),
jsonStr(mapID), jsonStr(markerID), jsonStr(markerID),
)
var b strings.Builder
b.WriteString(fmt.Sprintf(`var lng=$%s,lat=$%s;`, mk.LngSignal.ID(), mk.LatSignal.ID()))
if mk.RotationSignal != nil {
b.WriteString(fmt.Sprintf(`var rot=$%s;`, mk.RotationSignal.ID()))
}
b.WriteString(fmt.Sprintf(
`var m=window.__via_maps&&window.__via_maps[%s];`+
`if(m&&m._via_markers[%[2]s]){`+
`m._via_markers[%[2]s].setLngLat([lng,lat])`,
jsonStr(mapID), jsonStr(markerID)))
if mk.RotationSignal != nil {
b.WriteString(fmt.Sprintf(`;m._via_markers[%s].setRotation(rot)`, jsonStr(markerID)))
}
b.WriteString(`}`)
return b.String()
}
// addMarkerJS generates a self-contained IIFE to add a marker post-render.

View File

@@ -122,13 +122,18 @@ func (m *Map) Element(extra ...h.H) h.H {
}
}
// Hidden inputs for signal-backed marker position writeback (drag → signal)
// Hidden inputs for signal-backed marker position/rotation writeback
for _, me := range m.markers {
if me.marker.LngSignal != nil && me.marker.LatSignal != nil {
children = append(children,
h.Input(h.Type("hidden"), me.marker.LngSignal.Bind()),
h.Input(h.Type("hidden"), me.marker.LatSignal.Bind()),
)
if me.marker.RotationSignal != nil {
children = append(children,
h.Input(h.Type("hidden"), me.marker.RotationSignal.Bind()),
)
}
}
}

View File

@@ -313,6 +313,7 @@ type Marker struct {
Anchor string
// Rotation is clockwise degrees. Useful for directional icons (ships, vehicles).
// Ignored when RotationSignal is set.
Rotation float64
// Signal-backed position. When set, signals drive marker position reactively.
@@ -320,6 +321,9 @@ type Marker struct {
// If Draggable is true, drag updates write back to these signals.
LngSignal *via.Signal
LatSignal *via.Signal
// RotationSignal drives marker rotation reactively. When set, Rotation is ignored.
RotationSignal *via.Signal
}
// Popup describes a map popup.