1
0
forked from x/ContextOS

vps add html5.md

This commit is contained in:
shylinux 2018-08-31 13:03:35 +08:00
parent 07165a1957
commit b64b9e0d6a
14 changed files with 1018 additions and 51 deletions

2
.gitignore vendored
View File

@ -1,7 +1,5 @@
tmp/
var/
pkg/
bin/
*.swp
# Binaries for programs and plugins
*.exe

View File

@ -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

View File

@ -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

View File

@ -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")
}
}},
},
}

View File

@ -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 {

View File

@ -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" {
@ -291,16 +295,19 @@ var Index = &ctx.Context{Name: "web", 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
}
if !l.IsDir() {
es := strings.Split(l.Name(), ".")
if len(es) > 0 {
switch es[len(es)-1] {
case "pyc", "o", "gz", "tar":
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{}

View File

@ -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() {

View File

@ -1,7 +1,7 @@
{{define "head"}}
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{option .Meta "page_title"}}</title>
<style>
@ -28,7 +28,7 @@
overflow:scroll;
}
code {
font-size:14px;
font-size:13px;
}
.command {
font-size:14px;

View File

@ -14,6 +14,9 @@ function jumpto(url) {
}
function keyup(event) {
console.log(event);
if (typeof window.control == "function") {
control(event);
}
if (event.key == "z") {
var input = document.getElementsByClassName("query_input")[0];
if (!window.query_show) {
@ -156,18 +159,27 @@ function query(event) {
input.style.width = "0px";
}
}
var tags_list = {
{{range $key, $val := conf . "define"}}
"{{$key}}": true,
{{end}}
};
var tags_list = {};
ctx.GET("/wiki/define.json", undefined, function(msg){
tags_list = msg["define"];
})
function tags(event) {
console.log(event);
if (event.srcElement.tagName == "CODE") {
var tag = document.getSelection().toString();
console.log(tag);
if (tag && tag.length > 0 && tags_list[tag]) {
var position = tags_list[tag].position;
if (position.length == 1) {
jumpto("/wiki"+position[0].file+"#hash_"+position[0].line);
} else {
jumpto("/wiki/?query="+encodeURIComponent(tag));
}
}
}
}
document.onmouseup = tags;
toggle();
</script>
<style>
@ -192,36 +204,51 @@ toggle();
font-size:18px;
}
.number {
font-size:12px;
float:left;
position:relative;
left:-6px;
top:22px;
top:18px;
text-align:right;
}
.number div {
margin:0px;
padding:0px;
height:16px;
}
</style>
<div class="content">
<div class="toggle" title="点击,显示或隐藏目录" onclick="toggle()"></div>
<div class="text">
<div class="number">
{{range option . "nline"|meta|list}}
<div id="hash_{{.}}"><code>{{.}}</code></div>
<div id="hash_{{.}}" style="margin-top:-1px"><code>{{.}}</code></div>
{{end}}
</div>
{{$msg := .}}
{{if append . "name"}}
{{$l := append . "name"|len}}
{{if eq $l 1}}
<script>
location.replace("/wiki/{{option $msg "dir"|meta|unscaped}}/{{append . "name"|meta|unscaped}}");
</script>
{{else}}
<ul>
{{range append . "name"}}
{{range $i, $v := append . "name"}}
<li class="link">
<div><a href="/wiki/{{option $msg "dir"|meta}}/{{.}}">{{.}}</a></div>
<div>
<code>{{option $msg "time" $i}}&nbsp;&nbsp;&nbsp;</code>
<a href="/wiki/{{option $msg "dir"|meta}}/{{$v}}{{option $msg "pend" $i}}">{{$v}}{{option $msg "pend" $i}}</a>
</div>
</li>
{{end}}
<ul>
{{end}}
{{else}}
<p>{{append . "body"|meta|unscaped}}</p>
<p><pre><code onmouseup="return tags(event)">{{append . "code"|meta}}</code></pre><p>
<p><pre><code>{{append . "code"|meta}}</code></pre><p>
{{end}}
</div>
</div>
</div>
{{end}}

8
usr/wiki/html5.css Normal file
View File

@ -0,0 +1,8 @@
canvas {
border: solid 1px green;
}
.demo {
float:left;
margin-right:10px;
border: solid 1px green;
}

519
usr/wiki/html5.js Normal file
View File

@ -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 <current_ctx.hide) {
continue
}
var h = draw_history[i];
draws(draw, h.style, h.stroke, h.shape, h.begin_point, h.end_point, h.text);
}
}
//}}}
function draws(draw, style, stroke, shape, begin_point, end_point, text) {//{{{
draw.save();
begin_x = begin_point.x;
begin_y = begin_point.y;
end_x = end_point.x;
end_y = end_point.y;
if (current_ctx.index_point) {
draw.beginPath();
draw.arc(begin_x, begin_y, 5, 0, 2*Math.PI)
draw.fill()
}
if (current_ctx.index_point) {
draw.beginPath();
draw.arc(end_x, end_y, 5, 0, 2*Math.PI)
draw.fill()
}
switch (shape) {
case 'heart':
r = Math.sqrt(Math.pow(begin_x-end_x, 2)+Math.pow(begin_y-end_y,2));
a = Math.atan((end_y-begin_y)/(end_x-begin_x))/Math.PI*180;
drawHeart(draw, begin_x, begin_y, r, a, style, stroke)
break
case 'cycle':
draw.beginPath();
r = Math.sqrt(Math.pow(begin_x-end_x, 2)+Math.pow(begin_y-end_y,2));
draw.arc(begin_x, begin_y, r, 0, 2*Math.PI)
if (stroke == "stroke") {
if (style) {
draw.strokeStyle = style;
}
draw.stroke()
} else {
if (style) {
draw.fillStyle = style;
}
draw.fill()
}
break
case 'line':
draw.beginPath();
draw.moveTo(begin_x, begin_y);
draw.lineTo(end_x, end_y);
if (stroke == "stroke") {
if (style) {
draw.strokeStyle = style;
}
draw.stroke()
} else {
if (style) {
draw.fillStyle = style;
}
draw.fill()
}
break
case 'rect':
if (stroke == "stroke") {
if (style) {
draw.strokeStyle = style;
}
draw.strokeRect(begin_x, begin_y, end_x-begin_x, end_y-begin_y);
} else {
if (style) {
draw.fillStyle = style;
}
draw.fillRect(begin_x, begin_y, end_x-begin_x, end_y-begin_y);
}
break
case 'text':
if (stroke == "stroke") {
if (style) {
draw.strokeStyle = style;
}
draw.font = current_ctx.font;
draw.strokeText(text, begin_x, begin_y, end_x-begin_x);
} else {
if (style) {
draw.fillStyle = style;
}
draw.font = current_ctx.font;
draw.fillText(text, begin_x, begin_y, end_x-begin_x);
}
}
draw.restore();
}
//}}}
function show_debug(log, clear) {//{{{
var fuck = document.getElementById("fuck");
if (clear) {
fuck.innerHTML = "";
}
var div = fuck.appendChild(document.createElement("div"));
div.appendChild(document.createTextNode(log));
}
//}}}
function trans(point) {//{{{
point.x /= current_ctx.scale;
point.y /= current_ctx.scale;
return point;
}
//}}}
function draw_point(event) {//{{{
console.log("point");
console.log(event);
var point = trans({x:event.offsetX, y:event.offsetY});
if (current_ctx.index_point) {
draw.beginPath();
draw.arc(point.x, point.y, 5, 0, 2*Math.PI);
draw.fill();
}
if (!current_ctx.begin_point) {
current_ctx.begin_point = point;
return
}
current_ctx.end_point = point;
console.log(current_ctx.end_point);
var text = "";
if (current_ctx.shape == "text") {
text = prompt("请入文字", "");
}
draws(draw, current_ctx.color, current_ctx.stroke, current_ctx.shape, current_ctx.begin_point, current_ctx.end_point, text);
draw_history.push({style:current_ctx.color, stroke:current_ctx.stroke, shape:current_ctx.shape, begin_point:current_ctx.begin_point, end_point:current_ctx.end_point, text:text})
var headers = ["style", "stroke", "shape", "x1", "y1", "x2", "y2", "text"]
if (his.rows.length == 0) {
var tr = his.insertRow(-1);
for (var i in headers) {
var th = tr.appendChild(document.createElement("th"));
th.appendChild(document.createTextNode(headers[i]))
}
}
var tr = his.insertRow(-1);
var fields = [current_ctx.color, current_ctx.stroke, current_ctx.shape,
parseInt(current_ctx.begin_point.x), parseInt(current_ctx.begin_point.y),
parseInt(current_ctx.end_point.x), parseInt(current_ctx.end_point.y), text]
for (var i in fields) {
var td = tr.appendChild(document.createElement("td"));
switch (headers[i]) {
case "shape":
case "style":
case "stroke":
var select = td.appendChild(document.createElement("select"));
(function() {
var index = [headers[i]];
select.onchange = function(event) {
draw_history[tr.rowIndex-1][index] = event.target[event.target.selectedIndex].text;
refresh();
}
})();
var shapes = current_ctx.list[headers[i]];
for (var j in shapes) {
var option = select.appendChild(document.createElement("option"));
option.text = shapes[j];
if (option.text == fields[i]) {
select.selectedIndex = j;
}
}
break
default:
var input = td.appendChild(document.createElement("input"));
input.value = fields[i];
input.style.width="40px";
input.dataset.row = tr.rowIndex-1
input.dataset.col = headers[i]
input.onkeyup = modify
}
}
current_ctx.begin_point = null;
current_ctx.end_point = null;
}
//}}}
function draw_move(event) {//{{{
var point = trans({x:event.offsetX, y:event.offsetY});
show_debug("", true)
show.innerText="坐标: "+parseInt(point.x)+","+parseInt(point.y);
if (current_ctx.shape == "move") {
if (current_ctx.index_point) {
draw.beginPath();
draw.arc(point.x, point.y, 5, 0, 2*Math.PI);
draw.fill();
}
}
if (current_ctx.begin_point) {
refresh();
draws(draw, current_ctx.color, current_ctx.stroke, current_ctx.shape, current_ctx.begin_point, point, "");
}
return false
}
//}}}

159
usr/wiki/html5.md Normal file
View File

@ -0,0 +1,159 @@
<canvas id="heart" width="400" height="400"></canvas>
## 简介
- 文档: <https://developer.mozilla.org/en-US/docs/Learn>
- 文档: <https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/>
### miniCAD在线绘图
<label>颜色: </label>
<select onchange="select(event, 'color')">
<option>red</option>
<option>green</option>
<option>yellow</option>
<option>blue</option>
<option>black</option>
<option>white</option>
<option>purple</option>
</select>
<label>画笔: </label>
<select id="select_pan" onchange="select(event, 'stroke')">
<option>stroke</option>
<option>fill</option>
</select>
<label>图形: </label>
<select id="select_pan" onchange="select(event, 'shape')">
<option>heart</option>
<option>cycle</option>
<option>rect</option>
<option>line</option>
</select>
<label id="show">坐标: 0,0</label>
<br/>
<button class="control e" onclick="action(event, 'heart')">画心(e)</button>
<button class="control c" onclick="action(event, 'cycle')">画圆\(c\)</button>
<button class="control r" onclick="action(event, 'rect')">矩形\(r\)</button>
<button class="control v" onclick="action(event, 'line')">直线(v)</button>
<button class="control t" onclick="action(event, 'text')">文字(t)</button>
<button class="control a" onclick="action(event, 'play')">播放\(a\)</button>
<br/>
<canvas id="draw" width="400" height="400"
onmousemove="draw_move(event)"
onmouseup="draw_point(event)"
></canvas>
<br/>
<button class="control" onclick="action(event, 'move')">追踪</button>
<button class="control b" onclick="action(event, 'big')">放大(b)</button>
<button class="control m" onclick="action(event, 'small')">缩小(m)</button>
<button class="control" onclick="action(event, 'hide')">隐藏</button>
<button class="control" onclick="action(event, 'draw')">恢复</button>
<button class="control d" onclick="action(event, 'delete')">删除\(d\)</button>
<button class="control" onclick="action(event, 'clear')">清空\(q\)</button>
<br/>
<div id="fuck">
</div>
<div style="clear:both">
</div>
<br/>
<div><table id="draw_history"></table></div>
### canvas绘图
<canvas id="demo0" class="demo" width="120" height="120"></canvas>
```
<canvas id="canvas"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(10,10,100,100);
</script>
```
### 画矩形
```
fillRect(x, y, width, height)
strokeRect(x, y, width, height)
clearRect(x, y, width, height)
```
### 画路径
<canvas id="demo2" class="demo" width="120" height="120"></canvas>
```
<canvas id="demo2" width="120" height="120"></canvas>
<script>
var ctx2 = document.getElementById("demo2").getContext("2d");
ctx2.beginPath();
ctx2.moveTo(60,10);
ctx2.lineTo(10,110);
ctx2.lineTo(110,110);
ctx2.fill();
</script>
```
```
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()
```
### 设置样式
<canvas id="demo3" class="demo" width="120" height="120"></canvas>
```
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()
```
<link rel="stylesheet" href="/wiki/html5.css" type="text/css"></link>
<script src="/wiki/html5.js"></script>