Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'linetype' for theme elements #1072

Merged
merged 14 commits into from
Apr 3, 2024
Merged
Next Next commit
Add interfaces to set stroke-dasharray attribute for svg elements.
  • Loading branch information
OLarionova-HORIS committed Apr 2, 2024
commit 57bdaf16d193cd9fbee6020ebcc726773c355ac5
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.jetbrains.letsPlot.commons.values.Color
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.FILL
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.FILL_OPACITY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_DASHARRAY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_OPACITY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_WIDTH
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgTransformable.Companion.TRANSFORM
Expand Down Expand Up @@ -86,6 +87,10 @@ class SvgCircleElement() : SvgGraphicsElement(), SvgTransformable,
return getAttribute(STROKE_WIDTH)
}

override fun strokeDashArray(): Property<String?> {
return getAttribute(STROKE_DASHARRAY)
}

override fun pointToTransformedCoordinates(point: DoubleVector): DoubleVector {
return container().getPeer()!!.invertTransform(this, point)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.jetbrains.letsPlot.commons.values.Color
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.FILL
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.FILL_OPACITY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_DASHARRAY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_OPACITY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_WIDTH
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgTransformable.Companion.TRANSFORM
Expand Down Expand Up @@ -92,6 +93,10 @@ class SvgEllipseElement() : SvgGraphicsElement(),
return getAttribute(STROKE_WIDTH)
}

override fun strokeDashArray(): Property<String?> {
return getAttribute(STROKE_DASHARRAY)
}

override fun pointToTransformedCoordinates(point: DoubleVector): DoubleVector {
return container().getPeer()!!.invertTransform(this, point)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.jetbrains.letsPlot.commons.values.Color
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.FILL
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.FILL_OPACITY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_DASHARRAY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_OPACITY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_WIDTH
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgTransformable.Companion.TRANSFORM
Expand Down Expand Up @@ -92,6 +93,10 @@ class SvgLineElement() : SvgGraphicsElement(), SvgTransformable,
return getAttribute(STROKE_WIDTH)
}

override fun strokeDashArray(): Property<String?> {
return getAttribute(STROKE_DASHARRAY)
}

override fun pointToTransformedCoordinates(point: DoubleVector): DoubleVector {
return container().getPeer()!!.invertTransform(this, point)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.jetbrains.letsPlot.commons.values.Color
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.FILL
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.FILL_OPACITY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_DASHARRAY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_OPACITY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_WIDTH
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgTransformable.Companion.TRANSFORM
Expand Down Expand Up @@ -75,6 +76,10 @@ class SvgPathElement() : SvgGraphicsElement(), SvgTransformable,
return getAttribute(STROKE_WIDTH)
}

override fun strokeDashArray(): Property<String?> {
return getAttribute(STROKE_DASHARRAY)
}

fun strokeMiterLimit(): Property<Double?> {
return getAttribute(STROKE_MITER_LIMIT)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.jetbrains.letsPlot.commons.values.Color
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.FILL
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.FILL_OPACITY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_DASHARRAY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_OPACITY
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape.Companion.STROKE_WIDTH
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgTransformable.Companion.TRANSFORM
Expand Down Expand Up @@ -96,6 +97,10 @@ class SvgRectElement() : SvgGraphicsElement(), SvgTransformable,
return getAttribute(STROKE_WIDTH)
}

override fun strokeDashArray(): Property<String?> {
return getAttribute(STROKE_DASHARRAY)
}

override fun pointToTransformedCoordinates(point: DoubleVector): DoubleVector {
return container().getPeer()!!.invertTransform(this, point)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ interface SvgShape {

fun strokeWidth(): Property<Double?>

fun strokeDashArray(): Property<String?>

companion object {
val FILL: SvgAttributeSpec<SvgColor> =
SvgAttributeSpec.createSpec("fill")
Expand All @@ -36,5 +38,7 @@ interface SvgShape {
SvgAttributeSpec.createSpec("stroke-opacity")
val STROKE_WIDTH: SvgAttributeSpec<Double> =
SvgAttributeSpec.createSpec("stroke-width")
val STROKE_DASHARRAY: SvgAttributeSpec<String> =
SvgAttributeSpec.createSpec(SvgConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -317,38 +317,21 @@ open class GeomHelper(

companion object {
fun decorate(
node: SvgNode,
shape: SvgShape,
p: DataPointAesthetics,
applyAlphaToAll: Boolean = ALPHA_CONTROLS_BOTH,
strokeScaler: (DataPointAesthetics) -> Double = AesScaling::strokeWidth,
filled: Boolean = true
) {
if (node is SvgShape) {
decorateShape(node as SvgShape, p, applyAlphaToAll, strokeScaler, filled)
}

if (node is SvgElement) {
val lineType = p.lineType()
if (!(lineType.isBlank || lineType.isSolid)) {
StrokeDashArraySupport.apply(node, strokeScaler(p), lineType.dashArray)
}
}
}

private fun decorateShape(
shape: SvgShape,
p: DataPointAesthetics,
applyAlphaToAll: Boolean,
strokeScaler: (DataPointAesthetics) -> Double,
filled: Boolean
) {
AestheticsUtil.updateStroke(shape, p, applyAlphaToAll)
if (filled) {
AestheticsUtil.updateFill(shape, p)
} else {
shape.fill().set(SvgColors.NONE)
}
shape.strokeWidth().set(strokeScaler(p))
val strokeWidth = strokeScaler(p)
shape.strokeWidth().set(strokeWidth)
StrokeDashArraySupport.apply(shape, strokeWidth, p.lineType())
}

internal fun decorateSlimShape(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,7 @@ open class LinesHelper(
path.width().set(size)

val lineType = p.lineType()
if (!(lineType.isBlank || lineType.isSolid)) {
path.dashArray().set(lineType.dashArray)
}
path.lineType().set(lineType)
}

private fun decorateFillingPart(path: LinePath, p: DataPointAesthetics) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package org.jetbrains.letsPlot.core.plot.base.render.svg
import org.jetbrains.letsPlot.commons.geometry.DoubleVector
import org.jetbrains.letsPlot.commons.intern.observable.property.WritableProperty
import org.jetbrains.letsPlot.commons.values.Color
import org.jetbrains.letsPlot.core.plot.base.render.linetype.LineType
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgColors
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgPathDataBuilder
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgPathElement
Expand All @@ -18,7 +19,7 @@ import org.jetbrains.letsPlot.datamodel.svg.dom.SvgPathElement
class LinePath(builder: SvgPathDataBuilder) : SvgComponent() {

private val myPath: SvgPathElement
private var myDashArray: List<Double>? = null
private var myLineType: LineType? = null

init {
myPath = SvgPathElement(builder.build())
Expand Down Expand Up @@ -81,24 +82,19 @@ class LinePath(builder: SvgPathDataBuilder) : SvgComponent() {
}
}

fun dashArray(): WritableProperty<List<Double>> {
return object : WritableProperty<List<Double>> {
override fun set(value: List<Double>) {
myDashArray = ArrayList(value)
fun lineType(): WritableProperty<LineType> {
return object : WritableProperty<LineType> {
override fun set(value: LineType) {
myLineType = value
updatePathDashArray()
}
}
}

private fun updatePathDashArray() {
if (!(myDashArray == null || myDashArray!!.isEmpty())) {
val w = myPath.strokeWidth().get()
val width = w ?: 1.0
StrokeDashArraySupport.apply(
myPath,
width,
myDashArray!!
)
if (myLineType != null) {
val width = myPath.strokeWidth().get() ?: 1.0
StrokeDashArraySupport.apply(myPath, width, myLineType!!)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,34 @@

package org.jetbrains.letsPlot.core.plot.base.render.svg

import org.jetbrains.letsPlot.datamodel.svg.dom.SvgConstants
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgElement
import org.jetbrains.letsPlot.core.plot.base.render.linetype.LineType
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape

/**
* The counterpart of SVG 'stroke-dasharray' attribute but
* length of alternating dashes and gaps
* is defined as multiples of line width
*/
object StrokeDashArraySupport {
fun apply(element: SvgElement, strokeWidth: Double, dashArray: List<Double>) {
fun apply(element: SvgShape, strokeWidth: Double, lineType: LineType) {
val dashArray = toStrokeDashArray(strokeWidth, lineType)
if (dashArray != null) {
element.strokeDashArray().set(dashArray)
}
}

private fun toStrokeDashArray(strokeWidth: Double, lineType: LineType): String? {
if (lineType.isBlank || lineType.isSolid) {
return null
}
val sb = StringBuilder()
for (relativeLength in dashArray) {
lineType.dashArray.forEach { relativeLength ->
val length = relativeLength * strokeWidth
if (sb.length > 0) {
if (sb.isNotEmpty()) {
sb.append(',')
}
sb.append(length.toString())
}
element.getAttribute(SvgConstants.SVG_STROKE_DASHARRAY_ATTRIBUTE).set(sb.toString())
return sb.toString()
}
}