Skip to content

Commit

Permalink
Merge pull request #133 from mum4k/linechart-zoom
Browse files Browse the repository at this point in the history
The LineChart widget now supports zooming the content
  • Loading branch information
mum4k authored Feb 18, 2019
2 parents 66599a4 + a87c9c1 commit 2ab7083
Show file tree
Hide file tree
Showing 18 changed files with 2,969 additions and 123 deletions.
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

0 comments on commit 2ab7083

Please sign in to comment.