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

The LineChart widget now supports zooming the content #133

Merged
merged 11 commits into from
Feb 18, 2019
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
"roll" through the linechart.
- The LineChart widget now has a method that returns the observed capacity of
the LineChart the last time Draw was called.
- The LineChart widget now supports zoom of the content triggered by mouse
events.
- The Text widget now has a Write option that atomically replaces the entire
text content.

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ go run github.com/mum4k/termdash/widgets/barchart/barchartdemo/barchartdemo.go

### The LineChart

Displays series of values on a line chart. Run the
Displays series of values on a line chart, supports zoom triggered by mouse
events. Run the
[linechartdemo](widgets/linechart/linechartdemo/linechartdemo.go).

```go
Expand Down
33 changes: 1 addition & 32 deletions area/area.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,42 +96,11 @@ func ExcludeBorder(area image.Rectangle) image.Rectangle {
)
}

// findGCF finds the greatest common factor of two integers.
func findGCF(a, b int) int {
if a == 0 || b == 0 {
return 0
}

// https://en.wikipedia.org/wiki/Euclidean_algorithm
for {
rem := a % b
a = b
b = rem

if b == 0 {
break
}
}
return a
}

// simplifyRatio simplifies the given ratio.
func simplifyRatio(ratio image.Point) image.Point {
gcf := findGCF(ratio.X, ratio.Y)
if gcf == 0 {
return image.ZP
}
return image.Point{
X: ratio.X / gcf,
Y: ratio.Y / gcf,
}
}

// WithRatio returns the largest area that has the requested ratio but is
// either equal or smaller than the provided area. Returns zero area if the
// area or the ratio are zero, or if there is no such area.
func WithRatio(area image.Rectangle, ratio image.Point) image.Rectangle {
ratio = simplifyRatio(ratio)
ratio = numbers.SimplifyRatio(ratio)
if area == image.ZR || ratio == image.ZP {
return image.ZR
}
Expand Down
25 changes: 0 additions & 25 deletions area/area_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package area

import (
"fmt"
"image"
"testing"

Expand Down Expand Up @@ -321,30 +320,6 @@ func TestExcludeBorder(t *testing.T) {
}
}

func TestFindGCF(t *testing.T) {
tests := []struct {
a int
b int
want int
}{
{0, 0, 0},
{0, 1, 0},
{1, 0, 0},
{1, 1, 1},
{2, 2, 2},
{50, 35, 5},
{16, 88, 8},
}

for _, tc := range tests {
t.Run(fmt.Sprintf("findGCF(%d,%d)", tc.a, tc.b), func(t *testing.T) {
if got := findGCF(tc.a, tc.b); got != tc.want {
t.Errorf("findGCF(%d,%d) => got %v, want %v", tc.a, tc.b, got, tc.want)
}
})
}
}

func TestWithRatio(t *testing.T) {
tests := []struct {
desc string
Expand Down
49 changes: 47 additions & 2 deletions canvas/braille/braille.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ func (c *Canvas) Size() image.Point {
return image.Point{s.X * ColMult, s.Y * RowMult}
}

// CellArea returns the area of the underlying cell canvas in cells.
func (c *Canvas) CellArea() image.Rectangle {
return c.regular.Area()
}

// Area returns the area of the braille canvas in pixels.
// This will be zero-based area that is two times wider and four times taller
// than the area used to create the braille canvas.
Expand Down Expand Up @@ -186,17 +191,57 @@ func (c *Canvas) TogglePixel(p image.Point, opts ...cell.Option) error {
if err != nil {
return err
}
cell, err := c.regular.Cell(cp)
curCell, err := c.regular.Cell(cp)
if err != nil {
return err
}

if isBraille(cell.Rune) && pixelSet(cell.Rune, p) {
if isBraille(curCell.Rune) && pixelSet(curCell.Rune, p) {
return c.ClearPixel(p, opts...)
}
return c.SetPixel(p, opts...)
}

// SetCellOpts sets options on the specified cell of the braille canvas without
// modifying the content of the cell.
// Sets the default cell options if no options are provided.
// This method is idempotent.
func (c *Canvas) SetCellOpts(cellPoint image.Point, opts ...cell.Option) error {
curCell, err := c.regular.Cell(cellPoint)
if err != nil {
return err
}

if len(opts) == 0 {
// Set the default options.
opts = []cell.Option{
cell.FgColor(cell.ColorDefault),
cell.BgColor(cell.ColorDefault),
}
}
if _, err := c.regular.SetCell(cellPoint, curCell.Rune, opts...); err != nil {
return err
}
return nil
}

// SetAreaCellOpts is like SetCellOpts, but sets the specified options on all
// the cells within the provided area.
func (c *Canvas) SetAreaCellOpts(cellArea image.Rectangle, opts ...cell.Option) error {
haveArea := c.regular.Area()
if !cellArea.In(haveArea) {
return fmt.Errorf("unable to set cell options in area %v, it must fit inside the available cell area is %v", cellArea, haveArea)
}
for col := cellArea.Min.X; col < cellArea.Max.X; col++ {
for row := cellArea.Min.Y; row < cellArea.Max.Y; row++ {
if err := c.SetCellOpts(image.Point{col, row}, opts...); err != nil {
return err
}
}
}
return nil
}

// Apply applies the canvas to the corresponding area of the terminal.
// Guarantees to stay within limits of the area the canvas was created with.
func (c *Canvas) Apply(t terminalapi.Terminal) error {
Expand Down
Loading