Fix svg export

This commit is contained in:
Alexander Nozik 2023-09-10 21:13:54 +03:00
parent 75b5a69a27
commit aebf4af24f
5 changed files with 43 additions and 35 deletions

View File

@ -77,9 +77,12 @@ fun App() {
icon(pointOne, Icons.Filled.Home) icon(pointOne, Icons.Filled.Home)
val marker1 = rectangle(55.744 to 38.614, size = DpSize(10.dp, 10.dp)).color(Color.Magenta) val marker1 = rectangle(55.744 to 38.614, size = DpSize(10.dp, 10.dp))
val marker2 = rectangle(55.8 to 38.5, size = DpSize(10.dp, 10.dp)).color(Color.Magenta) .color(Color.Magenta)
val marker3 = rectangle(56.0 to 38.5, size = DpSize(10.dp, 10.dp)).color(Color.Magenta) val marker2 = rectangle(55.8 to 38.5, size = DpSize(10.dp, 10.dp))
.color(Color.Magenta)
val marker3 = rectangle(56.0 to 38.5, size = DpSize(10.dp, 10.dp))
.color(Color.Magenta)
draggableLine(marker1, marker2, id = "line 1").color(Color.Red).onClick { draggableLine(marker1, marker2, id = "line 1").color(Color.Red).onClick {
println("line 1 clicked") println("line 1 clicked")
@ -103,13 +106,13 @@ fun App() {
), ),
) )
points( // points(
points = listOf( // points = listOf(
55.744 to 38.614, // 55.744 to 38.614,
55.8 to 38.5, // 55.8 to 38.5,
56.0 to 38.5, // 56.0 to 38.5,
) // )
).pointSize(5f) // ).pointSize(5f)
// geodeticLine(Gmc.ofDegrees(40.7128, -74.0060), Gmc.ofDegrees(55.742465, 37.615812)).color(Color.Blue) // geodeticLine(Gmc.ofDegrees(40.7128, -74.0060), Gmc.ofDegrees(55.742465, 37.615812)).color(Color.Blue)
// line(Gmc.ofDegrees(40.7128, -74.0060), Gmc.ofDegrees(55.742465, 37.615812)) // line(Gmc.ofDegrees(40.7128, -74.0060), Gmc.ofDegrees(55.742465, 37.615812))

View File

@ -6,9 +6,6 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.drawscope.clipRect import androidx.compose.ui.graphics.drawscope.clipRect
import androidx.compose.ui.graphics.toComposeImageBitmap import androidx.compose.ui.graphics.toComposeImageBitmap
import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntOffset
@ -72,7 +69,7 @@ public fun MapView(
mapTiles[tile.id] = tile.image mapTiles[tile.id] = tile.image
} catch (ex: Exception) { } catch (ex: Exception) {
//displaying the error is maps responsibility //displaying the error is maps responsibility
if(ex !is CancellationException) { if (ex !is CancellationException) {
logger.error(ex) { "Failed to load tile with id=$id" } logger.error(ex) { "Failed to load tile with id=$id" }
} }
} }
@ -147,5 +144,6 @@ public fun MapView(
buildFeatures: FeatureGroup<Gmc>.() -> Unit = {}, buildFeatures: FeatureGroup<Gmc>.() -> Unit = {},
) { ) {
val featureState = FeatureGroup.remember(WebMercatorSpace, buildFeatures) val featureState = FeatureGroup.remember(WebMercatorSpace, buildFeatures)
MapView(mapTileProvider, config, featureState, initialViewPoint, initialRectangle, modifier) val computedRectangle = initialRectangle ?: featureState.getBoundingBox()
MapView(mapTileProvider, config, featureState, initialViewPoint, computedRectangle, modifier)
} }

View File

@ -29,7 +29,7 @@ public abstract class FeatureDrawScope<T : Any>(
toCoordinates(this@toCoordinates, this@FeatureDrawScope) toCoordinates(this@toCoordinates, this@FeatureDrawScope)
} }
public fun T.toOffset(): Offset = with(state) { public open fun T.toOffset(): Offset = with(state) {
toOffset(this@toOffset, this@FeatureDrawScope) toOffset(this@toOffset, this@FeatureDrawScope)
} }
@ -53,12 +53,17 @@ public class ComposeFeatureDrawScope<T : Any>(
override fun drawText(text: String, position: Offset, attributes: Attributes) { override fun drawText(text: String, position: Offset, attributes: Attributes) {
try { try {
drawText(textMeasurer, text, position) drawText(textMeasurer, text, position)
} catch (ex: Exception){ } catch (ex: Exception) {
KotlinLogging.logger("features").error(ex){"Failed to measure text"} logger.error(ex) { "Failed to measure text" }
} }
} }
override fun painterFor(feature: PainterFeature<T>): Painter = painterCache[feature] ?: error("Can't resolve painter for $feature") override fun painterFor(feature: PainterFeature<T>): Painter =
painterCache[feature] ?: error("Can't resolve painter for $feature")
public companion object{
private val logger = KotlinLogging.logger("ComposeFeatureDrawScope")
}
} }
@ -82,7 +87,7 @@ public fun <T : Any> FeatureCanvas(
if (state.canvasSize != size.toDpSize()) { if (state.canvasSize != size.toDpSize()) {
state.canvasSize = size.toDpSize() state.canvasSize = size.toDpSize()
} }
ComposeFeatureDrawScope(this, state, painterCache, textMeasurer).apply(draw).apply{ ComposeFeatureDrawScope(this, state, painterCache, textMeasurer).apply(draw).apply {
clipRect { clipRect {
features.featureMap.values.sortedBy { it.z } features.featureMap.values.sortedBy { it.z }
.filter { state.viewPoint.zoom in it.zoomRange } .filter { state.viewPoint.zoom in it.zoomRange }

View File

@ -21,9 +21,8 @@ import java.awt.Color as AWTColor
public class SvgDrawScope( public class SvgDrawScope(
state: CanvasState<XY>, state: CanvasState<XY>,
private val graphics: SVGGraphics2D, private val graphics: SVGGraphics2D,
size: Size,
private val painterCache: Map<PainterFeature<XY>, Painter>, private val painterCache: Map<PainterFeature<XY>, Painter>,
private val defaultStrokeWidth: Float = 1f private val defaultStrokeWidth: Float = 1f,
) : FeatureDrawScope<XY>(state) { ) : FeatureDrawScope<XY>(state) {
override val layoutDirection: LayoutDirection override val layoutDirection: LayoutDirection
@ -467,7 +466,7 @@ public class SvgDrawScope(
public fun renderText( public fun renderText(
textFeature: TextFeature<XY>, textFeature: TextFeature<XY>,
) { ) {
textFeature.color?.let { setupColor(it)} textFeature.color?.let { setupColor(it) }
graphics.drawString(textFeature.text, textFeature.position.x, textFeature.position.y) graphics.drawString(textFeature.text, textFeature.position.x, textFeature.position.y)
} }
@ -476,10 +475,10 @@ public class SvgDrawScope(
} }
override fun drawText(text: String, position: Offset, attributes: Attributes) { override fun drawText(text: String, position: Offset, attributes: Attributes) {
attributes[ColorAttribute]?.let { setupColor(it)} attributes[ColorAttribute]?.let { setupColor(it) }
graphics.drawString(text, position.x, position.y) graphics.drawString(text, position.x, position.y)
} }
override val drawContext: DrawContext = SvgDrawContext(graphics, size) override val drawContext: DrawContext = SvgDrawContext(graphics, state.canvasSize.toSize())
} }

View File

@ -3,6 +3,8 @@ package center.sciprog.maps.svg
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.geometry.Size import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import center.sciprog.maps.features.* import center.sciprog.maps.features.*
import center.sciprog.maps.scheme.XY import center.sciprog.maps.scheme.XY
import center.sciprog.maps.scheme.XYCanvasState import center.sciprog.maps.scheme.XYCanvasState
@ -154,14 +156,17 @@ public fun FeatureStateSnapshot<XY>.generateSvg(
// } // }
val svgGraphics2D: SVGGraphics2D = SVGGraphics2D(width, height) val svgGraphics2D: SVGGraphics2D = SVGGraphics2D(width, height)
val svgCanvasState: XYCanvasState = XYCanvasState(ViewConfig()) val svgCanvasState: XYCanvasState = XYCanvasState(ViewConfig()).apply {
val svgScope = SvgDrawScope(svgCanvasState, svgGraphics2D, Size(width.toFloat(), height.toFloat()), painterCache) this.viewPoint = viewPoint
this.canvasSize = DpSize(width.dp, height.dp)
}
val svgScope = SvgDrawScope(svgCanvasState, svgGraphics2D, painterCache)
svgScope.apply { svgScope.apply {
features.values.filter { features.values.sortedBy { it.z }
viewPoint.zoom in it.zoomRange .filter { state.viewPoint.zoom in it.zoomRange }
}.forEach { feature -> .forEach { feature ->
drawFeature(feature) this@apply.drawFeature(feature)
} }
} }
return svgGraphics2D.getSVGElement(id) return svgGraphics2D.getSVGElement(id)
@ -173,8 +178,6 @@ public fun FeatureStateSnapshot<XY>.exportToSvg(
height: Double, height: Double,
path: java.nio.file.Path, path: java.nio.file.Path,
) { ) {
val svgString: String = generateSvg(viewPoint, width, height)
val svgString = generateSvg(viewPoint, width, height)
SVGUtils.writeToSVG(path.toFile(), svgString) SVGUtils.writeToSVG(path.toFile(), svgString)
} }