forked from OrgGo/goplot
每次刷新都实时解析路由中给出的 .chart 文件.
Signed-off-by: lion.chan <cy187lion@sina.com>
This commit is contained in:
parent
e9103b47a6
commit
15e7b02ed1
16
.vscode/launch.json
vendored
Normal file
16
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch Package",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"cwd": "./examples",
|
||||||
|
"program": "${fileDirname}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
32
README.md
32
README.md
@ -1,9 +1,8 @@
|
|||||||
goplot
|
# goplot
|
||||||
======
|
|
||||||
|
|
||||||
goplot 是一个使用简单的绘制图表的工具,图表绘制使用了[Chart.js](http://www.chartjs.org/)开源库,编译好的goplot只有一个二进制文件,不依赖任何库/网络。
|
goplot 是一个使用简单的绘制图表的工具,图表绘制使用了[Chart.js](http://www.chartjs.org/)开源库,编译好的goplot只有一个二进制文件,不依赖任何库/网络。
|
||||||
|
|
||||||
##### 下载
|
## 下载
|
||||||
|
|
||||||
[Mac OS X](http://www.bigendian123.com/goplot-darwin.tar.gz)
|
[Mac OS X](http://www.bigendian123.com/goplot-darwin.tar.gz)
|
||||||
|
|
||||||
@ -11,23 +10,32 @@ goplot 是一个使用简单的绘制图表的工具,图表绘制使用了[Cha
|
|||||||
|
|
||||||
Windows暂缺
|
Windows暂缺
|
||||||
|
|
||||||
##### 使用方法
|
## 使用方法
|
||||||
|
|
||||||
* 解压下载包后,进入解压目录,可以看到一个 goplot 的可执行文件和一些 *.chart 文件,这些 chart 文件是默认的一些数据文件样例。可以在这些 chart 文件的目录执行 goplot,然后通过浏览器访问:<http://localhost:8000> 就可以看到图表了。
|
* 解压下载包后,进入解压目录,可以看到一个 goplot 的可执行文件和一些 *.chart 文件,这些 chart 文件是默认的一些数据文件样例。可以在这些 chart 文件的目录执行 goplot,然后通过浏览器访问:<http://localhost:8000> 就可以看到图表了。
|
||||||
* 你可以把 `goplot` 工具放到你的 `PATH` 中,在 chart 文件所在的目录执行 goplot 即可。
|
* 你可以把 `goplot` 工具放到你的 `PATH` 中,在 chart 文件所在的目录执行 goplot 即可。
|
||||||
* chart 文件必须是 .chart 后缀名,内容可以参考源码 examples 目录中的例子。启动 goplot 的目录如果有多个 chart 文件,可以通过不断刷新网页来切换图表。
|
* chart 文件必须是 .chart 后缀名,内容可以参考源码 examples 目录中的例子。启动 goplot 的目录如果有多个 chart 文件,可以通过不断刷新网页来切换图表。
|
||||||
|
|
||||||
.chart 文件定义了 Chart 的 Name,goplot 会根据该 Name 建立路由规则,访问对应 Name 的 Chart 规则为:
|
.chart 文件定义了 Chart 的 Type,可以为以下字符串:
|
||||||
|
|
||||||
|
* line
|
||||||
|
* bar
|
||||||
|
* pie
|
||||||
|
|
||||||
|
goplot 根据路由来匹配 .chart 文件,URL 一级名称即为需要解析的 .chart 文件名(路由中不包含扩展名部分)
|
||||||
|
|
||||||
```url
|
```url
|
||||||
http://localhost:8000/\<Chart Name>
|
http://localhost:8000/\<Chart File Name>
|
||||||
```
|
```
|
||||||
|
|
||||||
##### 曲线图
|
## 曲线图
|
||||||

|
|
||||||
|
|
||||||
##### 柱状图
|

|
||||||

|
|
||||||
|
|
||||||
##### 饼图
|
## 柱状图
|
||||||

|
|
||||||
|

|
||||||
|
|
||||||
|
## 饼图
|
||||||
|
|
||||||
|

|
||||||
|
42
data.go
42
data.go
@ -8,13 +8,14 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ParseState int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
START = iota
|
START ParseState = iota
|
||||||
PROP
|
PROP
|
||||||
DATA
|
DATA
|
||||||
)
|
)
|
||||||
@ -25,9 +26,9 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ChartPropType struct {
|
type ChartPropType struct {
|
||||||
Name string
|
Type string `json:"Type"`
|
||||||
Width int
|
Width int `json:"Width"`
|
||||||
Height int
|
Height int `json:"Height"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChartItemType struct {
|
type ChartItemType struct {
|
||||||
@ -146,20 +147,20 @@ func ParseDataFile(file string) ([]*ChartDataType, error) {
|
|||||||
|
|
||||||
switch status {
|
switch status {
|
||||||
case START:
|
case START:
|
||||||
if bytes.Compare(line, prop_header_str) == 0 {
|
if bytes.Equal(line, prop_header_str) {
|
||||||
status = PROP
|
status = PROP
|
||||||
c = newChartData()
|
c = newChartData()
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("invalid chart file")
|
return nil, errors.New("invalid chart file")
|
||||||
}
|
}
|
||||||
case PROP:
|
case PROP:
|
||||||
if bytes.Compare(line, data_header_str) == 0 {
|
if bytes.Equal(line, data_header_str) {
|
||||||
status = DATA
|
status = DATA
|
||||||
} else {
|
} else {
|
||||||
c.appendProp(line)
|
c.appendProp(line)
|
||||||
}
|
}
|
||||||
case DATA:
|
case DATA:
|
||||||
if bytes.Compare(line, prop_header_str) == 0 {
|
if bytes.Equal(line, prop_header_str) {
|
||||||
status = PROP
|
status = PROP
|
||||||
charts = append(charts, c)
|
charts = append(charts, c)
|
||||||
c = newChartData()
|
c = newChartData()
|
||||||
@ -173,28 +174,3 @@ func ParseDataFile(file string) ([]*ChartDataType, error) {
|
|||||||
charts = append(charts, c)
|
charts = append(charts, c)
|
||||||
return charts, nil
|
return charts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func LookupCurrentDir(dir string) ([]string, error) {
|
|
||||||
var tmp []string = make([]string, 0, 5)
|
|
||||||
|
|
||||||
err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
|
|
||||||
if f == nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.IsDir() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if ok, err := filepath.Match("*.chart", f.Name()); err != nil {
|
|
||||||
return err
|
|
||||||
} else if ok {
|
|
||||||
if path == f.Name() {
|
|
||||||
tmp = append(tmp, path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return tmp, err
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
===
|
===
|
||||||
{ "Name" : "bar", "Height" : 300, "Width" : 550 }
|
{ "Type":"bar", "Height":300, "Width":550 }
|
||||||
---
|
---
|
||||||
aaa 10 13
|
aaa 10 13
|
||||||
bbb 15 12
|
bbb 15 12
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
===
|
===
|
||||||
{ "Name" : "line", "Height" : 300, "Width" : 550 }
|
{ "Type":"line", "Height":300, "Width":550 }
|
||||||
---
|
---
|
||||||
aaa 10 13 10
|
1.0 10 13 10
|
||||||
bbb 15 12 11
|
2.0 15 12 11
|
||||||
ccc 23 14 15
|
3.0 23 14 15
|
||||||
ddd 20 24 25
|
4.0 20 24 25
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
===
|
===
|
||||||
{ "Name" : "pie", "Height" : 300, "Width" : 550 }
|
{ "Type":"pie", "Height":300, "Width":550 }
|
||||||
---
|
---
|
||||||
aaa 10
|
aaa 10
|
||||||
bbb 15
|
bbb 15
|
||||||
|
28
main.go
28
main.go
@ -1,9 +1,29 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
const start = `version: 1.0
|
import (
|
||||||
http://localhost:8000`
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ChartDir string
|
||||||
|
Welcome string = `version: 1.0
|
||||||
|
http://localhost:`
|
||||||
|
)
|
||||||
|
|
||||||
|
func usage() {
|
||||||
|
fmt.Println("goplot version v1.0.1")
|
||||||
|
flag.PrintDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
println(start)
|
var port string
|
||||||
println(ListenAndServe(":8000").Error())
|
flag.StringVar(&ChartDir, "c", "./", "Chart dir")
|
||||||
|
flag.StringVar(&port, "p", "8000", "Listen port")
|
||||||
|
flag.Usage = usage
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
Welcome += port
|
||||||
|
println(Welcome)
|
||||||
|
println(ListenAndServe(":" + port).Error())
|
||||||
}
|
}
|
||||||
|
35
server.go
35
server.go
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
@ -40,24 +41,17 @@ type ChartIf interface {
|
|||||||
NewChart(string) string
|
NewChart(string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var ChartHandlers = make(map[string]ChartIf)
|
||||||
ChartHandlers = make(map[string]ChartIf)
|
|
||||||
ChartFiles []string
|
|
||||||
Index int
|
|
||||||
)
|
|
||||||
|
|
||||||
func handler(w http.ResponseWriter, r *http.Request) {
|
func handler(w http.ResponseWriter, r *http.Request) {
|
||||||
if len(ChartFiles) == 0 {
|
urls := strings.Split(r.URL.String(), "/")
|
||||||
|
if 2 > len(urls) {
|
||||||
|
w.Write([]byte("RouteError"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var file string
|
|
||||||
if Index < len(ChartFiles) {
|
file := urls[1] + ".chart"
|
||||||
file = ChartFiles[Index]
|
file = filepath.Join(ChartDir, file)
|
||||||
Index++
|
|
||||||
} else {
|
|
||||||
Index = 0
|
|
||||||
file = ChartFiles[Index]
|
|
||||||
}
|
|
||||||
|
|
||||||
datas, err := ParseDataFile(file)
|
datas, err := ParseDataFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -80,12 +74,8 @@ func handler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
var ok bool
|
var ok bool
|
||||||
urls := strings.Split(r.URL.String(), "/")
|
|
||||||
if 2 > len(urls) {
|
chart, ok = ChartHandlers[prop.Type]
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
chart, ok = ChartHandlers[urls[1]]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
return
|
return
|
||||||
@ -118,10 +108,5 @@ func ListenAndServe(addr string) error {
|
|||||||
http.HandleFunc("/", handler)
|
http.HandleFunc("/", handler)
|
||||||
http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {})
|
http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) {})
|
||||||
|
|
||||||
var err error
|
|
||||||
ChartFiles, err = LookupCurrentDir(".")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return http.ListenAndServe(addr, nil)
|
return http.ListenAndServe(addr, nil)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user