From b64b9e0d6a576258985795f2a89015e51d1478d6 Mon Sep 17 00:00:00 2001 From: shylinux Date: Fri, 31 Aug 2018 13:03:35 +0800 Subject: [PATCH] vps add html5.md --- .gitignore | 2 - etc/exit.shy | 4 +- etc/init.shy | 4 +- etc/{ => pem}/cert.pem | 0 etc/{ => pem}/key.pem | 0 src/contexts/aaa/aaa.go | 63 ++++- src/contexts/ctx.go | 1 + src/contexts/web/web.go | 190 +++++++++++-- usr/library/context.js | 46 +++ usr/template/common/base.html | 4 +- usr/template/common/wiki.html | 69 +++-- usr/wiki/html5.css | 8 + usr/wiki/html5.js | 519 ++++++++++++++++++++++++++++++++++ usr/wiki/html5.md | 159 +++++++++++ 14 files changed, 1018 insertions(+), 51 deletions(-) rename etc/{ => pem}/cert.pem (100%) rename etc/{ => pem}/key.pem (100%) create mode 100644 usr/wiki/html5.css create mode 100644 usr/wiki/html5.js create mode 100644 usr/wiki/html5.md diff --git a/.gitignore b/.gitignore index 9273f9f2..ed56077a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ -tmp/ var/ pkg/ -bin/ *.swp # Binaries for programs and plugins *.exe diff --git a/etc/exit.shy b/etc/exit.shy index a49b1b48..917cd278 100644 --- a/etc/exit.shy +++ b/etc/exit.shy @@ -1,6 +1,6 @@ source etc/local_exit.shy ~file1 - history save etc/history.txt + history save var/history.txt ~aaa - login save etc/login.txt + login save var/login.txt diff --git a/etc/init.shy b/etc/init.shy index 3844103a..585dd826 100644 --- a/etc/init.shy +++ b/etc/init.shy @@ -1,8 +1,8 @@ login root root ~aaa - login load etc/login.txt + login load var/login.txt ~file1 - history load etc/history.txt + history load var/history.txt source etc/local.shy diff --git a/etc/cert.pem b/etc/pem/cert.pem similarity index 100% rename from etc/cert.pem rename to etc/pem/cert.pem diff --git a/etc/key.pem b/etc/pem/key.pem similarity index 100% rename from etc/key.pem rename to etc/pem/key.pem diff --git a/src/contexts/aaa/aaa.go b/src/contexts/aaa/aaa.go index c550576d..183c1e39 100644 --- a/src/contexts/aaa/aaa.go +++ b/src/contexts/aaa/aaa.go @@ -2,7 +2,12 @@ package aaa // {{{ // }}} import ( // {{{ "contexts" + "crypto/sha1" "math/big" + "net/http" + "sort" + + "encoding/json" "bufio" "io" @@ -147,8 +152,38 @@ var Pulse *ctx.Message var Index = &ctx.Context{Name: "aaa", Help: "认证中心", Caches: map[string]*ctx.Cache{ "nuser": &ctx.Cache{Name: "nuser", Value: "0", Help: "用户数量"}, + + "access_expire": &ctx.Cache{Name: "会话超时", Value: "0", Help: "会话超时"}, + "access_token": &ctx.Cache{Name: "会话令牌", Value: "0", Help: "会话令牌", Hand: func(m *ctx.Message, x *ctx.Cache, arg ...string) string { + if len(arg) > 0 { // {{{ + return arg[0] + } + + if m.Capi("access_expire") < int(time.Now().Unix()) { + var data struct { + Errcode int64 + Errmsg string + Access_token string + Expires_in int64 + } + res, e := http.Get(fmt.Sprintf(m.Conf("wx_api")+m.Conf("access_route"), m.Conf("appid"), m.Conf("appmm"))) + m.Assert(e) + m.Assert(json.NewDecoder(res.Body).Decode(&data)) + m.Cap("access_expire", fmt.Sprintf("%d", time.Now().Unix()+data.Expires_in)) + x.Value = data.Access_token + m.Log("info", "access_token: %s(%s)", m.Cap("access_token"), m.Cap("access_expire")) + m.Cap("stream", m.Conf("appid")) + } + return x.Value // }}} + }}, }, Configs: map[string]*ctx.Config{ + "wx_api": &ctx.Config{Name: "微信接口", Value: "https://api.weixin.qq.com/cgi-bin/", Help: "微信登录"}, + "access_route": &ctx.Config{Name: "微信登录", Value: "token?grant_type=client_credential&appid=%s&secret=%s", Help: "微信登录"}, + "appid": &ctx.Config{Name: "微信帐号", Value: "", Help: "微信帐号"}, + "appmm": &ctx.Config{Name: "微信密码", Value: "", Help: "微信密码"}, + "token": &ctx.Config{Name: "微信令牌", Value: "", Help: "微信密码"}, + "rootname": &ctx.Config{Name: "rootname", Value: "root", Help: "根用户名"}, "expire": &ctx.Config{Name: "expire(s)", Value: "7200", Help: "会话超时"}, "pub": &ctx.Config{Name: "pub", Value: "etc/pub.pem", Help: "公钥文件"}, @@ -171,9 +206,24 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { if aaa, ok := c.Server.(*AAA); m.Assert(ok) { // {{{ stream := "" + method := "" + username := "" + m.Log("fuck", "%s %s", method, username) + if len(arg) > 0 { + switch arg[0] { + case "openid": + method = arg[0] + username = arg[1] + stream = arg[1] + } + } + if m.Has("ip") { stream = m.Option("ip") } + if m.Has("openid") { + stream = m.Option("openid") + } if m.Has("pub") { stream = m.Option("pub") buf, e := ioutil.ReadFile(m.Option("pub")) @@ -249,7 +299,7 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心", word := strings.SplitN(bio.Text(), ":", 3) msg := m.Spawn() msg.Start(word[0], "用户", word[0], word[1], word[2]) - msg.Spawn().Cmd("config", "load", fmt.Sprintf("etc/%s.json", word[0]), "lark") + msg.Spawn().Cmd("config", "load", fmt.Sprintf("var/%s.json", word[0]), "lark") } } case "save": @@ -257,7 +307,7 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心", m.Travel(func(m *ctx.Message, i int) bool { if i > 0 && m.Cap("username") != "root" { f.WriteString(fmt.Sprintf("%s:%s:%s\n", m.Cap("username"), m.Cap("password"), m.Cap("sessid"))) - m.Spawn().Cmd("config", "save", fmt.Sprintf("etc/%s.json", m.Cap("username")), "lark") + m.Spawn().Cmd("config", "save", fmt.Sprintf("var/%s.json", m.Cap("username")), "lark") } return true }) @@ -701,6 +751,15 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心", } // }}} }}, + "wx": &ctx.Command{Name: "wx check signature", Help: "微信", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + list := []string{m.Option("nonce"), m.Option("timestamp"), m.Conf("token")} + sort.Strings(list) + b := sha1.Sum([]byte(strings.Join(list, ""))) + + if m.Option("signature") == hex.EncodeToString(b[:]) { + m.Echo("ok") + } + }}, }, } diff --git a/src/contexts/ctx.go b/src/contexts/ctx.go index c99ca7d8..3b8afeb3 100644 --- a/src/contexts/ctx.go +++ b/src/contexts/ctx.go @@ -3466,6 +3466,7 @@ func Start(args ...string) { Pulse.Sess("cli", "cli") Pulse.Sess("aaa", "aaa") + Pulse.Sess("web", "web") Pulse.Sess("log", "log") if len(args) > 0 { diff --git a/src/contexts/web/web.go b/src/contexts/web/web.go index d0180979..975315ad 100644 --- a/src/contexts/web/web.go +++ b/src/contexts/web/web.go @@ -8,6 +8,7 @@ import ( // {{{ "runtime" "encoding/json" + "encoding/xml" "html/template" "io/ioutil" "net/http" @@ -106,6 +107,8 @@ func (web *WEB) Trans(m *ctx.Message, key string, hand func(*ctx.Message, *ctx.C hand(msg, msg.Target(), msg.Option("path")) switch { + case msg.Has("directory"): + http.ServeFile(w, r, msg.Append("directory")) case msg.Has("redirect"): http.Redirect(w, r, msg.Append("redirect"), http.StatusFound) case msg.Has("template"): @@ -139,7 +142,7 @@ func (web *WEB) ServeHTTP(w http.ResponseWriter, r *http.Request) { // {{{ } if r.URL.Path == "/" && m.Confs("root_index") { - http.Redirect(w, r, "/index/", http.StatusFound) + http.Redirect(w, r, m.Conf("root_index"), http.StatusFound) } else { web.ServeMux.ServeHTTP(w, r) } @@ -254,6 +257,7 @@ func (web *WEB) Start(m *ctx.Message, arg ...string) bool { // {{{ yac.Cmd("train", "code", "struct", "typedef", "struct", "key", "key", ";") yac.Cmd("train", "code", "function", "key", "\\*", "key", "(", "other") yac.Cmd("train", "code", "function", "key", "key", "(", "other") + yac.Cmd("train", "code", "variable", "struct", "key", "key", "other") yac.Cmd("train", "code", "define", "#define", "key", "other") if m.Cap("protocol") == "https" { @@ -287,20 +291,23 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", "nroute": &ctx.Cache{Name: "nroute", Value: "0", Help: "路由数量"}, }, Configs: map[string]*ctx.Config{ - "cmd": &ctx.Config{Name: "cmd", Value: "tmux", Help: "路由数量"}, - "cert": &ctx.Config{Name: "cert", Value: "etc/cert.pem", Help: "路由数量"}, - "key": &ctx.Config{Name: "key", Value: "etc/key.pem", Help: "路由数量"}, - "wiki_dir": &ctx.Config{Name: "wiki_dir", Value: "usr/wiki", Help: "路由数量"}, + "cmd": &ctx.Config{Name: "cmd", Value: "tmux", Help: "路由数量"}, + "cert": &ctx.Config{Name: "cert", Value: "etc/cert.pem", Help: "路由数量"}, + "key": &ctx.Config{Name: "key", Value: "etc/key.pem", Help: "路由数量"}, + "wiki_dir": &ctx.Config{Name: "wiki_dir", Value: "usr/wiki", Help: "路由数量"}, + "wiki_list_show": &ctx.Config{Name: "wiki_list_show", Value: map[string]interface{}{ + "md": true, + }, Help: "路由数量"}, "which": &ctx.Config{Name: "which", Value: "redis.note", Help: "路由数量"}, - "root_index": &ctx.Config{Name: "root_index(true/false)", Value: "true", Help: "路由数量"}, + "root_index": &ctx.Config{Name: "root_index", Value: "/wiki/", Help: "路由数量"}, "auto_create": &ctx.Config{Name: "auto_create(true/false)", Value: "true", Help: "路由数量"}, "refresh_time": &ctx.Config{Name: "refresh_time(ms)", Value: "1000", Help: "路由数量"}, "define": &ctx.Config{Name: "define", Value: map[string]interface{}{ "ngx_command_t": map[string]interface{}{ - "position": map[string]interface{}{ + "position": []interface{}{map[string]interface{}{ "file": "nginx-1.15.2/src/core/ngx_core.h", "line": "22", - }, + }}, }, "ngx_command_s": map[string]interface{}{ "position": map[string]interface{}{ @@ -562,6 +569,11 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", m.Assert(e) defer file.Close() + if m.Option("type") == "json" { + contenttype = "application/json" + body = file + break + } buf := &bytes.Buffer{} writer := multipart.NewWriter(buf) @@ -1193,7 +1205,6 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", case "pyc", "o", "gz", "tar": continue case "c": - m.Log("fuck", "parse %s", name) case "h": default: continue @@ -1202,8 +1213,7 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", f, e := os.Open(name) m.Assert(e) defer f.Close() - - m.Log("fuck", "parse %d/%d %s", i, len(msg.Meta["filename"]), name) + m.Log("fuck", "%d/%d %s", i, len(msg.Meta["filename"]), v) bio := bufio.NewScanner(f) for line := 1; bio.Scan(); line++ { @@ -1228,11 +1238,16 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", default: key = l.Result(3) } + case "variable": + switch l.Result(2) { + case "struct": + key = l.Result(4) + } case "define": key = l.Result(3) } if key != "" { - m.Confv("define", strings.Join([]string{key, "position"}, "."), map[string]interface{}{ + m.Confv("define", strings.Join([]string{key, "position", "-2"}, "."), map[string]interface{}{ "file": strings.TrimPrefix(name, m.Confx("wiki_dir")), "line": line, "type": l.Result(1), @@ -1271,10 +1286,11 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", if m.Options("query") { if v, ok := m.Confv("define", m.Option("query")).(map[string]interface{}); ok { - if val, ok := v["position"].(map[string]interface{}); ok { - m.Add("append", "name", fmt.Sprintf("%v#hash_%v", val["file"], val["line"])) - return + for _, val := range v["position"].([]interface{}) { + value := val.(map[string]interface{}) + m.Add("append", "name", fmt.Sprintf("%v#hash_%v", value["file"], value["line"])) } + return } msg := m.Sess("nfs").Cmd("dir", path.Join(m.Conf("wiki_dir"), m.Option("dir")), "dir_name", "path") for _, v := range msg.Meta["filename"] { @@ -1309,21 +1325,155 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", if l.Name()[0] == '.' { continue } - es := strings.Split(l.Name(), ".") - if len(es) > 0 { - switch es[len(es)-1] { - case "pyc", "o", "gz", "tar": - continue + if !l.IsDir() { + es := strings.Split(l.Name(), ".") + if len(es) > 0 { + if show, ok := m.Confv("wiki_list_show", es[len(es)-1]).(bool); !ok || !show { + continue + } } } m.Add("append", "name", l.Name()) + m.Add("append", "time", l.ModTime().Format("2006-01-02 15:04:05")) + if l.IsDir() { + m.Add("append", "pend", "/") + } else { + m.Add("append", "pend", "") + } + m.Option("time_layout", "2006-01-02 15:04:05") + m.Sort("time", "time_r") } }}, "/wiki/": &ctx.Command{Name: "/wiki", Help: "维基", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { m.Option("which", strings.TrimPrefix(key, "/wiki/")) + if f, e := os.Stat(path.Join(m.Conf("wiki_dir"), m.Option("which"))); e == nil && !f.IsDir() && (strings.HasSuffix(m.Option("which"), ".json") || strings.HasSuffix(m.Option("which"), ".js") || strings.HasSuffix(m.Option("which"), ".css")) { + m.Append("directory", path.Join(m.Conf("wiki_dir"), m.Option("which"))) + return + } + m.Append("template", "wiki") }}, + "/wx/": &ctx.Command{Name: "/wx/", Help: "微信", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if !m.Sess("aaa").Cmd("wx").Results(0) { + return + } + if m.Has("echostr") { + m.Echo(m.Option("echostr")) + return + } + r := m.Optionv("request").(*http.Request) + + switch r.Header.Get("Content-Type") { + case "text/xml": + type Article struct { + XMLName xml.Name `xml:"item"` + PicUrl string + Title string + Description string + Url string + } + type WXMsg struct { + XMLName xml.Name `xml:"xml"` + ToUserName string + FromUserName string + CreateTime int32 + MsgId int64 + MsgType string + + Event string + EventKey string + + Content string + + Format string + Recognition string + + PicUrl string + MediaId string + + Location_X float64 + Location_Y float64 + Scale int64 + Label string + + ArticleCount int + Articles struct { + XMLName xml.Name `xml:"Articles"` + Articles []*Article + } + } + + var data WXMsg + + b, e := ioutil.ReadAll(r.Body) + m.Log("fuck", "b: %v", string(b)) + e = xml.Unmarshal(b, &data) + m.Log("fuck", "b: %#v", data) + + // de := xml.NewDecoder(r.Body) + // e := de.Decode(&data) + m.Assert(e) + + var echo WXMsg + echo.FromUserName = data.ToUserName + echo.ToUserName = data.FromUserName + echo.CreateTime = data.CreateTime + + fs, e := ioutil.ReadDir("usr/wiki") + m.Assert(e) + msg := m.Spawn() + for _, f := range fs { + if !strings.HasSuffix(f.Name(), ".md") { + continue + } + msg.Add("append", "name", f.Name()) + msg.Add("append", "title", strings.TrimSuffix(f.Name(), ".md")+"源码解析") + msg.Add("append", "time", f.ModTime().Format("01/02 15:03")) + } + msg.Option("time_layout", "01/02 15:03") + msg.Sort("time", "time_r") + + articles := []*Article{} + articles = append(articles, &Article{PicUrl: "http://mmbiz.qpic.cn/mmbiz_jpg/sCJZHmp0V0doWEFBe6gS2HjgB0abiaK7H5WjkXGTvAI0CkCFrVJDEBBbJX8Kz0VegZ54ZoCo4We0sKJUOTuf1Tw/0", + Title: "wiki首页", Description: "技术文章", Url: "https://shylinux.com/wiki/"}) + for i, v := range msg.Meta["title"] { + if i > 6 { + continue + } + + articles = append(articles, &Article{PicUrl: "http://mmbiz.qpic.cn/mmbiz_jpg/sCJZHmp0V0doWEFBe6gS2HjgB0abiaK7H5WjkXGTvAI0CkCFrVJDEBBbJX8Kz0VegZ54ZoCo4We0sKJUOTuf1Tw/0", + Title: msg.Meta["time"][i] + " " + v, Description: "技术文章", Url: "https://shylinux.com/wiki/" + msg.Meta["name"][i]}) + } + + switch data.MsgType { + case "event": + echo.MsgType = "news" + echo.Articles.Articles = articles + echo.ArticleCount = len(echo.Articles.Articles) + case "text": + echo.MsgType = "news" + echo.Articles.Articles = articles + echo.ArticleCount = len(echo.Articles.Articles) + case "voice": + echo.MsgType = "text" + echo.Content = "你好" + case "image": + echo.MsgType = "text" + echo.Content = "你好" + case "location": + echo.MsgType = "text" + echo.Content = "你好" + } + + b, e = xml.Marshal(echo) + m.Echo(string(b)) + } + }}, + "user": &ctx.Command{Name: "user", Help: "应用示例", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + aaa := m.Sess("aaa") + m.Spawn().Cmd("get", fmt.Sprintf("%suser/get", aaa.Conf("wx_api")), "access_token", aaa.Cap("access_token")) + }}, "temp": &ctx.Command{Name: "temp", Help: "应用示例", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { msg := m.Spawn(m.Target()) question := []string{} diff --git a/usr/library/context.js b/usr/library/context.js index 085ef767..d53f55e8 100644 --- a/usr/library/context.js +++ b/usr/library/context.js @@ -41,6 +41,52 @@ ctx = { } location.search = arg.join("&"); },//}}} + GET: function(url, form, cb) {//{{{ + var xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function() { + switch (xhr.readyState) { + case 4: + switch (xhr.status) { + case 200: + try { + var msg = JSON.parse(xhr.responseText||'{"result":[]}'); + } catch (e) { + msg = {"result": [xhr.responseText]} + } + + msg && console.log(msg) + msg.result && console.log(msg.result.join("")); + typeof cb == "function" && cb(msg) + } + break; + } + } + + form = form || {} + form["dir"] = form["dir"] || this.Search("dir") || undefined + form["module"] = form["module"] || this.Search("module") || undefined + form["domain"] = form["domain"] || this.Search("domain") || undefined + + var args = []; + for (k in form) { + if (form[k] instanceof Array) { + for (i in form[k]) { + args.push(k+"="+encodeURIComponent(form[k][i])); + } + } else if (form[k] != undefined) { + args.push(k+"="+encodeURIComponent(form[k])); + } + } + + var arg = args.join("&"); + if (arg) { + url += "?"+arg + } + + xhr.open("GET", url); + console.log("GET: "+url+"?"+arg); + xhr.send(); + },//}}} POST: function(url, form, cb) {//{{{ var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { diff --git a/usr/template/common/base.html b/usr/template/common/base.html index c95defb3..26466984 100644 --- a/usr/template/common/base.html +++ b/usr/template/common/base.html @@ -1,7 +1,7 @@ {{define "head"}} - + {{option .Meta "page_title"}}
{{range option . "nline"|meta|list}} -
{{.}}
+
{{.}}
{{end}}
{{$msg := .}} {{if append . "name"}} -
    - {{range append . "name"}} - - {{end}} -
      + {{$l := append . "name"|len}} + {{if eq $l 1}} + + {{else}} +
        + {{range $i, $v := append . "name"}} + + {{end}} +
          + {{end}} {{else}}

          {{append . "body"|meta|unscaped}}

          -

          {{append . "code"|meta}}

          +

          {{append . "code"|meta}}

          {{end}}

+ {{end}} diff --git a/usr/wiki/html5.css b/usr/wiki/html5.css new file mode 100644 index 00000000..9e169c8e --- /dev/null +++ b/usr/wiki/html5.css @@ -0,0 +1,8 @@ +canvas { + border: solid 1px green; +} +.demo { + float:left; + margin-right:10px; + border: solid 1px green; +} diff --git a/usr/wiki/html5.js b/usr/wiki/html5.js new file mode 100644 index 00000000..2b2790bd --- /dev/null +++ b/usr/wiki/html5.js @@ -0,0 +1,519 @@ +var canvas = document.getElementById("heart"); +var ctx = canvas.getContext('2d'); + +var main_angle = 30; +function refreshHeart() { + ctx.clearRect(0,0,400,400) + drawHeart(ctx,200,200,60,main_angle); + main_angle += 10; + for (var i = 0; i < 10; i++) { + var x = Math.random() * 400; + var y = Math.random() * 400; + var scale = Math.random() * 20+10; + var angle = Math.random() * 360; + drawHeart(ctx,x,y,scale,angle); + } + setTimeout(refreshHeart, 200); +} +setTimeout(refreshHeart, 200); + +function drawHeart(ctx,x,y,scale,angle, style, stroke) {//{{{ + ctx.save(); + ctx.translate(x,y); + ctx.rotate(angle/180*Math.PI); + ctx.scale(scale, scale); + heartPath(ctx); + ctx.shadowColor = "gray"; + ctx.shadowOffsetX = 5; + ctx.shadowOffsetY = 5; + ctx.shadowBlur = 5; + if (stroke == "stroke") { + ctx.strokeStyle = style||"red"; + ctx.stroke(); + } else { + ctx.fillStyle = style||"red"; + ctx.fill(); + } + ctx.restore(); +} +//}}} +function heartPath(ctx) {//{{{ + ctx.beginPath(); + ctx.arc(-1,0,1,Math.PI,0,false); + ctx.arc(1,0,1,Math.PI,0,false); + ctx.bezierCurveTo(1.9, 1.2, 0.6, 1.6, 0, 3.0); + ctx.bezierCurveTo( -0.6, 1.6,-1.9, 1.2,-2,0); + ctx.closePath(); +} +//}}} + +var ctx0 = document.getElementById("demo0").getContext("2d"); +ctx0.fillStyle = "green"; +ctx0.fillRect(10,10,100,100); + +var ctx2 = document.getElementById("demo2").getContext("2d"); +ctx2.beginPath(); +ctx2.moveTo(60,10); +ctx2.lineTo(10,110); +ctx2.lineTo(110,110); +ctx2.fill(); + + +function draw3() { + for (var i = 0; i < 120; i+=20) { + for (var j = 0; j < 120; j+=20) { + r = Math.random()*255; + g = Math.random()*255; + b = Math.random()*255; + ctx3.fillStyle = "rgb("+r+","+g+","+b+")"; + ctx3.fillRect(i, j, 20, 20); + } + } +} +var demo3 = document.getElementById("demo3"); +var ctx3 = demo3.getContext("2d"); +demo3.onclick = draw3; +draw3() + +var select_pan = document.getElementById("select_pan"); +var his = document.getElementById("draw_history"); +var show = document.getElementById("show"); +var item = document.getElementById("draw"); +var draw = item.getContext("2d"); + +var control_map = {//{{{ + s: "stroke", + f: "fill", + + e: "heart", + c: "cycle", + r: "rect", + v: "line", + t: "text", + + d: "delete", + + b: "big", + m: "small", + a: "play", + + Escape: "escape", +} +//}}} +function control(event) {//{{{ + if (event.type == "keyup") { + action(event, control_map[event.key]); + } +} +//}}} + +var current_ctx = {//{{{ + hide: 0, + scale: 1, + index_point: false, + shape: 'cycle', + stroke: 'stroke', + color: 'red', + font: '32px sans-serif', + big_scale: 1.25, + small_scale: 0.8, + begin_point: null, + end_point: null, + list: { + style: ["red", "green", "yellow", "blue"], + stroke: ["fill", "stroke"], + shape: ["heart", "cycle", "rect", "line"], + } +} +//}}} +function display(which, group) {//{{{ + var cs = document.getElementsByClassName(group); + for (var i = 0; i < cs.length; i++) { + cs[i].style.backgroundColor = "white"; + } + + var cs = document.getElementsByClassName(group+" "+which); + for (var i = 0; i < cs.length; i++) { + cs[i].style.backgroundColor = "lightblue"; + } +} +//}}} +function action(event, s) {//{{{ + console.log(event); + switch (s) { + case "escape": + current_ctx.begin_point = null; + current_ctx.end_point = null; + refresh(); + break + case "big": + current_ctx.scale *= current_ctx.big_scale; + draw.scale(current_ctx.big_scale, current_ctx.big_scale); + refresh(); + break + case "small": + current_ctx.scale *= current_ctx.small_scale; + draw.scale(current_ctx.small_scale, current_ctx.small_scale); + refresh(); + break + case "clear": + if (confirm("clear all?")) { + action(event, "clear"); + his.innerHTML = ""; + draw_history = []; + refresh(); + } + break + case "hide": + current_ctx.hide = draw_history.length; + refresh(); + break + case "delete": + draw_history.pop(); + refresh(); + break + case "draw": + current_ctx.hide = 0; + refresh(); + break + + case "fill": + current_ctx.stroke = "fill"; + select_pan.selectedIndex=1; + break + case "stroke": + current_ctx.stroke = "stroke"; + select_pan.selectedIndex=0; + break + + case "heart": + current_ctx.shape = s; + current_ctx.stroke = "fill"; + display("e", "control"); + select_pan.selectedIndex=1; + break + case "cycle": + current_ctx.shape = s; + display("c", "control"); + break + case "rect": + current_ctx.shape = s; + display("r", "control"); + break + case "line": + current_ctx.shape = s; + current_ctx.stroke = "stroke"; + select_pan.selectedIndex=0; + display("v", "control"); + break + case "text": + current_ctx.shape = s; + current_ctx.stroke = "fill"; + select_pan.selectedIndex=0; + display("t", "control"); + break + + case "play": + current_ctx.hide = 0; + refresh(500, 0); + break + } +} +//}}} +function select(event, config, val) {//{{{ + var target = event.target; + var value = target[target.selectedIndex].value; + switch (config) { + case "color": + current_ctx.color = value; + break + case "stroke": + current_ctx.stroke = value; + break + case "shape": + display("r", "control"); + switch (value) { + case "heart": + current_ctx.stroke = "fill"; + display("h", "control"); + break + case "cycle": + display("c", "control"); + break + case "rect": + display("r", "control"); + break + case "line": + current_ctx.stroke = "stroke"; + display("v", "control"); + break + } + current_ctx.shape = value; + break + } +} +//}}} + +var draw_history = []; +function modify(event, row, col) {//{{{ + if (event.key != "Enter") { + return + } + console.log("modify"); + console.log(event); + console.log(); + var data = event.target.dataset; + var row = draw_history[data.row]; + var value = event.target.value; + switch (data.col) { + case "x1": + row.begin_point.x = value; + break + case "y1": + row.begin_point.y = value; + break + case "x2": + row.end_point.x = value; + break + case "y2": + row.end_point.y = value; + break + default: + row[data.col] = value; + } + + refresh(); +} +//}}} +function refresh(time, i) {//{{{ + if (time) { + if (0 == i) { + draw.clearRect(0, 0,400/current_ctx.scale, 400/current_ctx.scale); + } + + if (current_ctx.hide <= i && i < draw_history.length) { + var h = draw_history[i]; + draws(draw, h.style, h.stroke, h.shape, h.begin_point, h.end_point); + i++; + setTimeout(function(){ + refresh(time, i); + }, time); + } + return + } + + draw.clearRect(0, 0,400/current_ctx.scale, 400/current_ctx.scale); + + for (var i in draw_history) { + if (i + +## 简介 + +- 文档: +- 文档: + +### miniCAD在线绘图 + + + + + + + +
+ + + + + + +
+ +
+ + + + + + + +
+
+
+
+
+
+
+ +### canvas绘图 + +``` + + +``` + +### 画矩形 + +``` +fillRect(x, y, width, height) +strokeRect(x, y, width, height) +clearRect(x, y, width, height) +``` + +### 画路径 + +``` + + +``` + +``` +beginPath() +moveTo(x, y) +LineTo(x, y) +closePath() +stroke() +fill() + +arc(x, y, radius, startAngle, endAngle, anticlockwise) +arcTo(x1, y1, x2, y2, radius) +quadraticCurveTo(cp1x, cp1y, x, y) +bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) +new Path2D() +``` +### 设置样式 + +``` +fillStyle = "red" +fillStyle = "#FF0000" +fillStyle = "rgb(255,0,0)" +fillStyle = "rgb(255,0,0,1)" +strokeStyle = + +var img = new Image(); +img.src = "img.png"; +img.onLoad = function() {} +createPattern(img, style) + +createLinearGradient(x1, y1, x2, y2) +createRadialGradient(x1, y1, r1, x2, y2, r2) + addColorStop(position, color) + +shadowOffsetX +shadowOffsetY +shadowBlur +shadowColor + +lineWidth +lineCap +lineJoin +``` +### 输出文字 +``` +font +textAlign +textBaseline +direction +measureText() +fillText(text, x, y[, maxWidth]) +strokeText(text, x, y[, maxWidth]) +``` + +### 坐标变换 +``` +save() +restore() +translate(x,y) +rotate(angle) +scale(x, y) +transform(a,b,c,d,e,f) +setTransform(a,b,c,d,e,f) +resetTransform() +``` + + +