Skip to content

Commit

Permalink
Use osascript to detect window size
Browse files Browse the repository at this point in the history
  • Loading branch information
rs committed Feb 25, 2018
1 parent 5894b0c commit 6e1690e
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 22 deletions.
Binary file modified doc/all.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/demo.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/dual.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/memstats.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion doc/producer.go
Expand Up @@ -16,7 +16,7 @@ func add(i *int, d, min int) int {
}

func main() {
t := time.NewTicker(time.Second)
t := time.NewTicker(time.Millisecond)
var utime, stime, cpu int
for range t.C {
b, _ := json.Marshal(map[string]interface{}{
Expand Down
Binary file modified doc/single.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
118 changes: 118 additions & 0 deletions legend.go
@@ -0,0 +1,118 @@
package main

import (
"math"

chart "github.com/wcharczuk/go-chart"
"github.com/wcharczuk/go-chart/drawing"
)

// custom version of chart.Legend
func legend(c *chart.Chart, userDefaults ...chart.Style) chart.Renderable {
return func(r chart.Renderer, cb chart.Box, chartDefaults chart.Style) {
legendDefaults := chart.Style{
FillColor: drawing.ColorWhite,
FontColor: chart.DefaultTextColor,
FontSize: 8.0,
StrokeColor: chart.DefaultAxisColor,
StrokeWidth: chart.DefaultAxisLineWidth,
}

legendPadding := chart.Box{
Top: 5,
Left: 5,
Right: 5,
Bottom: 5,
}
lineTextGap := 5
lineLengthMinimum := 25

var legendStyle chart.Style
if len(userDefaults) > 0 {
legendStyle = userDefaults[0].InheritFrom(chartDefaults.InheritFrom(legendDefaults))
} else {
legendStyle = chartDefaults.InheritFrom(legendDefaults)
}

var labels []string
var lines []chart.Style
for _, s := range c.Series {
if s.GetStyle().IsZero() || s.GetStyle().Show {
if _, isAnnotationSeries := s.(chart.AnnotationSeries); !isAnnotationSeries {
labels = append(labels, s.GetName())
lines = append(lines, s.GetStyle())
}
}
}

legend := chart.Box{
Top: cb.Top,
Left: cb.Left,
// bottom and right will be sized by the legend content
}

legendContent := chart.Box{
Top: legend.Top + legendPadding.Top,
Left: legend.Left + legendPadding.Left,
Right: legend.Left + legendPadding.Left,
Bottom: legend.Top + legendPadding.Top,
}

legendStyle.GetTextOptions().WriteToRenderer(r)

// measure
labelCount := 0
for x := 0; x < len(labels); x++ {
if len(labels[x]) > 0 {
tb := r.MeasureText(labels[x])
legendContent.Bottom += tb.Height() + 5
right := legendContent.Left + tb.Width() + lineTextGap + lineLengthMinimum
legendContent.Right = int(math.Max(float64(legendContent.Right), float64(right)))
labelCount++
}
}

legend = legend.Grow(legendContent)
legend.Right = legendContent.Right + legendPadding.Right
legend.Bottom = legendContent.Bottom + legendPadding.Bottom

chart.Draw.Box(r, legend, legendStyle)

legendStyle.GetTextOptions().WriteToRenderer(r)

ycursor := legendContent.Top
tx := legendContent.Left
legendCount := 0
var label string
for x := 0; x < len(labels); x++ {
label = labels[x]
if len(label) > 0 {
if legendCount > 0 {
ycursor += 5
}

tb := r.MeasureText(label)

ty := ycursor + tb.Height()
r.Text(label, tx, ty)

th2 := tb.Height() >> 1

lx := tx + tb.Width() + lineTextGap
ly := ty - th2
lx2 := legendContent.Right - legendPadding.Right

r.SetStrokeColor(lines[x].GetStrokeColor())
r.SetStrokeWidth(lines[x].GetStrokeWidth())
r.SetStrokeDashArray(lines[x].GetStrokeDashArray())

r.MoveTo(lx, ly)
r.LineTo(lx2, ly)
r.Stroke()

ycursor += tb.Height()
legendCount++
}
}
}
}
44 changes: 23 additions & 21 deletions main.go
Expand Up @@ -16,6 +16,7 @@ import (

"github.com/rs/jplot/data"
"github.com/rs/jplot/source"
"github.com/rs/jplot/window"

humanize "github.com/dustin/go-humanize"
"github.com/wcharczuk/go-chart"
Expand All @@ -24,9 +25,7 @@ import (
)

type graphSpec struct {
width, height int
dpi float64
fields []field
fields []field
}

type field struct {
Expand All @@ -39,12 +38,13 @@ type field struct {
func main() {
url := flag.String("url", "", "URL to fetch every second. Read JSON objects from stdin if not specified.")
steps := flag.Int("steps", 100, "Number of values to plot.")
width := flag.Int("width", 2500, "Canvas width")
height := flag.Int("height", 1400, "Canvas height")
dpi := flag.Float64("dpi", 220, "Canvas definition")
flag.Parse()

specs := parseSpec(flag.Args(), *width, *height, *dpi)
if _, _, err := window.Size(); err != nil {
log.Fatal("Cannot get window size")
}

specs := parseSpec(flag.Args())

dp := &data.Points{Size: *steps}
wg := &sync.WaitGroup{}
Expand All @@ -58,11 +58,15 @@ func main() {
t := time.NewTicker(time.Second)
defer t.Stop()
for {
width, height, err := window.Size()
if err != nil {
log.Fatal("Cannot get window size")
}
select {
case <-t.C:
render(specs, dp)
render(specs, dp, width, height-25)
case <-exit:
render(specs, dp)
render(specs, dp, width, height-25)
return
}
}
Expand Down Expand Up @@ -97,14 +101,10 @@ func main() {
}
}

func parseSpec(args []string, width, height int, dpi float64) []graphSpec {
func parseSpec(args []string) []graphSpec {
specs := make([]graphSpec, 0, len(args))
for i, v := range flag.Args() {
gs := graphSpec{
width: width,
height: height / len(args),
dpi: dpi,
}
gs := graphSpec{}
for j, name := range strings.Split(v, "+") {
var isCounter bool
var isMarker bool
Expand Down Expand Up @@ -137,7 +137,7 @@ func parseSpec(args []string, width, height int, dpi float64) []graphSpec {
return specs
}

func render(specs []graphSpec, dp *data.Points) {
func render(specs []graphSpec, dp *data.Points, width, height int) {
graphs := make([]chart.Chart, 0, len(specs))
for _, gs := range specs {
series := []chart.Series{}
Expand All @@ -157,7 +157,7 @@ func render(specs []graphSpec, dp *data.Points) {
YValues: vals,
})
}
graphs = append(graphs, graph(series, markers, gs.width, gs.height, gs.dpi))
graphs = append(graphs, graph(series, markers, width, height/len(specs)))
}
printGraphs(graphs)
}
Expand All @@ -180,7 +180,7 @@ func reset() {
}

// graph generate a line graph with series.
func graph(series []chart.Series, markers []chart.GridLine, width, height int, dpi float64) chart.Chart {
func graph(series []chart.Series, markers []chart.GridLine, width, height int) chart.Chart {
for i, s := range series {
if s, ok := s.(chart.ContinuousSeries); ok {
s.XValues = seq.Range(0, float64(len(s.YValues)-1))
Expand All @@ -190,6 +190,7 @@ func graph(series []chart.Series, markers []chart.GridLine, width, height int, d
StrokeWidth: 2,
StrokeColor: c,
FillColor: c.WithAlpha(20),
FontSize: 9,
}
series[i] = s
max := &chart.MaxSeries{
Expand All @@ -203,15 +204,16 @@ func graph(series []chart.Series, markers []chart.GridLine, width, height int, d
last := chart.LastValueAnnotation(s, siValueFormater)
last.Style.FillColor = c
last.Style.FontColor = textColor(c)
last.Style.FontSize = 9
last.Style.Padding = chart.NewBox(2, 2, 2, 2)
series = append(series, max, last)
}
}
graph := chart.Chart{
Width: width,
Height: height,
DPI: dpi,
Background: chart.Style{
Padding: chart.NewBox(20, 0, 0, 20),
Padding: chart.NewBox(5, 0, 0, 5),
},
YAxis: chart.YAxis{
Style: chart.StyleShow(),
Expand All @@ -237,7 +239,7 @@ func graph(series []chart.Series, markers []chart.GridLine, width, height int, d
}
}
graph.Elements = []chart.Renderable{
chart.Legend(&graph, chart.Style{
legend(&graph, chart.Style{
FillColor: drawing.Color{A: 100},
FontColor: chart.ColorWhite,
StrokeColor: chart.ColorTransparent,
Expand Down
46 changes: 46 additions & 0 deletions window/size.go
@@ -0,0 +1,46 @@
package window

import (
"bytes"
"fmt"
"os/exec"
"strconv"
"strings"
)

// Gets the size of the current front
var script = `
tell application "iTerm"
--set w to front window
--set w to window id 1887
set w to %s
set b to bounds of w
set width to ((item 3 of b) - (item 1 of b)) as text
set height to ((item 4 of b) - (item 2 of b)) as text
do shell script "echo " & (id of w) & " " & width & " " & height
end tell`

var winID string

// Size returns current window height and width.
func Size() (int, int, error) {
win := "front window"
if winID != "" {
win = "window id " + winID
}
cmd := exec.Command("osascript", "-e", fmt.Sprintf(script, win))
cmd.Stdin = strings.NewReader("some input")
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return 0, 0, fmt.Errorf("Cannot execute osascript: %v", err)
}
rv := strings.Split(strings.TrimSpace(out.String()), " ")
if len(rv) != 3 {
return 0, 0, fmt.Errorf("invalid output: %s", out.String())
}
winID = rv[0]
width, _ := strconv.Atoi(rv[1])
height, _ := strconv.Atoi(rv[2])
return width, height, nil
}

0 comments on commit 6e1690e

Please sign in to comment.