Browse Source

сохранение/запись/непрерывное рисование

kpmy 10 years ago
parent
commit
d4d9de2046
3 changed files with 131 additions and 12 deletions
  1. 5 1
      web/index.html
  2. 125 10
      web/main.dart
  3. 1 1
      web/styles/main.css

+ 5 - 1
web/index.html

@@ -17,7 +17,11 @@
 </head>
 
 <body>
-  <div id="root_data_container">Сохраните это: <textarea id="root_data" style="width: 80%"></textarea></div>
+  <div id="root_data_container">Сохранить:
+    <input id="root_name" value="без имени"/>
+    <input type="button" id="root_save_button" value="сохранить"/>
+    Загрузить: <input type='file' id='file_path'/>
+  </div>
   <div id="root_canvas_container">
     <canvas id="root_canvas" class="layer">
       <p>html5 canvas unsupported :(</p>

+ 125 - 10
web/main.dart

@@ -3,6 +3,9 @@
 
 import 'dart:html';
 import 'package:color/color.dart';
+import 'dart:convert';
+import 'dart:async';
+import 'dart:typed_data';
 
 final Color BG_COLOR = new Color.hex("ced6b5");
 final Color SHADE_COLOR = new Color.hex("bac1a3");
@@ -48,7 +51,20 @@ class Point {
   Color col = BLACK;
 
   Point(this.x, this.y);
-  String toString() => '{x: $x, y: $y, col: $col}';
+  String toString() => '{x: $x, y: $y, col: "$col"}';
+  Map<String, Object> toMap(){
+    Map<String, Object> ret = new Map();
+    ret["x"]=x;
+    ret["y"]=y;
+    ret["col"]=col.toString();
+    return ret;
+  }
+
+  Point.fromMap(Map<String, Object> m){
+    this.x = m["x"];
+    this.y = m["y"];
+    this.col = new Color.hex(m["col"]);
+  }
 }
 
 class Port {
@@ -59,6 +75,8 @@ class Port {
   int width;
   int height;
 
+  Color lastPen;
+
   Map<Tuple2<int, int>, Point> data = new Map();
 
   void prepare(int w, int h){
@@ -159,18 +177,33 @@ class Port {
     via.clearRect(0, 0, width, height);
   }
 
-  void put(int x, int y){
+  void put(int x, int y, [Color col = null]){
     var p = new Tuple2<int, int>(x, y);
     Point tp = data[p];
     if (tp == null){
       data[p]=new Point(x, y);
-    }else{
+      if(col != null){
+        data[p].col = col;
+      }else{
+        data[p].col = BLACK;
+      }
+      lastPen = data[p].col;
+    }else if (col!=null){
+      lastPen = col;
+      if (col == SHADE_COLOR){
+        clear(x, y);
+      }else{
+        tp.col = col;
+      }
+    }else if (col==null){
       if(tp.col == BLACK){
         tp.col = GREY50;
+        lastPen = tp.col;
       }else if(tp.col == GREY50){
         tp.col = GREY25;
+        lastPen = tp.col;
       }else{
-        data.remove(p);
+        clear(x, y);
       }
     }
   }
@@ -178,15 +211,49 @@ class Port {
   void clear(int x, int y){
       var p = new Tuple2<int, int>(x, y);
       data.remove(p);
+      lastPen = SHADE_COLOR;
   }
 
   String export(){
     if (data.values!=null){
-      return data.values.toString();
+      Map<String, Object> r = new Map();
+      List<Map<String, Object>> ret = new List();
+      data.values.forEach((Point p){
+        ret.add(p.toMap());
+      });
+      String name = (querySelector("#root_name") as InputElement).value;
+      if(name==null || name==""){
+        name="noname";
+      }
+      r["name"]=name;
+      r["data"]=ret;
+      return JSON.encode(r);
     }else{
-      return "";
+      return "{}";
     }
   }
+
+  void import(String js){
+    Map<String, Object> r;
+    r = JSON.decode(js);
+    String name = r["name"];
+    if(name == null || name == ""){
+      name = "noname";
+    }
+    (querySelector("#root_name") as InputElement).value = name;
+    data.clear();
+    List<Map<String, Object>> pl = r["data"];
+    if(pl!=null){
+      pl.forEach((Map<String, Object>m){
+        Point p = new Point.fromMap(m);
+        data[new Tuple2(p.x, p.y)]=p;
+      });
+    }
+  }
+
+  Tuple2<int, int> mapCoord(int x, int y){
+    return new Tuple2((x+1) ~/ DOT, (y+1) ~/DOT);
+  }
 }
 
 Port port = null;
@@ -217,21 +284,69 @@ void main() {
   window.onResize.listen(draw);
   div
       ..onMouseMove.listen((MouseEvent e){
-    port.move((e.offset.x+1) ~/ DOT, (e.offset.y+1) ~/DOT);
+    var c = port.mapCoord(e.offset.x, e.offset.y);
+    port.move(c.i1, c.i2);
+    if(port.lastPen!=null){
+      port.put(c.i1, c.i2, port.lastPen);
+      port.front();
+    }
   })
       ..onMouseOut.listen((MouseEvent e){
     port.leave();
+    port.lastPen = null;
+  })
+      ..onMouseUp.listen((MouseEvent e){
+      port.lastPen = null;
   })
       ..onMouseDown.listen((MouseEvent e){
+    var c = port.mapCoord(e.offset.x, e.offset.y);
     if(e.button==0){
-      port.put((e.offset.x+1) ~/ DOT, (e.offset.y+1) ~/DOT);
+      port.put(c.i1, c.i2);
     }else{
-      port.clear((e.offset.x+1) ~/ DOT, (e.offset.y+1) ~/DOT);
+      port.clear(c.i1, c.i2);
     }
     port.front();
-    (querySelector("#root_data") as TextAreaElement).value = port.export();
     e.preventDefault();
   });
+
   via.onContextMenu.listen((e){e.preventDefault();});
+  querySelector("#root_save_button").onClick.listen((e){
+    List<String> data = new List();
+    data.add(port.export());
+    window.open(Url.createObjectUrlFromBlob(new Blob(data, "application/octet-stream")), "");
+  });
+
+  querySelector('#file_path')
+      ..onChange.listen((e){
+    File fi;
+    FileUploadInputElement fo = querySelector('#file_path');
+      if((fo != null) && (fo.files.length>0)){
+        print("get file");
+        FileSystem fs;
+        fi = fo.files.first;
+        Future future = window.requestFileSystem(fi.size).then((fs){
+          print("get fs");
+          FileEntry fe;
+          Future future = fs.root.createFile(fi.name);
+          future.then((fe){
+            print("get writer");
+            FileWriter wr;
+            Future future = fe.createWriter();
+            future.then((wr){
+              print("writer");
+              FileReader rd;
+              wr.write(fi);
+              Future future = HttpRequest.request(fe.toUrl(), mimeType: 'application/octet-stream', responseType: 'arraybuffer').then((req){
+                 print("read");
+                 Uint8List ul = (req.response as ByteBuffer).asUint8List();
+                 String js = UTF8.decode(ul);
+                 port.import(js);
+                 draw(null);
+              });
+            });
+          });
+        });
+      }
+  });
   draw(null);
 }

+ 1 - 1
web/styles/main.css

@@ -37,5 +37,5 @@ html, body {
   height: 100%;
   position: relative;
   top: 20px;
-  /* cursor: none; */
+  cursor: none;
 }