Skip to content

Commit

Permalink
Improve border line type experience (#1106)
Browse files Browse the repository at this point in the history
* Improve linetype experience (LPK-220).

* LPK-220: Change linewidth calculation for the midline of the boxplot.

* LPK-220: Refactor code and fix linewidth calculation for the crossbars.

* LPK-220: Refactor code.

* LPK-220: Another small refactor in BoxHelper.
  • Loading branch information
ASmirnov-HORIS committed May 24, 2024
1 parent c57bdbe commit 10a1039
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 60 deletions.
3 changes: 2 additions & 1 deletion future_changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
- Undesired vertical scroller when displaying `gggrid` in Jupyter notebook.
- GeoJson structure breaks if the ring start label occurs several times [[#1086](https://github.com/JetBrains/lets-plot/issues/1086)].
- `theme`: left margin doesn't work for the `plot_title` parameter [[#1101](https://github.com/JetBrains/lets-plot/issues/1101)].
- Support for marker rotation [[#736](https://github.com/JetBrains/lets-plot/issues/736)].
- Support for marker rotation [[#736](https://github.com/JetBrains/lets-plot/issues/736)].
- Improve border line type experience [[LPK-220](https://github.com/JetBrains/lets-plot-kotlin/issues/220)].
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,17 @@ class BoxplotGeom : GeomBase() {
ctx: GeomContext,
geomHelper: GeomHelper
) {
BoxHelper.buildMidlines(root, aesthetics, middleAesthetic = Aes.MIDDLE, ctx, geomHelper, fatten = fattenMidline)
BoxHelper.buildMidlines(
root,
aesthetics,
xAes = Aes.X,
middleAes = Aes.MIDDLE,
sizeAes = Aes.WIDTH,
ctx,
geomHelper,
fatten = fattenMidline,
flip = false
)

val elementHelper = geomHelper.createSvgElementHelper()
for (p in aesthetics.dataPoints()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import org.jetbrains.letsPlot.core.plot.base.geom.util.GeomHelper
import org.jetbrains.letsPlot.core.plot.base.geom.util.HintColorUtil
import org.jetbrains.letsPlot.core.plot.base.render.LegendKeyElementFactory
import org.jetbrains.letsPlot.core.plot.base.render.SvgRoot
import org.jetbrains.letsPlot.datamodel.svg.dom.SvgShape

class CrossBarGeom(
private val isVertical: Boolean
Expand Down Expand Up @@ -48,10 +47,6 @@ class CrossBarGeom(
return flipHelper.flip(rectangle)
}

private fun afterRotation(vector: DoubleVector): DoubleVector {
return flipHelper.flip(vector)
}

override fun buildIntern(
root: SvgRoot,
aesthetics: Aesthetics,
Expand All @@ -64,7 +59,17 @@ class CrossBarGeom(
root, aesthetics, pos, coord, ctx,
rectFactory = clientRectByDataPoint(ctx, geomHelper, isHintRect = false)
)
buildMidlines(root, aesthetics, ctx, geomHelper, fatten = fattenMidline)
BoxHelper.buildMidlines(
root,
aesthetics,
xAes = afterRotation(Aes.X),
middleAes = afterRotation(Aes.Y),
sizeAes = Aes.WIDTH, // do not flip as height is not defined for CrossBarGeom
ctx,
geomHelper,
fatten = fattenMidline,
flip = !isVertical
)
// tooltip
flipHelper.buildHints(
listOf(Aes.YMIN, Aes.YMAX).map(::afterRotation),
Expand Down Expand Up @@ -114,39 +119,6 @@ class CrossBarGeom(
}
}

private fun buildMidlines(
root: SvgRoot,
aesthetics: Aesthetics,
ctx: GeomContext,
geomHelper: GeomHelper,
fatten: Double
) {
val elementHelper = geomHelper.createSvgElementHelper()
val xAes = afterRotation(Aes.X)
val yAes = afterRotation(Aes.Y)
val sizeAes = Aes.WIDTH // do not flip as height is not defined for CrossBarGeom
for (p in aesthetics.dataPoints()) {
val x = p.finiteOrNull(xAes) ?: continue
val middle = p.finiteOrNull(yAes) ?: continue
val w = p.finiteOrNull(sizeAes) ?: continue

val width = w * ctx.getResolution(xAes)
val (line) = elementHelper.createLine(
afterRotation(DoubleVector(x - width / 2, middle)),
afterRotation(DoubleVector(x + width / 2, middle)),
p
) ?: continue

// TODO: use strokeScale in createLine() function
// adjust thickness
require(line is SvgShape)
val thickness = line.strokeWidth().get()!!
line.strokeWidth().set(thickness * fatten)

root.add(line)
}
}

companion object {
const val HANDLES_GROUPS = false
private val LEGEND_FACTORY = BoxHelper.legendFactory(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,30 +34,30 @@ object BoxHelper {
fun buildMidlines(
root: SvgRoot,
aesthetics: Aesthetics,
middleAesthetic: Aes<Double>,
xAes: Aes<Double>,
middleAes: Aes<Double>,
sizeAes: Aes<Double>,
ctx: GeomContext,
geomHelper: GeomHelper,
fatten: Double
fatten: Double,
flip: Boolean
) {
val elementHelper = geomHelper.createSvgElementHelper()
for (p in aesthetics.dataPoints()) {
val x = p.finiteOrNull(Aes.X) ?: continue
val middle = p.finiteOrNull(middleAesthetic) ?: continue
val w = p.finiteOrNull(Aes.WIDTH) ?: continue
val x = p.finiteOrNull(xAes) ?: continue
val middle = p.finiteOrNull(middleAes) ?: continue
val w = p.finiteOrNull(sizeAes) ?: continue

val width = w * ctx.getResolution(Aes.X)
val width = w * ctx.getResolution(xAes)

val (line) = elementHelper.createLine(
DoubleVector(x - width / 2, middle),
DoubleVector(x + width / 2, middle),
DoubleVector(x - width / 2, middle).flipIf(flip),
DoubleVector(x + width / 2, middle).flipIf(flip),
p
) ?: continue
) { AesScaling.strokeWidth(it) * fatten } ?: continue

// TODO: use strokeScale in createLine() function
// adjust thickness
require(line is SvgShape)
val thickness = line.strokeWidth().get()!!
line.strokeWidth().set(thickness * fatten)

root.add(line)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ enum class NamedLineType(val code: Int, private val myDashArray: List<Double>?)
override val isSolid: Boolean
get() = true
},
DASHED(2, listOf(4.3, 4.3)),
DOTTED(3, listOf(1.0, 3.2)),
DASHED(2, listOf(4.0, 4.0)),
DOTTED(3, listOf(1.0, 3.0)),
@Suppress("SpellCheckingInspection")
DOTDASH(4, listOf(1.0, 3.2, 4.3, 3.2)),
DOTDASH(4, listOf(1.0, 3.0, 4.0, 3.0)),
@Suppress("SpellCheckingInspection")
LONGDASH(5, listOf(7.4, 3.2)),
LONGDASH(5, listOf(7.0, 3.0)),
@Suppress("SpellCheckingInspection")
TWODASH(6, listOf(2.4, 2.4, 6.4, 2.4));
TWODASH(6, listOf(2.0, 2.0, 6.0, 2.0));

override val isSolid: Boolean
get() = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class PathConverterTest {

matcher!!
.strokeWidth(eq(1.1))
.lineDash(vectorEq(listOf(4.73, 4.73)))
.lineDash(vectorEq(listOf(4.4, 4.4)))

assertMapObject()
}
Expand All @@ -61,7 +61,7 @@ class PathConverterTest {

matcher!!
.strokeWidth(eq(4.4))
.lineDash(vectorEq(listOf(18.92, 18.92)))
.lineDash(vectorEq(listOf(17.6, 17.6)))

assertMapObject()
}
Expand Down

0 comments on commit 10a1039

Please sign in to comment.