edit.dart 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. library edit;
  2. import 'dart:html';
  3. import 'package:color/color.dart';
  4. import 'package:chi/tools.dart';
  5. import 'dart:convert';
  6. import 'dart:async';
  7. import 'dart:typed_data';
  8. final Color BG_COLOR = new Color.hex("ced6b5");
  9. final Color SHADE_COLOR = new Color.hex("bac1a3");
  10. final Color BLACK = new Color.hex("000000");
  11. final Color GREY50 = new Color.hex("7c806d");
  12. final Color GREY25 = new Color.hex("a5ab91");
  13. const int OUTER_SIDE = INNER_SIDE+2*INNER_MARGIN+2*OUTER_STROKE;
  14. const int INNER_SIDE = 7;
  15. const int INNER_MARGIN = 1;
  16. const int OUTER_MARGIN = 1;
  17. const int OUTER_STROKE = 1;
  18. const DOT = OUTER_SIDE+2*OUTER_MARGIN;
  19. class Point {
  20. int x = 0;
  21. int y = 0;
  22. Color col = BLACK;
  23. Point(this.x, this.y);
  24. String toString() => '{x: $x, y: $y, col: "$col"}';
  25. Map<String, Object> toMap(){
  26. Map<String, Object> ret = new Map();
  27. ret["x"]=x;
  28. ret["y"]=y;
  29. ret["col"]=col.toString();
  30. return ret;
  31. }
  32. Point.fromMap(Map<String, Object> m){
  33. this.x = m["x"];
  34. this.y = m["y"];
  35. this.col = new Color.hex(m["col"]);
  36. }
  37. }
  38. class Port {
  39. CanvasRenderingContext2D ctx;
  40. CanvasRenderingContext2D via;
  41. CanvasRenderingContext2D img;
  42. int width;
  43. int height;
  44. Color lastPen;
  45. Map<Tuple2<int, int>, Point> data = new Map();
  46. Tuple2<int, int> size = new Tuple2(50, 40);
  47. void prepare(int w, int h){
  48. ctx.imageSmoothingEnabled = false;
  49. ctx.translate(0.5, 0.5);
  50. ctx.scale(1, 1);
  51. via.imageSmoothingEnabled = false;
  52. via.translate(0.5, 0.5);
  53. via.scale(1, 1);
  54. img.imageSmoothingEnabled = false;
  55. img.translate(0.5, 0.5);
  56. img.scale(1, 1);
  57. width = w;
  58. height = h;
  59. }
  60. void back(){
  61. RgbColor color;
  62. color = BG_COLOR.toRgbColor();
  63. ctx.lineWidth = OUTER_STROKE;
  64. ctx.setFillColorRgb(color.r, color.g, color.b);
  65. ctx.fillRect(0, 0, width, height);
  66. color = SHADE_COLOR.toRgbColor();
  67. ctx.setFillColorRgb(color.r, color.g, color.b);
  68. ctx.setStrokeColorRgb(color.r, color.g, color.b);
  69. int w = 0;
  70. int h = 0;
  71. int y = 2*OUTER_MARGIN;
  72. while(y<height){
  73. int x = 2*OUTER_MARGIN;
  74. w = 0;
  75. while(x<width){
  76. ctx.strokeRect(x, y, OUTER_SIDE, OUTER_SIDE);
  77. ctx.fillRect(x+OUTER_STROKE + INNER_MARGIN, y+OUTER_STROKE+INNER_MARGIN, INNER_SIDE, INNER_SIDE);
  78. ctx.strokeRect(x+OUTER_STROKE + INNER_MARGIN, y+OUTER_STROKE + INNER_MARGIN, INNER_SIDE, INNER_SIDE);
  79. w++;
  80. x = x + DOT;
  81. }
  82. h++;
  83. y = y + DOT;
  84. }
  85. }
  86. void front(){
  87. // Store the current transformation matrix
  88. img.save();
  89. // Use the identity matrix while clearing the canvas
  90. img.setTransform(1, 0, 0, 1, 0, 0);
  91. img.clearRect(0, 0, width, height);
  92. // Restore the transform
  93. img.restore();
  94. if(size != null){
  95. img.setStrokeColorRgb(0xFF, 0, 0);
  96. img.strokeRect(2 * OUTER_MARGIN, 2 * OUTER_MARGIN, size.i1 * DOT - 2, size.i2 * DOT - 2);
  97. }
  98. int w = 0;
  99. int h = 0;
  100. int y = 2*OUTER_MARGIN;
  101. while(y<height){
  102. int x = 2*OUTER_MARGIN;
  103. w = 0;
  104. while(x<width){
  105. var p = new Tuple2<int, int>(w, h);
  106. Point tp = data[p];
  107. if (tp!=null){
  108. var color = tp.col.toRgbColor();
  109. img.setFillColorRgb(color.r, color.g, color.b);
  110. img.setStrokeColorRgb(color.r, color.g, color.b);
  111. img.strokeRect(x, y, OUTER_SIDE, OUTER_SIDE);
  112. img.fillRect(x+OUTER_STROKE + INNER_MARGIN, y+OUTER_STROKE+INNER_MARGIN, INNER_SIDE, INNER_SIDE);
  113. img.strokeRect(x+OUTER_STROKE + INNER_MARGIN, y+OUTER_STROKE + INNER_MARGIN, INNER_SIDE, INNER_SIDE);
  114. }
  115. w++;
  116. x = x + DOT;
  117. }
  118. h++;
  119. y = y + DOT;
  120. }
  121. }
  122. void limit(int x, int y){
  123. size = new Tuple2(x, y);
  124. }
  125. void move(int x, int y){
  126. // Store the current transformation matrix
  127. via.save();
  128. // Use the identity matrix while clearing the canvas
  129. via.setTransform(1, 0, 0, 1, 0, 0);
  130. via.clearRect(0, 0, width, height);
  131. // Restore the transform
  132. via.restore();
  133. var c = new Color.hex("0000ff").toRgbColor();
  134. via.setStrokeColorRgb(c.r, c.g, c.b);
  135. via.strokeRect(x*DOT+1, y*DOT+1, DOT, DOT);
  136. via.strokeRect(x*DOT+1+OUTER_STROKE+INNER_MARGIN, y*DOT+1+OUTER_STROKE+INNER_MARGIN, INNER_SIDE+2*INNER_MARGIN, INNER_SIDE+2*INNER_MARGIN);
  137. (querySelector("#pos") as SpanElement).text = "$x:$y";
  138. (querySelector("#size") as SpanElement).text = "$size";
  139. }
  140. void leave(){
  141. via.clearRect(0, 0, width, height);
  142. }
  143. void put(int x, int y, [Color col = null]){
  144. var p = new Tuple2<int, int>(x, y);
  145. Point tp = data[p];
  146. if ((tp == null) && (col != SHADE_COLOR)){
  147. data[p]=new Point(x, y);
  148. if(col != null){
  149. data[p].col = col;
  150. }else{
  151. data[p].col = BLACK;
  152. }
  153. lastPen = data[p].col;
  154. }else if (col!=null){
  155. lastPen = col;
  156. if (col == SHADE_COLOR){
  157. clear(x, y);
  158. }else{
  159. tp.col = col;
  160. }
  161. }else if (col==null){
  162. if(tp.col == BLACK){
  163. tp.col = GREY50;
  164. lastPen = tp.col;
  165. }else if(tp.col == GREY50){
  166. tp.col = GREY25;
  167. lastPen = tp.col;
  168. }else{
  169. clear(x, y);
  170. }
  171. }
  172. }
  173. void clear(int x, int y){
  174. var p = new Tuple2<int, int>(x, y);
  175. data.remove(p);
  176. lastPen = SHADE_COLOR;
  177. }
  178. void shift(dx, dy){
  179. Map<Tuple2<int, int>, Point> tmp = new Map();
  180. data.keys.forEach((t){
  181. var p = data[t];
  182. var nt = new Tuple2<int, int>(t.i1 + dx, t.i2+dy);
  183. var np = new Point(nt.i1, nt.i2);
  184. np.col = p.col;
  185. tmp[nt] = np;
  186. });
  187. data = tmp;
  188. }
  189. String export(){
  190. if (data.values!=null){
  191. Map<String, Object> r = new Map();
  192. List<Map<String, Object>> ret = new List();
  193. data.values.forEach((Point p){
  194. ret.add(p.toMap());
  195. });
  196. String name = (querySelector("#root_name") as InputElement).value;
  197. if(name==null || name==""){
  198. name="noname";
  199. }
  200. r["name"]=name;
  201. r["size"]=size.toList();
  202. r["data"]=ret;
  203. return JSON.encode(r);
  204. }else{
  205. return "{}";
  206. }
  207. }
  208. void import(String js){
  209. Map<String, Object> r;
  210. r = JSON.decode(js);
  211. String name = r["name"];
  212. if(name == null || name == ""){
  213. name = "noname";
  214. }
  215. (querySelector("#root_name") as InputElement).value = name;
  216. if (r.containsKey("size"))
  217. size = new Tuple2.fromList(r["size"]);
  218. else
  219. size = new Tuple2(50, 40);
  220. data.clear();
  221. List<Map<String, Object>> pl = r["data"];
  222. if(pl!=null){
  223. pl.forEach((Map<String, Object>m){
  224. Point p = new Point.fromMap(m);
  225. data[new Tuple2(p.x, p.y)]=p;
  226. });
  227. }
  228. }
  229. Tuple2<int, int> mapCoord(int x, int y){
  230. return new Tuple2((x+1) ~/ DOT, (y+1) ~/DOT);
  231. }
  232. }
  233. Port port = null;
  234. void run(){
  235. final CanvasElement root = (querySelector('#root_canvas') as CanvasElement);
  236. final CanvasElement via = (querySelector('#via_canvas') as CanvasElement);
  237. final CanvasElement img = (querySelector('#img_canvas') as CanvasElement);
  238. port = new Port();
  239. port.ctx = root.context2D;
  240. port.via = via.context2D;
  241. port.img = img.context2D;
  242. var div = querySelector("#root_canvas_container");
  243. var draw = (e){
  244. root.width = div.clientWidth;
  245. root.height = div.clientHeight;
  246. via.width = div.clientWidth;
  247. via.height = div.clientHeight;
  248. img.width = div.clientWidth;
  249. img.height = div.clientHeight;
  250. port.prepare(root.width, root.height);
  251. port.back();
  252. port.front();
  253. };
  254. window.onResize.listen(draw);
  255. div
  256. ..onMouseMove.listen((MouseEvent e){
  257. var c = port.mapCoord(e.offset.x, e.offset.y);
  258. port.move(c.i1, c.i2);
  259. if(port.lastPen!=null){
  260. port.put(c.i1, c.i2, port.lastPen);
  261. port.front();
  262. }
  263. })
  264. ..onMouseOut.listen((MouseEvent e){
  265. port.leave();
  266. port.lastPen = null;
  267. })
  268. ..onMouseUp.listen((MouseEvent e){
  269. port.lastPen = null;
  270. })
  271. ..onMouseDown.listen((MouseEvent e){
  272. var c = port.mapCoord(e.offset.x, e.offset.y);
  273. if(e.button==0){
  274. port.put(c.i1, c.i2);
  275. }else if (e.button == 1){
  276. port.limit(c.i1+1, c.i2+1);
  277. }else{
  278. port.clear(c.i1, c.i2);
  279. }
  280. port.front();
  281. e.preventDefault();
  282. });
  283. window.onKeyDown.listen((KeyboardEvent e){
  284. switch(e.keyCode){
  285. case 37:
  286. port.shift(-1, 0);
  287. break;
  288. case 39:
  289. port.shift(1, 0);
  290. break;
  291. case 40:
  292. port.shift(0, 1);
  293. break;
  294. case 38:
  295. port.shift(0, -1);
  296. break;
  297. }
  298. port.front();
  299. e.preventDefault();
  300. });
  301. via.onContextMenu.listen((e){e.preventDefault();});
  302. querySelector("#root_save_button").onClick.listen((e){
  303. List<String> data = new List();
  304. data.add(port.export());
  305. window.open(Url.createObjectUrlFromBlob(new Blob(data, "application/octet-stream")), "");
  306. });
  307. querySelector('#file_path')
  308. ..onChange.listen((e){
  309. File fi;
  310. FileUploadInputElement fo = querySelector('#file_path');
  311. if((fo != null) && (fo.files.length>0)){
  312. print("get file");
  313. FileSystem fs;
  314. fi = fo.files.first;
  315. Future future = window.requestFileSystem(fi.size).then((fs){
  316. print("get fs");
  317. FileEntry fe;
  318. Future future = fs.root.createFile(fi.name);
  319. future.then((fe){
  320. print("get writer");
  321. FileWriter wr;
  322. Future future = fe.createWriter();
  323. future.then((wr){
  324. print("writer");
  325. FileReader rd;
  326. wr.write(fi);
  327. Future future = HttpRequest.request(fe.toUrl(), mimeType: 'application/octet-stream', responseType: 'arraybuffer').then((req){
  328. print("read");
  329. Uint8List ul = (req.response as ByteBuffer).asUint8List();
  330. String js = UTF8.decode(ul);
  331. port.import(js);
  332. draw(null);
  333. });
  334. });
  335. });
  336. });
  337. }
  338. });
  339. draw(null);
  340. }