Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ val canvas = document.getElementById("my-canvas").asInstanceOf[HTMLCanvasElement

// Render the chart
styledChart.renderTo(canvas.getContext2D())

// Fit by redrawing at canvas size (no distortion)
styledChart.renderAtCanvasSize(canvas.getContext2D())

```

## Customising Charts
Expand Down Expand Up @@ -176,3 +180,7 @@ Experimental
## License

[License details]

## Dev Environment

- Nix + direnv: enable the dev shell by running `direnv allow` in the repo. The `.envrc` uses `use flake` to load the environment defined in `flake.nix` (JDK 17, Mill, Node/Yarn).
4 changes: 1 addition & 3 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,16 @@
let
pkgs = import nixpkgs { inherit system; };
jdkToUse = pkgs.jdk17;
sbtWithJRE = pkgs.sbt.override { jre = jdkToUse; };

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed sbt since we are not using it

millWithJRE = pkgs.mill.override { jre = jdkToUse; };
in
{
devShells.default = pkgs.mkShell {
packages = [
jdkToUse
sbtWithJRE
millWithJRE
pkgs.git
pkgs.nodejs
pkgs.yarn
pkgs.nodePackages_latest.http-server

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed unused package

];
};
}
Expand Down
50 changes: 50 additions & 0 deletions florence/src-js/florence/renderer/CanvasRenderer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,53 @@ object CanvasRendererExtensions:
def render(drawing: Drawing): Unit =
val ctx = getContext2D()
CanvasRenderer.render(drawing, ctx)

import florence.core.dsl.styling.StyledChart
import florence.core.model.Chart.LineChart
import florence.core.model.styling.ChartStyle.LineChartStyle



extension (styled: StyledChart[LineChart, LineChartStyle])

/** Redraw at canvas width and height
* No distortion
* Layout recomputed for ticks labels and margins
*/
def renderAtCanvasSize(ctx: CanvasRenderingContext2D)(using
interpreter: Interpreter[StyledChart[LineChart, LineChartStyle], Drawing]
): Unit =
val cw = ctx.canvas.width
val ch = ctx.canvas.height
val s = styled.style
val s2: LineChartStyle = LineChartStyle(
commonProps = s.commonProps.copy(width = cw, height = ch),
xAxis = s.xAxis,
yAxis = s.yAxis,
seriesStyles = s.seriesStyles,
defaultSeriesStyle = s.defaultSeriesStyle,
showPoints = s.showPoints
)
val drw = interpreter.interpret(styled.copy(style = s2))
CanvasRenderer.render(drw, ctx)

extension (chart: LineChart)

/** Redraw with style at canvas size
* Same as renderAtCanvasSize but takes chart and style separately
*/
def renderAtCanvasSizeWith(style: LineChartStyle, ctx: CanvasRenderingContext2D)(using
interpreter: Interpreter[(LineChart, LineChartStyle), Drawing]
): Unit =
val cw = ctx.canvas.width
val ch = ctx.canvas.height
val s2: LineChartStyle = LineChartStyle(
commonProps = style.commonProps.copy(width = cw, height = ch),
xAxis = style.xAxis,
yAxis = style.yAxis,
seriesStyles = style.seriesStyles,
defaultSeriesStyle = style.defaultSeriesStyle,
showPoints = style.showPoints
)
val drw = interpreter.interpret((chart, s2))
CanvasRenderer.render(drw, ctx)
57 changes: 57 additions & 0 deletions florence/test/src/florence/renderer/ResizeRenderingTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package florence

import munit.FunSuite

import florence.core.dsl.LineChartDsl.*
import florence.core.dsl.styling.LineChartStylingDsl.*
import florence.core.model.*
import florence.core.model.styling.*
import florence.core.model.shared.StyleTypes.*
import florence.core.rendering.*

class ResizeRenderingTests extends FunSuite:

private def hasXAxisAt(ops: List[DrawOp], width: Int, height: Int, margins: Margins): Boolean =
ops.exists {
case LineOp(x1, y1, x2, y2, style) =>
val expectedY = height - margins.bottom
val expectedX1 = margins.left
val expectedX2 = width - margins.right
y1 == expectedY && y2 == expectedY && x1 == expectedX1 && x2 == expectedX2 && style.width == 2.0
case _ => false
}

private def hasYAxisAt(ops: List[DrawOp], height: Int, margins: Margins): Boolean =
ops.exists {
case LineOp(x1, y1, x2, y2, style) =>
val expectedX = margins.left
val expectedY1 = margins.top
val expectedY2 = height - margins.bottom
x1 == expectedX && x2 == expectedX && y1 == expectedY1 && y2 == expectedY2 && style.width == 2.0
case _ => false
}

private def resizedStyle(base: ChartStyle.LineChartStyle, w: Int, h: Int, margins: Margins): ChartStyle.LineChartStyle =
base
.withWidth(w)
.withHeight(h)
.withMargins(margins)
.withXAxis(base.xAxis.copy(gridLines = false))
.withYAxis(base.yAxis.copy(gridLines = false))

private def simpleChart: Chart.LineChart =
lineChart("t", pointsSeries("s", (1.0, 1.0), (2.0, 2.0)))

test("axes respect resized width/height at 600x200"):
val margins = Margins(20, 40, 30, 50)
val style = resizedStyle(lineChartStyle(), 600, 200, margins)
val drawing = LineChartInterpreter.interpretLineChart(simpleChart, style)
assert(hasXAxisAt(drawing.ops, 600, 200, margins))
assert(hasYAxisAt(drawing.ops, 200, margins))

test("axes respect resized width/height at 1300x300"):
val margins = Margins(30, 60, 40, 70)
val style = resizedStyle(lineChartStyle(), 1300, 300, margins)
val drawing = LineChartInterpreter.interpretLineChart(simpleChart, style)
assert(hasXAxisAt(drawing.ops, 1300, 300, margins))
assert(hasYAxisAt(drawing.ops, 300, margins))
2 changes: 1 addition & 1 deletion sandbox-tyrian/src/florence/sandbox/CustomChart.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,4 @@ object CustomChart:
def renderChart(canvas: HTMLCanvasElement): Unit =
chart
.withStyling(style)
.renderTo(canvas.getContext2D())
.renderAtCanvasSize(canvas.getContext2D())
2 changes: 1 addition & 1 deletion sandbox/src/florence/sandbox/js/Example.scala
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,6 @@ object Example:
.withHeight(400)
.withMargins(Margins(40, 80, 50, 110))
val styledChart = chart.withStyling(style)
styledChart.renderTo(canvas.getContext2D())
styledChart.renderAtCanvasSize(canvas.getContext2D())
end renderChart
end Example
Loading