Fix SVG rendering for scheme
This commit is contained in:
parent
77e27c7eb6
commit
737bbbde6a
@ -10,7 +10,7 @@ val ktorVersion by extra("2.0.3")
|
||||
|
||||
allprojects {
|
||||
group = "center.sciprog"
|
||||
version = "0.1.0-dev-11"
|
||||
version = "0.1.0-dev-12"
|
||||
}
|
||||
|
||||
ksciencePublish{
|
||||
|
@ -172,7 +172,12 @@ public fun SchemeView(
|
||||
center = feature.center.toOffset()
|
||||
)
|
||||
|
||||
is SchemeLineFeature -> drawLine(feature.color, feature.a.toOffset(), feature.b.toOffset())
|
||||
is SchemeLineFeature -> drawLine(
|
||||
feature.color,
|
||||
feature.a.toOffset(),
|
||||
feature.b.toOffset(),
|
||||
)
|
||||
|
||||
is SchemeArcFeature -> {
|
||||
val topLeft = feature.oval.leftTop.toOffset()
|
||||
val bottomRight = feature.oval.rightBottom.toOffset()
|
||||
|
@ -9,10 +9,14 @@ import androidx.compose.ui.graphics.drawscope.DrawContext
|
||||
import androidx.compose.ui.graphics.drawscope.DrawTransform
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import org.jfree.svg.SVGGraphics2D
|
||||
import java.awt.BasicStroke
|
||||
import java.awt.Graphics2D
|
||||
import java.awt.geom.Arc2D
|
||||
|
||||
internal fun Paint.toAwt(): java.awt.Paint {
|
||||
return java.awt.Color(color.toArgb())
|
||||
internal fun Graphics2D.setupPaint(p: Paint){
|
||||
paint = java.awt.Color(p.color.toArgb())
|
||||
stroke = BasicStroke(p.strokeWidth)
|
||||
}
|
||||
|
||||
|
||||
@ -73,7 +77,7 @@ internal fun DrawContext.asDrawTransform(): DrawTransform = object : DrawTransfo
|
||||
}
|
||||
}
|
||||
|
||||
internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
|
||||
internal class SvgCanvas(val graphics: SVGGraphics2D) : Canvas {
|
||||
override fun clipPath(path: Path, clipOp: ClipOp) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
@ -112,19 +116,15 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
|
||||
useCenter: Boolean,
|
||||
paint: Paint,
|
||||
) {
|
||||
graphics.paint = paint.toAwt()
|
||||
graphics.drawArc(
|
||||
top.toInt(),
|
||||
left.toInt(),
|
||||
(right - left).toInt(),
|
||||
(top - bottom).toInt(),
|
||||
startAngle.toInt(),
|
||||
sweepAngle.toInt()
|
||||
graphics.setupPaint(paint)
|
||||
val arc = Arc2D.Float(
|
||||
left, top, (right - left), (top - bottom), -startAngle, -sweepAngle, Arc2D.OPEN
|
||||
)
|
||||
graphics.draw(arc)
|
||||
}
|
||||
|
||||
override fun drawCircle(center: Offset, radius: Float, paint: Paint) {
|
||||
graphics.paint = paint.toAwt()
|
||||
graphics.setupPaint(paint)
|
||||
graphics.drawOval(
|
||||
(center.x - radius).toInt(),
|
||||
(center.y - radius).toInt(),
|
||||
@ -134,7 +134,7 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
|
||||
}
|
||||
|
||||
override fun drawImage(image: ImageBitmap, topLeftOffset: Offset, paint: Paint) {
|
||||
graphics.paint = paint.toAwt()
|
||||
graphics.setupPaint(paint)
|
||||
graphics.drawImage(image.toAwtImage(), null, topLeftOffset.x.toInt(), topLeftOffset.y.toInt())
|
||||
}
|
||||
|
||||
@ -150,12 +150,12 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
|
||||
}
|
||||
|
||||
override fun drawLine(p1: Offset, p2: Offset, paint: Paint) {
|
||||
graphics.paint = paint.toAwt()
|
||||
graphics.setupPaint(paint)
|
||||
graphics.drawLine(p1.x.toInt(), p1.y.toInt(), p2.x.toInt(), p2.y.toInt())
|
||||
}
|
||||
|
||||
override fun drawOval(left: Float, top: Float, right: Float, bottom: Float, paint: Paint) {
|
||||
graphics.paint = paint.toAwt()
|
||||
graphics.setupPaint(paint)
|
||||
graphics.drawOval(
|
||||
left.toInt(),
|
||||
top.toInt(),
|
||||
@ -165,13 +165,14 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
|
||||
}
|
||||
|
||||
override fun drawPath(path: Path, paint: Paint) {
|
||||
graphics.setupPaint(paint)
|
||||
val skiaPath = path.asSkiaPath()
|
||||
val points: List<Offset> = skiaPath.points.mapNotNull { it?.let { Offset(it.x, it.y) } }
|
||||
drawPoints(PointMode.Lines, points, paint)
|
||||
}
|
||||
|
||||
override fun drawPoints(pointMode: PointMode, points: List<Offset>, paint: Paint) {
|
||||
graphics.paint = paint.toAwt()
|
||||
graphics.setupPaint(paint)
|
||||
val xs = IntArray(points.size) { points[it].x.toInt() }
|
||||
val ys = IntArray(points.size) { points[it].y.toInt() }
|
||||
when (pointMode) {
|
||||
@ -218,7 +219,7 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
|
||||
}
|
||||
|
||||
override fun drawRect(left: Float, top: Float, right: Float, bottom: Float, paint: Paint) {
|
||||
graphics.paint = paint.toAwt()
|
||||
graphics.setupPaint(paint)
|
||||
graphics.drawRect(
|
||||
left.toInt(),
|
||||
top.toInt(),
|
||||
@ -236,7 +237,7 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
|
||||
radiusY: Float,
|
||||
paint: Paint,
|
||||
) {
|
||||
graphics.paint = paint.toAwt()
|
||||
graphics.setupPaint(paint)
|
||||
graphics.drawRoundRect(
|
||||
left.toInt(),
|
||||
top.toInt(),
|
||||
@ -285,7 +286,7 @@ internal class SvgCanvas(val graphics: Graphics2D) : Canvas {
|
||||
}
|
||||
}
|
||||
|
||||
internal class SvgDrawContext(val graphics: Graphics2D, override var size: Size) : DrawContext {
|
||||
internal class SvgDrawContext(val graphics: SVGGraphics2D, override var size: Size) : DrawContext {
|
||||
override val canvas: Canvas = SvgCanvas(graphics)
|
||||
|
||||
override val transform: DrawTransform = asDrawTransform()
|
||||
|
@ -8,17 +8,19 @@ import androidx.compose.ui.graphics.drawscope.*
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import org.jfree.svg.SVGGraphics2D
|
||||
import java.awt.BasicStroke
|
||||
import java.awt.Font
|
||||
import java.awt.Graphics2D
|
||||
import java.awt.geom.AffineTransform
|
||||
import java.awt.geom.Arc2D
|
||||
import java.awt.image.AffineTransformOp
|
||||
import java.awt.Color as AWTColor
|
||||
|
||||
private fun Color.toAWT(): java.awt.Color = AWTColor(toArgb())
|
||||
private fun Brush.toAWT(): java.awt.Paint = TODO()
|
||||
|
||||
public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawScope {
|
||||
public class SvgDrawScope(
|
||||
private val graphics: SVGGraphics2D,
|
||||
size: Size,
|
||||
val defaultStrokeWidth: Float = 1f,
|
||||
) : DrawScope {
|
||||
|
||||
override val layoutDirection: LayoutDirection
|
||||
get() = LayoutDirection.Ltr
|
||||
@ -27,6 +29,42 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
|
||||
override val fontScale: Float get() = 1f
|
||||
|
||||
private fun setupStroke(strokeWidth: Float, cap: StrokeCap, join: StrokeJoin = StrokeJoin.Miter) {
|
||||
val width = if (strokeWidth == 0f) defaultStrokeWidth else strokeWidth
|
||||
val capValue = when (cap) {
|
||||
StrokeCap.Butt -> BasicStroke.CAP_BUTT
|
||||
StrokeCap.Round -> BasicStroke.CAP_ROUND
|
||||
StrokeCap.Square -> BasicStroke.CAP_SQUARE
|
||||
else -> BasicStroke.CAP_SQUARE
|
||||
}
|
||||
val joinValue = when (join) {
|
||||
StrokeJoin.Bevel -> BasicStroke.JOIN_BEVEL
|
||||
StrokeJoin.Miter -> BasicStroke.JOIN_MITER
|
||||
StrokeJoin.Round -> BasicStroke.JOIN_ROUND
|
||||
else -> BasicStroke.JOIN_MITER
|
||||
}
|
||||
graphics.stroke = BasicStroke(width, capValue, joinValue)
|
||||
}
|
||||
|
||||
private fun setupStroke(stroke: Stroke) {
|
||||
setupStroke(stroke.width, stroke.cap, stroke.join)
|
||||
}
|
||||
|
||||
private fun setupColor(color: Color) {
|
||||
graphics.paint = AWTColor(color.toArgb(), false)
|
||||
}
|
||||
|
||||
private fun setupColor(brush: Brush) {
|
||||
when (brush) {
|
||||
is SolidColor -> {
|
||||
graphics.paint = AWTColor(brush.value.toArgb(), false)
|
||||
}
|
||||
|
||||
is ShaderBrush -> TODO()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun drawArc(
|
||||
brush: Brush,
|
||||
startAngle: Float,
|
||||
@ -39,7 +77,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = brush.toAWT()
|
||||
setupColor(brush)
|
||||
when (style) {
|
||||
Fill -> graphics.fillArc(
|
||||
topLeft.x.toInt(),
|
||||
@ -50,14 +88,17 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
sweepAngle.toInt()
|
||||
)
|
||||
|
||||
is Stroke -> graphics.drawArc(
|
||||
topLeft.x.toInt(),
|
||||
topLeft.y.toInt(),
|
||||
size.width.toInt(),
|
||||
size.height.toInt(),
|
||||
startAngle.toInt(),
|
||||
sweepAngle.toInt()
|
||||
)
|
||||
is Stroke -> {
|
||||
setupStroke(style)
|
||||
graphics.drawArc(
|
||||
topLeft.x.toInt(),
|
||||
topLeft.y.toInt(),
|
||||
size.width.toInt(),
|
||||
size.height.toInt(),
|
||||
startAngle.toInt(),
|
||||
sweepAngle.toInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,25 +114,24 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = color.toAWT()
|
||||
setupColor(color)
|
||||
when (style) {
|
||||
Fill -> graphics.fillArc(
|
||||
topLeft.x.toInt(),
|
||||
topLeft.y.toInt(),
|
||||
size.width.toInt(),
|
||||
size.height.toInt(),
|
||||
startAngle.toInt(),
|
||||
sweepAngle.toInt()
|
||||
-startAngle.toInt(),
|
||||
-sweepAngle.toInt()
|
||||
)
|
||||
|
||||
is Stroke -> graphics.drawArc(
|
||||
topLeft.x.toInt(),
|
||||
topLeft.y.toInt(),
|
||||
size.width.toInt(),
|
||||
size.height.toInt(),
|
||||
startAngle.toInt(),
|
||||
sweepAngle.toInt()
|
||||
)
|
||||
is Stroke -> {
|
||||
setupStroke(style)
|
||||
val arc = Arc2D.Float(
|
||||
topLeft.x, topLeft.y, size.width, size.height, -startAngle, -sweepAngle, Arc2D.OPEN
|
||||
)
|
||||
graphics.draw(arc)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -105,7 +145,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = brush.toAWT()
|
||||
setupColor(brush)
|
||||
when (style) {
|
||||
Fill -> graphics.fillOval(
|
||||
(center.x - radius).toInt(),
|
||||
@ -114,12 +154,15 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
(radius * 2).toInt()
|
||||
)
|
||||
|
||||
is Stroke -> graphics.drawOval(
|
||||
(center.x - radius).toInt(),
|
||||
(center.y - radius).toInt(),
|
||||
(radius * 2).toInt(),
|
||||
(radius * 2).toInt()
|
||||
)
|
||||
is Stroke -> {
|
||||
setupStroke(style)
|
||||
graphics.drawOval(
|
||||
(center.x - radius).toInt(),
|
||||
(center.y - radius).toInt(),
|
||||
(radius * 2).toInt(),
|
||||
(radius * 2).toInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -133,7 +176,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = color.toAWT()
|
||||
setupColor(color)
|
||||
when (style) {
|
||||
Fill -> graphics.fillOval(
|
||||
(center.x - radius).toInt(),
|
||||
@ -142,12 +185,15 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
(radius * 2).toInt()
|
||||
)
|
||||
|
||||
is Stroke -> graphics.drawOval(
|
||||
(center.x - radius).toInt(),
|
||||
(center.y - radius).toInt(),
|
||||
(radius * 2).toInt(),
|
||||
(radius * 2).toInt()
|
||||
)
|
||||
is Stroke -> {
|
||||
setupStroke(style)
|
||||
graphics.drawOval(
|
||||
(center.x - radius).toInt(),
|
||||
(center.y - radius).toInt(),
|
||||
(radius * 2).toInt(),
|
||||
(radius * 2).toInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,8 +260,8 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = brush.toAWT()
|
||||
graphics.stroke = BasicStroke(strokeWidth)
|
||||
setupColor(brush)
|
||||
setupStroke(strokeWidth, cap)
|
||||
graphics.drawLine(start.x.toInt(), start.y.toInt(), end.x.toInt(), end.y.toInt())
|
||||
}
|
||||
|
||||
@ -230,8 +276,8 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = color.toAWT()
|
||||
graphics.stroke = BasicStroke(strokeWidth)
|
||||
setupColor(color)
|
||||
setupStroke(strokeWidth, cap)
|
||||
graphics.drawLine(start.x.toInt(), start.y.toInt(), end.x.toInt(), end.y.toInt())
|
||||
}
|
||||
|
||||
@ -244,7 +290,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = brush.toAWT()
|
||||
setupColor(brush)
|
||||
when (style) {
|
||||
Fill -> graphics.fillOval(topLeft.x.toInt(), topLeft.y.toInt(), size.width.toInt(), size.height.toInt())
|
||||
is Stroke -> graphics.drawOval(
|
||||
@ -265,7 +311,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = color.toAWT()
|
||||
setupColor(color)
|
||||
when (style) {
|
||||
Fill -> graphics.fillOval(topLeft.x.toInt(), topLeft.y.toInt(), size.width.toInt(), size.height.toInt())
|
||||
is Stroke -> graphics.drawOval(
|
||||
@ -314,7 +360,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = brush.toAWT()
|
||||
setupColor(brush)
|
||||
graphics.stroke = BasicStroke(strokeWidth)
|
||||
val xs = IntArray(points.size) { points[it].x.toInt() }
|
||||
val ys = IntArray(points.size) { points[it].y.toInt() }
|
||||
@ -332,7 +378,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = color.toAWT()
|
||||
setupColor(color)
|
||||
graphics.stroke = BasicStroke(strokeWidth)
|
||||
val xs = IntArray(points.size) { points[it].x.toInt() }
|
||||
val ys = IntArray(points.size) { points[it].y.toInt() }
|
||||
@ -348,15 +394,18 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = brush.toAWT()
|
||||
setupColor(brush)
|
||||
when (style) {
|
||||
Fill -> graphics.fillRect(topLeft.x.toInt(), topLeft.y.toInt(), size.width.toInt(), size.height.toInt())
|
||||
is Stroke -> graphics.drawRect(
|
||||
topLeft.x.toInt(),
|
||||
topLeft.y.toInt(),
|
||||
size.width.toInt(),
|
||||
size.height.toInt()
|
||||
)
|
||||
is Stroke -> {
|
||||
setupStroke(style)
|
||||
graphics.drawRect(
|
||||
topLeft.x.toInt(),
|
||||
topLeft.y.toInt(),
|
||||
size.width.toInt(),
|
||||
size.height.toInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -370,15 +419,18 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = color.toAWT()
|
||||
setupColor(color)
|
||||
when (style) {
|
||||
Fill -> graphics.fillRect(topLeft.x.toInt(), topLeft.y.toInt(), size.width.toInt(), size.height.toInt())
|
||||
is Stroke -> graphics.drawRect(
|
||||
topLeft.x.toInt(),
|
||||
topLeft.y.toInt(),
|
||||
size.width.toInt(),
|
||||
size.height.toInt()
|
||||
)
|
||||
is Stroke -> {
|
||||
setupStroke(style)
|
||||
graphics.drawRect(
|
||||
topLeft.x.toInt(),
|
||||
topLeft.y.toInt(),
|
||||
size.width.toInt(),
|
||||
size.height.toInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,7 +444,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = brush.toAWT()
|
||||
setupColor(brush)
|
||||
when (style) {
|
||||
Fill -> graphics.fillRoundRect(
|
||||
topLeft.x.toInt(),
|
||||
@ -403,14 +455,17 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
cornerRadius.y.toInt()
|
||||
)
|
||||
|
||||
is Stroke -> graphics.drawRoundRect(
|
||||
topLeft.x.toInt(),
|
||||
topLeft.y.toInt(),
|
||||
size.width.toInt(),
|
||||
size.height.toInt(),
|
||||
cornerRadius.x.toInt(),
|
||||
cornerRadius.y.toInt()
|
||||
)
|
||||
is Stroke -> {
|
||||
setupStroke(style)
|
||||
graphics.drawRoundRect(
|
||||
topLeft.x.toInt(),
|
||||
topLeft.y.toInt(),
|
||||
size.width.toInt(),
|
||||
size.height.toInt(),
|
||||
cornerRadius.x.toInt(),
|
||||
cornerRadius.y.toInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -425,7 +480,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
colorFilter: ColorFilter?,
|
||||
blendMode: BlendMode,
|
||||
) {
|
||||
graphics.paint = color.toAWT()
|
||||
setupColor(color)
|
||||
when (style) {
|
||||
Fill -> graphics.fillRoundRect(
|
||||
topLeft.x.toInt(),
|
||||
@ -436,14 +491,17 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
cornerRadius.y.toInt()
|
||||
)
|
||||
|
||||
is Stroke -> graphics.drawRoundRect(
|
||||
topLeft.x.toInt(),
|
||||
topLeft.y.toInt(),
|
||||
size.width.toInt(),
|
||||
size.height.toInt(),
|
||||
cornerRadius.x.toInt(),
|
||||
cornerRadius.y.toInt()
|
||||
)
|
||||
is Stroke -> {
|
||||
setupStroke(style)
|
||||
graphics.drawRoundRect(
|
||||
topLeft.x.toInt(),
|
||||
topLeft.y.toInt(),
|
||||
size.width.toInt(),
|
||||
size.height.toInt(),
|
||||
cornerRadius.x.toInt(),
|
||||
cornerRadius.y.toInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -454,7 +512,7 @@ public class SvgDrawScope(public val graphics: Graphics2D, size: Size) : DrawSco
|
||||
font: Font,
|
||||
color: Color,
|
||||
) {
|
||||
graphics.paint = color.toAWT()
|
||||
setupColor(color)
|
||||
graphics.font = font
|
||||
graphics.drawString(text, x, y)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user