├── .gitignore ├── .travis.yml ├── Makefile ├── README.md ├── daisy_spread_image ├── .gitignore ├── css │ └── style.css ├── image.svg ├── image │ ├── icon.ai │ ├── icon.icns │ ├── icon.ico │ ├── icon.png │ └── icon.xcf ├── index.html ├── index.js ├── js │ ├── ad.js │ ├── daisy-io.js │ ├── diagram.js │ ├── external_browser.js │ ├── fileex.js │ ├── index.js │ ├── menu.js │ ├── object-util.js │ ├── preference.js │ ├── renderer.js │ └── version.js ├── main.js ├── package.json ├── resource │ ├── circle │ │ ├── MagicCircle_RuneAMN_20141111.svg │ │ ├── MagicCircle_RuneAMN_20141112.svg │ │ ├── MagicCircle_RuneAMN_20141113.svg │ │ ├── MagicCircle_RuneAMN_20141114.svg │ │ ├── MagicCircle_RuneAMN_20141116.svg │ │ ├── MagicCircle_RuneAMN_20141117.svg │ │ ├── MagicCircle_RuneAMN_20141118.svg │ │ ├── MagicCircle_RuneAMN_20141119.svg │ │ ├── MagicCircle_RuneAMN_20141120.svg │ │ ├── MagicCircle_RuneAMN_20141121.svg │ │ ├── MagicCircle_RuneAMN_20141122.svg │ │ └── MagicCircle_RuneAMN_20141123.svg │ ├── default-document.daisyspreadimage │ └── default-preference.json └── test │ ├── mocha.js │ └── spec.js ├── document └── image │ └── daisy_spread_image_0.0.1.png └── release ├── installer_darwin.sh ├── installer_debian.sh ├── installer_debian_amd64_config.json └── installer_win32_x64.sh /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .* 3 | !.gitkeep 4 | !.gitignore 5 | tags 6 | 7 | *~ 8 | *.back 9 | # patch command backup file 10 | *.rej 11 | *.orig 12 | 13 | # cash 14 | *~ 15 | 16 | # tmporary 17 | tmp/ 18 | temp/ 19 | gabage/ 20 | work/ 21 | log/ 22 | 23 | # object files 24 | *.d 25 | *.o 26 | *.a 27 | *.exe 28 | *.app 29 | 30 | # Object files 31 | *.o 32 | *.ko 33 | *.obj 34 | *.elf 35 | 36 | # Libraries 37 | *.lib 38 | *.a 39 | *.la 40 | *.lo 41 | 42 | # Shared objects (inc. Windows DLLs) 43 | *.dll 44 | *.so 45 | *.so.* 46 | *.dylib 47 | 48 | # doxygen 49 | doxygen/ 50 | 51 | *.txt 52 | 53 | 54 | # 55 | .DS_Store 56 | Thumbs.db* 57 | 58 | 59 | node_modules/ 60 | release/ 61 | package-lock.json 62 | 63 | !.travis.yml 64 | 65 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | node_js: 5 | - "14" 6 | - "12" 7 | 8 | addons: 9 | apt: 10 | packages: 11 | - make 12 | - librsvg2-bin 13 | - plantuml 14 | #- wine 15 | 16 | # need spectron test 17 | services: 18 | - xvfb 19 | before_script: 20 | - "export DISPLAY=:99.0" 21 | 22 | script: 23 | - make ci-test 24 | 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | .PHONY: all run clean 3 | 4 | all: 5 | # NOP 6 | exit 1 7 | 8 | run: 9 | cd daisy_spread_image && npm run running 10 | 11 | clean: 12 | cd daisy_spread_image && npm run clean 13 | rm -rf release/release 14 | 15 | .PHONY: test ci-test 16 | ci-test: 17 | cd daisy_spread_image && npm install 18 | make test 19 | #make package 20 | 21 | test: 22 | cd daisy_spread_image && npm run test test/$(ARG) 23 | 24 | .PHONY: package package_desktop 25 | package: package_desktop 26 | 27 | package_desktop: 28 | rm -rf daisy_spread_image/node_modules 29 | #cd daisy_spread_image && npm install # audit command depend npm version 6 30 | cd daisy_spread_image && npm install && npm audit fix 31 | make test 32 | bash ./release/installer_win32_x64.sh 33 | bash ./release/installer_darwin.sh 34 | bash ./release/installer_debian.sh 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | daisy spread image 2 | ==== 3 | 4 | [![Build Status](https://travis-ci.org/MichinariNukazawa/daisy_spread_image.svg?branch=master)](https://travis-ci.org/MichinariNukazawa/daisy_spread_image) 5 | 6 | daisy spread image is magickcircle free scale image generator. 7 | 8 | # 概要 9 | daisy spread imageは、魔法陣ばら撒き画像の生成アプリです。 10 | Win/Mac/Linux対応。 11 | 12 | ![daisy spread_image](document/image/daisy_spread_image_0.0.1.png) 13 | 14 | # Download 15 | [Download for latest release](https://github.com/MichinariNukazawa/daisy_spread_image/releases) 16 | 17 | # Contact 18 | mail: [michinari.nukazawa@gmail.com][mailto] 19 | twitter: [@MNukazawa][twitter] 20 | 21 | Develop by Michinari.Nukazawa, in project "daisy bell". 22 | 23 | [pixiv_booth_project_daisy_bell]: https://daisy-bell.booth.pm/ 24 | [gumroad_runeamn_fonts_pro]: https://gumroad.com/l/UNWF 25 | [mailto]: mailto:michinari.nukazawa@gmail.com 26 | [twitter]: https://twitter.com/MNukazawa 27 | 28 | -------------------------------------------------------------------------------- /daisy_spread_image/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | object/ 3 | 4 | -------------------------------------------------------------------------------- /daisy_spread_image/css/style.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | html, body{ 4 | margin: 0px; /* 余白の削除 */ 5 | padding: 0px; /* 余白の削除 */ 6 | width:100%; 7 | height: 99%; 8 | } 9 | 10 | /*dark theme*/ 11 | body, input, button, select{ 12 | color: rgb(240, 240, 240); 13 | border-color: rgb(180, 180, 180); 14 | background-color: rgb(30, 30, 30); 15 | } 16 | 17 | input, button{ 18 | background-color: rgb(70, 70, 70); 19 | } 20 | 21 | div{ 22 | margin: 0px; 23 | padding: 0px; 24 | } 25 | 26 | input, select{ 27 | font-family: Consolas, 'Courier New', Courier, Monaco, monospace; 28 | vertical-align: bottom; 29 | font-size: 0.8em; 30 | } 31 | 32 | input[type="number"]{ 33 | text-align: right; 34 | width: 70px; 35 | direction: rtl; 36 | } 37 | 38 | input[type="text"]{ 39 | width: 70px; 40 | } 41 | 42 | input[type="checkbox"][disabled] + span{ 43 | color: #707070; 44 | } 45 | 46 | input:disabled, button:disabled, select:disabled{ 47 | background: rgba(128, 128, 128, 0.8); 48 | color: rgba(64, 64, 64, 0.5); 49 | } 50 | 51 | button{ 52 | font-size: 0.8em; 53 | } 54 | 55 | #editor__background-transparent-view{ 56 | font-size: 75%; 57 | } 58 | 59 | #edit-control{ 60 | text-align: right; 61 | font-size: 120%; 62 | background-color: rgb(40, 40, 40); 63 | } 64 | 65 | .box-container{ 66 | display: flex; 67 | height: calc(99% - 48px); 68 | } 69 | 70 | .frame{ 71 | margin: 2px; 72 | padding: 2px; 73 | border: solid 1.5px rgba(220, 220, 220, 0.6); 74 | border-radius: 2px; 75 | } 76 | 77 | table th{ 78 | vertical-align: middle; 79 | text-align: left; 80 | overflow: visible; 81 | position: relative; 82 | font-weight: normal; 83 | } 84 | 85 | #property-editor{ 86 | width: 320px; 87 | font-size: 120%; 88 | background-color: rgb(40, 40, 40); 89 | overflow: visible auto; 90 | } 91 | 92 | #canvas-header{ 93 | padding: 5px; 94 | font-family: Consolas, 'Courier New', Courier, Monaco, monospace; 95 | font-size: 75%; 96 | } 97 | 98 | #editor__element-text{ 99 | resize: vertical; 100 | } 101 | 102 | #thumbnail-container{ 103 | border: solid 1px rgba(0, 0, 0, 0.3); 104 | background: white; 105 | } 106 | 107 | #magickcircle_source_num{ 108 | font-family: Consolas, 'Courier New', Courier, Monaco, monospace; 109 | } 110 | 111 | #canvas-container{ 112 | border: solid 1px rgba(0, 0, 0, 0.3); 113 | /* background: white; */ 114 | position:absolute; 115 | top:58px; bottom:24px; left:325px; right:2px; 116 | overflow: auto; 117 | cursor: default; 118 | } 119 | 120 | #canvas{ 121 | min-height: 90%; 122 | } 123 | 124 | #canvas svg{ 125 | background: white; 126 | } 127 | 128 | #footer-control{ 129 | text-align: right; 130 | background-color: rgb(100, 100, 100); 131 | position: absolute; 132 | bottom: 0; 133 | width: 100%; 134 | padding-bottom: 1px; 135 | } 136 | 137 | #editor-canvas_scale_par{ 138 | width: 70px; 139 | } 140 | 141 | #nodocument-message{ 142 | padding: 5px; 143 | } 144 | 145 | #editor-magickcircle_source_directory_path{ 146 | width: 70%; 147 | } 148 | 149 | #link-get-more-magickcircle{ 150 | width: 100%; 151 | color: rgba(80, 200, 256, 0.92); 152 | cursor: default; 153 | } 154 | 155 | #editor-randomseed_value{ 156 | text-align: right; 157 | width: 110px; 158 | } 159 | 160 | -------------------------------------------------------------------------------- /daisy_spread_image/image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 12 | 15 | 17 | 19 | 22 | 23 | 25 | 27 | 29 | 32 | 35 | 38 | 40 | 43 | 45 | 47 | 48 | 50 | 52 | 55 | 57 | 59 | 61 | 64 | 66 | 68 | 70 | 72 | 74 | 76 | 78 | 80 | 82 | 84 | 87 | 88 | 90 | 91 | 93 | 94 | 96 | 97 | 99 | 103 | 105 | 107 | 108 | 110 | 112 | 114 | 117 | 120 | 123 | 125 | 126 | 128 | 130 | 133 | 136 | 139 | 140 | 141 | 142 | 143 | 145 | 147 | 149 | 150 | 152 | 154 | 155 | -------------------------------------------------------------------------------- /daisy_spread_image/image/icon.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichinariNukazawa/daisy_spread_image/ca71a9869bece5b9477d40bce8dd085500d63477/daisy_spread_image/image/icon.ai -------------------------------------------------------------------------------- /daisy_spread_image/image/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichinariNukazawa/daisy_spread_image/ca71a9869bece5b9477d40bce8dd085500d63477/daisy_spread_image/image/icon.icns -------------------------------------------------------------------------------- /daisy_spread_image/image/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichinariNukazawa/daisy_spread_image/ca71a9869bece5b9477d40bce8dd085500d63477/daisy_spread_image/image/icon.ico -------------------------------------------------------------------------------- /daisy_spread_image/image/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichinariNukazawa/daisy_spread_image/ca71a9869bece5b9477d40bce8dd085500d63477/daisy_spread_image/image/icon.png -------------------------------------------------------------------------------- /daisy_spread_image/image/icon.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichinariNukazawa/daisy_spread_image/ca71a9869bece5b9477d40bce8dd085500d63477/daisy_spread_image/image/icon.xcf -------------------------------------------------------------------------------- /daisy_spread_image/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | daisy spread image 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | document size 15 | width: px 16 | height: px 17 |
18 |
19 |
20 |
21 | Thumbnail 22 |
23 |
24 |
25 | Editor 26 |
27 | RandomSeed 28 | 31 |
32 | RandomSeedValue 33 | 34 |
35 |
36 | Directory 37 | SourceImageNum : --- 38 |
39 | SourceKind : 40 | 44 |
45 | 46 | 49 |
50 | <Get More MagickCircle (link)> 51 |
52 |
53 | MagickCircle 54 | UseImageNum : 55 |
56 | 60 |
61 | 65 |
66 | ImageScale: 67 |
68 | 72 |
73 | 77 |
78 | 82 |
83 | SkewDegree: 84 |
85 | 86 |
87 |
88 |
89 |
90 | (-) 91 | (-,-) 92 | [] 93 |
94 |
95 |
96 | 99 |
100 |
101 |
102 |
103 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /daisy_spread_image/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //const DaisyIO = require('./js/daisy-io'); 4 | 5 | //module.exports.DaisyIO = DaisyIO; 6 | 7 | -------------------------------------------------------------------------------- /daisy_spread_image/js/ad.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | class Ad{ 4 | constructor() 5 | { 6 | this.INTERVAL_MSEC = 50; 7 | 8 | this.TIMEOUT_COUNT_MSEC = 2 *1000; 9 | this.timeout_count = this.TIMEOUT_COUNT_MSEC; 10 | 11 | this.HIDE_COUNT_MSEC = 1 *1000; 12 | this.hide_count = this.HIDE_COUNT_MSEC; 13 | 14 | this.ad_root_element = document.createElement('div'); 15 | 16 | this.ad_root_element.style.cssText = 17 | '' 18 | + 'top:' + 0 + 'px;' 19 | + 'left:' + 0 + 'px;' 20 | + 'width:320px;' 21 | + 'position: fixed;' 22 | //+ 'background-color:rgba(255, 255, 255, 0.95);' 23 | + 'color: rgb(240, 240, 240);' 24 | + 'background-color: rgb(30, 30, 30);' 25 | + 'border: 1.5px solid black;' 26 | + 'border-radius: 3px;' 27 | + 'text-align:center;' 28 | ; 29 | 30 | 31 | this.ads = [ 32 | { 33 | 'width': 320, 34 | 'height': 240, 35 | 'html':`
36 | 37 |
38 | daisy spread image
39 | magickcircles freescale image generator. 40 |
` 41 | }, 42 | /* 43 | { 44 | 'width': 320, 45 | 'height': 240, 46 | 'html':`` 47 | }, 48 | */ 49 | ]; 50 | } 51 | 52 | get_position_(width, height) 53 | { 54 | const position = { 55 | 'top': (window.innerHeight - height) - 150, 56 | 'left': (window.innerWidth - width) / 2, 57 | }; 58 | 59 | return position; 60 | } 61 | 62 | hide_() 63 | { 64 | let callback = function(){ 65 | this.hide_count -= this.INTERVAL_MSEC; 66 | if(0 > this.hide_count){ 67 | this.ad_root_element.style["display"] = "none"; 68 | }else{ 69 | this.ad_root_element.style["opacity"] = (this.hide_count / this.HIDE_COUNT_MSEC); 70 | setTimeout(callback, this.INTERVAL_MSEC); 71 | } 72 | }.bind(this); 73 | setTimeout(callback, this.INTERVAL_MSEC); 74 | } 75 | 76 | start() 77 | { 78 | let index = Math.floor(Math.random(0, this.ads.length)); 79 | const position = this.get_position_(this.ads[index].width, this.ads[index].height); 80 | console.log(index, position); 81 | 82 | this.ad_root_element.style["top"] = position["top"] + 'px'; 83 | this.ad_root_element.style["left"] = position["left"] + 'px'; 84 | this.ad_root_element.innerHTML = this.ads[index].html; 85 | 86 | document.body.appendChild(this.ad_root_element); 87 | let callback = function(){ 88 | this.timeout_count -= this.INTERVAL_MSEC; 89 | // console.log("ad count:%d", this.timeout_count); 90 | if(0 > this.timeout_count){ 91 | this.hide_(); 92 | }else{ 93 | setTimeout(callback, this.INTERVAL_MSEC); 94 | } 95 | }.bind(this); 96 | setTimeout(callback, this.INTERVAL_MSEC); 97 | } 98 | }; 99 | 100 | -------------------------------------------------------------------------------- /daisy_spread_image/js/daisy-io.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const sprintf = require('sprintf-js').sprintf; 4 | const fs = require("fs"); 5 | 6 | module.exports = class DaisyIO{ 7 | static set_err_(err_, level, label, message) 8 | { 9 | err_.level = level; 10 | err_.label = label; 11 | err_.message = message; 12 | } 13 | 14 | static add_errs_(errs_, level, label, message) 15 | { 16 | let err_ = {}; 17 | DaisyIO.set_err_(err_, level, label, message); 18 | 19 | if(! Array.isArray(errs_)){ 20 | console.error(errs_); 21 | errs_ = []; 22 | } 23 | errs_.push(err_); 24 | } 25 | 26 | static open_diagram_from_path(filepath, errs_) 27 | { 28 | // const Diagram = require('./diagram'); 29 | 30 | if(typeof filepath !== 'string'){ 31 | DaisyIO.add_errs_(errs_, 'bug', "Open", "not filepath."); 32 | return null; 33 | } 34 | 35 | let strdata = ''; 36 | try{ 37 | strdata = fs.readFileSync(filepath, 'utf-8'); 38 | }catch(err){ 39 | console.error(err.message); 40 | DaisyIO.add_errs_(errs_, 'warning', "Open", err.message); 41 | return null; 42 | } 43 | 44 | const diagram = Diagram.create_from_native_format_string(strdata, errs_); 45 | return diagram; 46 | } 47 | 48 | static get_ext_from_filepath(filepath) 49 | { 50 | const m = filepath.match(/\.[a-zA-Z0-9]*$/); 51 | if(null === m){ 52 | return ''; 53 | } 54 | return m[0]; 55 | } 56 | 57 | static write_export_diagram(filepath, diagram, errs_) 58 | { 59 | // 周辺情報: 0x0pxのSVGを開くとeye of gnomeが読み込みエラーを起こす。 60 | 61 | if(typeof filepath !== 'string'){ 62 | DaisyIO.add_errs_(errs_, 'bug', "Export", "not filepath."); 63 | return null; 64 | } 65 | 66 | const ext = DaisyIO.get_ext_from_filepath(filepath); 67 | 68 | let res; 69 | switch(ext){ 70 | case '.png': 71 | res = DaisyIO.write_export_png_from_diagram_(filepath, diagram, errs_); 72 | break; 73 | case '.svg': 74 | res = DaisyIO.write_export_svg_from_diagram_(filepath, diagram, errs_); 75 | break; 76 | case '': 77 | DaisyIO.add_errs_(errs_, "warning", "Export", sprintf("file type (ext) not exist. :`%s`", filepath)); 78 | return false; 79 | break; 80 | default: 81 | DaisyIO.add_errs_(errs_, "warning", "Export", sprintf("invalid file type. :`%s`", filepath)); 82 | return false; 83 | } 84 | 85 | return res; 86 | } 87 | 88 | static write_export_png_from_diagram_(filepath, diagram, errs_) 89 | { 90 | let err_ = {}; 91 | 92 | /** 93 | png export is not synced. 94 | https://github.com/domenic/svg2png/issues/113 95 | */ 96 | let svgAsPngUri = require('save-svg-as-png').svgAsPngUri; 97 | let dataUriToBuffer = require('data-uri-to-buffer'); 98 | 99 | const opt = {'scale':1}; 100 | let draw = Renderer.generate_svgjsdraw_from_diagram(diagram, opt); 101 | if(null === draw){ 102 | DaisyIO.add_errs_(errs_, err_.level, "Export", err_.message); 103 | return false; 104 | } 105 | 106 | let svg_elem = draw.node; 107 | // saveSvgAsPng(svg_elem, filepath, {scale: 3}); 108 | // @todo 上限サイズ(4800x3600~どこかまでの間)があるようでその場合0byteファイルが書き出される。 109 | svgAsPngUri(svg_elem, 110 | { 111 | 'backgroundColor': "#fff", 112 | }, 113 | function(uri) { 114 | const decoded = dataUriToBuffer(uri) 115 | try{ 116 | fs.writeFileSync(filepath, decoded); 117 | }catch(err){ 118 | let err_ = {}; 119 | DaisyIO.set_err_(err_, "warning", "Export", err.message); 120 | console.error(err_); 121 | alart(err_); 122 | return; 123 | } 124 | }); 125 | 126 | return true; 127 | } 128 | 129 | static write_export_svg_from_diagram_(filepath, diagram, errs_) 130 | { 131 | let err_ = {}; 132 | const opt = { 133 | 'scale': 1, 134 | }; 135 | const strdata = DaisyIO.get_svg_string_from_diagram_(diagram, opt, err_); 136 | if(null === strdata){ 137 | console.error(err_); 138 | DaisyIO.add_errs_(errs_, err_.level, "Export", err_.message); 139 | return false; 140 | } 141 | 142 | try{ 143 | fs.writeFileSync(filepath, strdata); 144 | }catch(err){ 145 | DaisyIO.add_errs_(errs_, "warning", "Export", sprintf("writeFile error. :`%s`", filepath)); 146 | return false; 147 | } 148 | 149 | return true; 150 | } 151 | 152 | static get_svg_string_from_diagram_(diagram, opt, err_) 153 | { 154 | const xml_formatter = require('xml-formatter'); 155 | const Version = require('./version'); 156 | 157 | let s = Renderer.generate_svgstr_from_diagram(diagram, opt); 158 | 159 | const h = sprintf("", Version.get_name(), Version.get_version()); 160 | s = h + s; 161 | 162 | let options = {indentation: '\t',}; 163 | return xml_formatter(s, options); 164 | } 165 | }; 166 | 167 | -------------------------------------------------------------------------------- /daisy_spread_image/js/diagram.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const sprintf = require('sprintf-js').sprintf; 4 | 5 | const ObjectUtil = require('./object-util'); 6 | const Version = require('./version'); 7 | 8 | module.exports = class Diagram{ 9 | static set_err_(err_, level, label, message) 10 | { 11 | err_.level = level; 12 | err_.label = label; 13 | err_.message = message; 14 | } 15 | 16 | static add_errs_(errs_, level, label, message) 17 | { 18 | let err_ = {}; 19 | DaisyIO.set_err_(err_, level, label, message); 20 | 21 | if(! Array.isArray(errs_)){ 22 | console.error(errs_); 23 | errs_ = []; 24 | } 25 | errs_.push(err_); 26 | } 27 | 28 | static create_from_native_format_string(strdata, errs_) 29 | { 30 | let native_doc = {}; 31 | try{ 32 | native_doc = JSON.parse(strdata); 33 | }catch(err){ 34 | console.debug(err); 35 | DaisyIO.add_errs_(errs_, 'error', "Diagram", err.message); 36 | return null; 37 | } 38 | 39 | if(! native_doc.hasOwnProperty('diagram')){ 40 | DaisyIO.add_errs_(errs_, 'error', "Diagram", 'nothing property "diagram"'); 41 | return null; 42 | } 43 | 44 | const sanitized_diagram = Diagram.sanitize(native_doc.diagram, errs_); 45 | if(null === sanitized_diagram){ 46 | return null; 47 | } 48 | 49 | return sanitized_diagram; 50 | } 51 | 52 | static sanitize(src_diagram, errs_) 53 | { 54 | //! @todo not implement 55 | return ObjectUtil.deepcopy(src_diagram); 56 | } 57 | 58 | static get_size(diagram) 59 | { 60 | return { 61 | 'width': diagram.property.document_width, 62 | 'height': diagram.property.document_height, 63 | }; 64 | } 65 | 66 | static MAX_SIZE() 67 | { 68 | return 30000; 69 | } 70 | 71 | static MIN_SIZE() 72 | { 73 | return 150; 74 | } 75 | 76 | static set_size(diagram, size) 77 | { 78 | if(! Number.isFinite(size.width) 79 | || Diagram.MIN_SIZE() > size.width 80 | || Diagram.MAX_SIZE() < size.width){ 81 | return false; 82 | } 83 | if(! Number.isFinite(size.height) 84 | || Diagram.MIN_SIZE() > size.height 85 | || Diagram.MAX_SIZE() < size.height){ 86 | return false; 87 | } 88 | diagram.property.document_width = Math.round(size.width); 89 | diagram.property.document_height = Math.round(size.height); 90 | 91 | return true; 92 | } 93 | }; 94 | 95 | -------------------------------------------------------------------------------- /daisy_spread_image/js/external_browser.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class ExternalBrowser{ 4 | static open(link){ 5 | require('electron').shell.openExternal(link) 6 | } 7 | }; 8 | 9 | -------------------------------------------------------------------------------- /daisy_spread_image/js/fileex.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class FileEx{ 4 | static is_exist_file(filepath){ 5 | const fs = require('fs'); 6 | try{ 7 | fs.accessSync(filepath); 8 | return true; 9 | }catch(err){ 10 | console.debug(err); 11 | return false; 12 | } 13 | } 14 | 15 | static touch(filepath){ 16 | const fs = require('fs'); 17 | fs.writeFileSync(filepath, ""); 18 | } 19 | 20 | static join(path1, path2){ 21 | const path = require('path'); 22 | return path.join(path1, path2); 23 | } 24 | 25 | static read_textfile(filepath){ 26 | const fs = require('fs'); 27 | try{ 28 | const t = fs.readFileSync(filepath, 'utf8'); 29 | return t; 30 | }catch(err){ 31 | console.debug(err); 32 | return null; 33 | } 34 | } 35 | 36 | static read_json(filepath){ 37 | const t = FileEx.read_textfile(filepath); 38 | if(null === t){ 39 | return {}; 40 | } 41 | return JSON.parse(t); 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /daisy_spread_image/js/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require("fs"); 4 | const path = require('path'); 5 | const sprintf = require('sprintf-js').sprintf; 6 | let SVG = require('svg.js'); 7 | //const {app} = require('electron').remote; 8 | const Preference = require('./js/preference'); 9 | const Renderer = require('./js/renderer').Renderer; 10 | const RenderingHandle = require('./js/renderer').RenderingHandle; 11 | const DaisyIO = require('./js/daisy-io'); 12 | const ExternalBrowser = require('./js/external_browser'); 13 | let ad = new Ad(); 14 | 15 | let rendering_handle = null; 16 | let rendering_handle_thumbnail = null; 17 | 18 | 19 | 20 | // 再現可能擬似乱数 21 | //! @notice 再現さえできればよく、かつ機能追加などであっさり呼び出しが増減するのでバージョン間の再現は諦める。 22 | // https://sbfl.net/blog/2017/06/01/javascript-reproducible-random/ 23 | class Random { 24 | constructor(seed = 88675123) { 25 | this.x = 123456789; 26 | this.y = 362436069; 27 | this.z = 521288629; 28 | this.w = seed; 29 | } 30 | 31 | // XorShift 32 | next() { 33 | let t; 34 | 35 | t = this.x ^ (this.x << 11); 36 | this.x = this.y; this.y = this.z; this.z = this.w; 37 | return this.w = (this.w ^ (this.w >>> 19)) ^ (t ^ (t >>> 8)); 38 | } 39 | 40 | range(min, max){ 41 | const v = Math.abs(this.next()); 42 | const n = max - min; 43 | const r = (v % n) + min; 44 | return r; 45 | } 46 | } 47 | 48 | class Point{ 49 | static between_s(p0, p1){ 50 | return Math.abs(p0.x - p1.x) + Math.abs(p0.y - p1.y); 51 | } 52 | } 53 | 54 | 55 | 56 | function isExistDirSync(file) 57 | { 58 | try{ 59 | const stat = fs.statSync(file); 60 | return stat.isDirectory(); 61 | }catch(err){ 62 | return false; 63 | } 64 | } 65 | 66 | function opendir_dialog(default_dirpath) 67 | { 68 | const {app} = require('electron').remote; 69 | const {dialog} = require('electron').remote; 70 | const fs = require('fs'); 71 | 72 | let open_dirpath = app.getPath('home'); 73 | if(isExistDirSync(default_dirpath)){ 74 | open_dirpath = default_dirpath; 75 | } 76 | console.debug('open_dirpath', open_dirpath); 77 | 78 | let filepath = dialog.showOpenDialogSync( 79 | remote.getCurrentWindow(), 80 | { 81 | title: 'Open', 82 | defaultPath: open_dirpath, 83 | properties: ['openDirectory'], 84 | }); 85 | 86 | if(typeof filepath === "undefined"){ 87 | return ''; 88 | } 89 | 90 | filepath = filepath[0]; 91 | return filepath; 92 | } 93 | 94 | 95 | 96 | function add_event_listener_from_property(property, callback_){ 97 | Object.keys(property).forEach(function (key) { 98 | console.debug(key, property[key]); 99 | 100 | const property_name = key; 101 | const value = property[key]; 102 | let element = document.getElementById('editor-' + property_name); 103 | if(! element){ 104 | console.warn("bug or not implement", property_name); // not implement 'magickcircle_dirpath' 105 | return; // == continue; 106 | } 107 | switch(element.type){ 108 | case 'checkbox': 109 | element.addEventListener('click', callback_, false); 110 | break; 111 | default: 112 | element.addEventListener('change', callback_, false); 113 | } 114 | }); 115 | } 116 | 117 | function set_ui_from_property(property){ 118 | Object.keys(property).forEach(function (key) { 119 | console.debug(key, property[key]); 120 | 121 | const property_name = key; 122 | const value = property[key]; 123 | let element = document.getElementById('editor-' + property_name); 124 | if(! element){ 125 | console.error("bug"); 126 | return; // == continue; 127 | } 128 | switch(element.type){ 129 | case 'checkbox': 130 | element.checked = value; 131 | break; 132 | default: 133 | element.value = value; 134 | } 135 | 136 | let view = document.getElementById('editor-' + property_name + '-view'); 137 | if(view){ 138 | view.textContent = '(' + sprintf("%3d", value) + '%)'; 139 | } 140 | }); 141 | } 142 | 143 | function get_property_from_ui(){ 144 | let property = {}; 145 | 146 | property.magickcircle_dirpath = get_circle_dirpath(); 147 | 148 | property.canvas_scale_par = document.getElementById('editor-canvas_scale_par').value; 149 | property.document_width = document.getElementById('editor-document_width').value; 150 | property.document_height = document.getElementById('editor-document_height').value; 151 | property.randomseed_value = document.getElementById('editor-randomseed_value').value; 152 | property.magickcircle_num = document.getElementById('editor-magickcircle_num').value; 153 | property.magickcircle_source_kind = document.getElementById('editor-magickcircle_source_kind').value; 154 | property.magickcircle_source_directory_path = document.getElementById('editor-magickcircle_source_directory_path').value; 155 | property.magickcircle_unique_picking = document.getElementById('editor-magickcircle_unique_picking').checked; 156 | property.magickcircle_not_collision = document.getElementById('editor-magickcircle_not_collision').checked; 157 | property.magickcircle_imagescale = document.getElementById('editor-magickcircle_imagescale').value; 158 | property.magickcircle_randomsize = document.getElementById('editor-magickcircle_randomsize').checked; 159 | property.magickcircle_randomrotate = document.getElementById('editor-magickcircle_randomrotate').checked; 160 | property.magickcircle_randomskew = document.getElementById('editor-magickcircle_randomskew').checked; 161 | property.magickcircle_skewdegree = document.getElementById('editor-magickcircle_skewdegree').value; 162 | 163 | return property; 164 | } 165 | 166 | function read_circle_filepaths_from_dirpath(dirpath){ 167 | let a = fs.readdirSync(dirpath); 168 | console.debug(a); 169 | return a.filter(name => /.svg$/.test(name)); 170 | } 171 | 172 | function get_circle_dirpath(){ 173 | const fileex = require('./js/fileex'); 174 | return fileex.join(__dirname, "resource/circle/"); 175 | } 176 | 177 | function generate_position_not_collision(random, position_range, elem_scale, diagram_elements){ 178 | for(let i = 0; i < 400; i++){ 179 | let position = { 180 | "x": random.range(position_range.min.x, position_range.max.x), 181 | "y": random.range(position_range.min.y, position_range.max.y), 182 | }; 183 | 184 | let is_collision = false; 185 | for(let eix = 0; eix < diagram_elements.length; eix++){ 186 | // @todo magickcircle自体の元サイズに関わらず左上基準位置の距離だけ見ている 187 | const col = 1600; 188 | const bet = (col / 2 * diagram_elements[eix].scale) + (col / 2 * elem_scale); 189 | if(bet > Point.between_s(position, diagram_elements[eix])){ 190 | is_collision = true; 191 | break; 192 | } 193 | } 194 | if(! is_collision){ // 衝突していなければそれを返す 195 | return position; 196 | } 197 | } 198 | 199 | return null; 200 | } 201 | 202 | function set_ui_generate_diagram(diagram){ 203 | const fileex = require('./js/fileex'); 204 | const property = diagram.property; 205 | console.log("prop:", property); 206 | 207 | let dirpath = get_circle_dirpath(); 208 | if('BuiltIn' !== property.magickcircle_source_kind){ 209 | if(! isExistDirSync(property.magickcircle_source_directory_path)){ 210 | // use faullback to BuiltIn 211 | console.log('use faullback to BuiltIn', property.magickcircle_source_directory_path); 212 | if('' !== property.magickcircle_source_directory_path){ 213 | alert(sprintf("directory not exist:¥n`%s`", property.magickcircle_source_directory_path)); 214 | } 215 | }else{ 216 | dirpath = property.magickcircle_source_directory_path; 217 | Preference.save_preference_of_keypath('magickcircle_source_directory_path', dirpath); 218 | } 219 | } 220 | property.magickcircle_dirpath = dirpath; 221 | 222 | let circle_filepaths = read_circle_filepaths_from_dirpath(dirpath); 223 | document.getElementById('magickcircle_source_num').textContent = sprintf("%3d", circle_filepaths.length); 224 | 225 | let random = new Random(parseInt(diagram.property.randomseed_value, 10)); 226 | 227 | const position_range = { 228 | "min": {"x": 0, "y": 0}, 229 | "max": { 230 | "x": diagram.property.document_width - (1000 * diagram.property.magickcircle_imagescale), 231 | "y": diagram.property.document_height - (1000 * diagram.property.magickcircle_imagescale) 232 | }, 233 | }; 234 | 235 | diagram.diagram_elements = []; 236 | for(let i = 0; i < property.magickcircle_num; i++){ 237 | const ix = random.range(0, circle_filepaths.length); 238 | 239 | if(0 === circle_filepaths.length){ 240 | alert("empty magickcircle (or full unique)"); 241 | break; 242 | } 243 | 244 | // randomrotate無効にした場合に位置他が変わらないよう乱数を取ってから消す。 245 | let rotate_degree = random.range(0, 360); 246 | if(! diagram.property.magickcircle_randomrotate){ 247 | rotate_degree = 0; 248 | } 249 | let scale = random.range(5, 15); 250 | if(! diagram.property.magickcircle_randomsize){ 251 | scale = 10.0; 252 | } 253 | scale = scale / 10.0; 254 | scale *= diagram.property.magickcircle_imagescale; 255 | 256 | let circle_subfilepath = circle_filepaths[ix]; 257 | if(diagram.property.magickcircle_unique_picking){ 258 | circle_filepaths.splice(ix, 1); 259 | } 260 | console.debug(i, circle_subfilepath); 261 | 262 | let position; 263 | if(! diagram.property.magickcircle_not_collision){ 264 | position = { 265 | "x": random.range(position_range.min.x, position_range.max.x), 266 | "y": random.range(position_range.min.y, position_range.max.y), 267 | }; 268 | }else{ 269 | position = generate_position_not_collision(random, position_range, scale, diagram.diagram_elements); 270 | if(null == position){ 271 | alert("position collision. document full."); 272 | break; 273 | } 274 | } 275 | 276 | let elem = { 277 | "kind": "circle_svg", 278 | "x": position.x, 279 | "y": position.y, 280 | "scale": scale, 281 | "rotate_degree": rotate_degree, 282 | "skew": { 'x': 0, 'y': 0,}, 283 | "subfilepath": circle_subfilepath 284 | }; 285 | diagram.diagram_elements.push(elem); 286 | } 287 | 288 | for(let i = 0; i < diagram.diagram_elements.length; i++){ 289 | let elem = diagram.diagram_elements[i]; 290 | 291 | if(diagram.property.magickcircle_randomskew){ 292 | const skew_v = diagram.property.magickcircle_skewdegree; //20; 293 | const skew = { 294 | 'x': random.range(-100, 100) / 100.0 * skew_v, 295 | 'y': random.range(-100, 100) / 100.0 * skew_v, 296 | }; 297 | 298 | elem.skew = skew; 299 | } 300 | } 301 | 302 | Renderer.rerendering(rendering_handle, diagram, null, null, null); 303 | Renderer.rendering_thumbnail(rendering_handle_thumbnail, rendering_handle, {'x': 300,'y': 150}); 304 | } 305 | 306 | function rerendering(){ 307 | const property = get_property_from_ui(); 308 | 309 | console.debug("get prop", property); 310 | get_doc().diagram.property = property; 311 | 312 | set_ui_generate_diagram(get_doc().diagram); 313 | } 314 | 315 | // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/random 316 | function getRandomInt(min, max){ 317 | min = Math.ceil(min); 318 | max = Math.floor(max); 319 | return Math.floor(Math.random() * (max - min)) + min; //The maximum is exclusive and the minimum is inclusive 320 | } 321 | 322 | let global_doc = null; 323 | function get_doc(){ 324 | return global_doc; 325 | } 326 | 327 | window.addEventListener("load", function(){ 328 | console.debug("wakeup"); 329 | 330 | // ** preference 331 | try{ 332 | Preference.init(); 333 | }catch(err){ 334 | message_dialog('error', 'user preference error', "user preference load error:\n" + err.message); 335 | } 336 | 337 | // ** doc init 338 | const fileex = require('./js/fileex'); 339 | const filepathDefaultDoc = fileex.join(__dirname, "resource/default-document.daisyspreadimage"); 340 | global_doc = fileex.read_json(filepathDefaultDoc); 341 | console.debug(global_doc); 342 | 343 | set_ui_from_property(get_doc().diagram.property); 344 | 345 | rendering_handle = new RenderingHandle('canvas'); 346 | rendering_handle_thumbnail = new RenderingHandle('thumbnail-canvas'); 347 | 348 | set_ui_generate_diagram(get_doc().diagram); 349 | 350 | { 351 | // ** preference overwrite 352 | const pref = Preference.get_preference(); 353 | //console.log("pref", pref); 354 | 355 | document.getElementById('editor-magickcircle_source_directory_path').value = pref.magickcircle_source_directory_path; 356 | } 357 | 358 | // ** eventListener 359 | document.getElementById('generate-randomseed').addEventListener('click', function(e){ 360 | document.getElementById('editor-randomseed_value').value = getRandomInt(0, 4294967295); 361 | 362 | rerendering(); 363 | }, false); 364 | document.getElementById('editor-magickcircle_source_kind').addEventListener('change', function(e){ 365 | console.log("kind:", e.target.value); 366 | let elem_pathinput = document.getElementById('editor-magickcircle_source_directory_path'); 367 | let elem_pathbutton = document.getElementById('opendir-magickcircle_source_directory_path'); 368 | switch(e.target.value){ 369 | case "BuiltIn": 370 | elem_pathinput.disabled = true; 371 | elem_pathbutton.disabled = true; 372 | break; 373 | default: 374 | elem_pathinput.disabled = false; 375 | elem_pathbutton.disabled = false; 376 | } 377 | }, false); 378 | document.getElementById('opendir-magickcircle_source_directory_path').addEventListener('click', function(e){ 379 | let elem_dirpath = document.getElementById('editor-magickcircle_source_directory_path'); 380 | let dirpath = elem_dirpath.value; 381 | dirpath = opendir_dialog(dirpath); 382 | console.log("dirpath", dirpath); 383 | elem_dirpath.value = dirpath; 384 | 385 | rerendering(); 386 | }, false); 387 | document.getElementById('link-get-more-magickcircle').addEventListener('click', function(e){ 388 | ExternalBrowser.open('https://daisy-bell.booth.pm/items/81865'); 389 | }, false); 390 | 391 | // ** 392 | let callback_editor_change_ = function(e){ 393 | console.debug(e.target); 394 | 395 | rerendering(); 396 | }; 397 | add_event_listener_from_property(get_doc().diagram.property, callback_editor_change_); 398 | 399 | ad.start(); 400 | }); 401 | 402 | -------------------------------------------------------------------------------- /daisy_spread_image/js/menu.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const remote = require('electron').remote; 4 | const Menu = remote.Menu; 5 | const MenuItem = remote.MenuItem; 6 | const join = require('path').join; 7 | const openAboutWindow = require('about-window').default; 8 | 9 | function message_dialog(strtype, strtitle, strmessage) { 10 | const {dialog} = require('electron').remote; 11 | dialog.showMessageBoxSync( 12 | remote.getCurrentWindow(), 13 | { 14 | type: strtype, 15 | buttons: ['OK'], 16 | title: ((typeof strtitle === 'string')? strtitle:''), 17 | message: strmessage, 18 | }); 19 | } 20 | 21 | function confirm_dialog(strtitle, strmessage) { 22 | const {dialog} = require('electron').remote; 23 | let choice = dialog.showMessageBoxSync( 24 | remote.getCurrentWindow(), 25 | { 26 | type: 'question', 27 | buttons: ['Yes', 'No'], 28 | defaultId: 1, 29 | title: strtitle, 30 | message: strmessage, 31 | }); 32 | 33 | return choice === 0; 34 | }; 35 | 36 | function open_dialog(default_filepath) 37 | { 38 | const {app} = require('electron').remote; 39 | const {dialog} = require('electron').remote; 40 | const fs = require('fs'); 41 | const isExistSync = function(file) 42 | { 43 | try{ 44 | fs.statSync(file); 45 | }catch(err){ 46 | return false; 47 | } 48 | return true 49 | }; 50 | 51 | let open_filepath = app.getPath('home'); 52 | if('' != default_filepath){ 53 | default_filepath = path.resolve(default_filepath); 54 | const dirpath = path.dirname(default_filepath); 55 | if(isExistSync(default_filepath)){ 56 | open_filepath = default_filepath; 57 | }else if(isExistSync(dirpath) && fs.statSync(dirpath).isDirectory()){ 58 | open_filepath = dirpath; 59 | } 60 | } 61 | console.debug('open_filepath', open_filepath); 62 | 63 | let filepath = dialog.showOpenDialogSync( 64 | remote.getCurrentWindow(), 65 | { 66 | title: 'Open', 67 | defaultPath: open_filepath, 68 | filters: [ 69 | {name: 'Documents', extensions: ['daisysequence']}, 70 | {name: 'All', extensions: ['*']}, 71 | ], 72 | properties: ['openFile'], 73 | }); 74 | 75 | if(typeof filepath === "undefined"){ 76 | return ''; 77 | } 78 | 79 | filepath = filepath[0]; 80 | return filepath; 81 | } 82 | 83 | function save_dialog(title, default_filepath) 84 | { 85 | const {app} = require('electron').remote; 86 | const {dialog} = require('electron').remote; 87 | 88 | if('' == default_filepath){ 89 | // 拡張子のみのファイルパスを作っておくとdialogが勝手にoverwrite確認をしてくれる 90 | default_filepath = path.join(app.getPath('home'), '.' + 'daisysequence'); 91 | } 92 | let filepath = dialog.showSaveDialogSync( 93 | remote.getCurrentWindow(), 94 | { 95 | 'title': title, 96 | defaultPath: default_filepath, 97 | filters: [ 98 | {name: 'Documents', extensions: ['daisysequence']}, 99 | {name: 'All', extensions: ['*']}, 100 | ], 101 | }); 102 | if(typeof filepath === "undefined"){ 103 | return ''; 104 | } 105 | 106 | return filepath; 107 | } 108 | 109 | function export_dialog(default_filepath, format_name) 110 | { 111 | const {app} = require('electron').remote; 112 | const {dialog} = require('electron').remote; 113 | 114 | if('' == default_filepath){ 115 | default_filepath = path.join(app.getPath('home'), '.' + format_name); 116 | }else{ 117 | default_filepath = default_filepath.replace(/\.[a-zA-Z0-9]*$/, '.' + format_name); 118 | } 119 | let filepath = dialog.showSaveDialogSync( 120 | remote.getCurrentWindow(), 121 | { 122 | title: 'Export', 123 | defaultPath: default_filepath, 124 | filters: [ 125 | {name: format_name, extensions: [format_name]}, 126 | {name: 'All', extensions: ['*']}, 127 | ], 128 | }); 129 | if(typeof filepath === "undefined"){ 130 | return ''; 131 | } 132 | 133 | return filepath; 134 | } 135 | 136 | function menu_do_export_(format_name) 137 | { 138 | let filepath = ''; 139 | filepath = export_dialog(filepath, format_name); 140 | if('' == filepath){ 141 | return; 142 | } 143 | 144 | let errs_ = []; 145 | let res = DaisyIO.write_export_diagram(filepath, get_doc().diagram, errs_); 146 | 147 | let message_ = ""; 148 | for(let i = 0; i < errs_.length; i++){ 149 | message_ += sprintf("%s: %s\n", errs_[i].level, errs_[i].message); 150 | } 151 | 152 | if(! res){ 153 | message_dialog('warning', "Export", "Export error.\n" + message_); 154 | return; 155 | }else{ 156 | if(0 !== errs_.length){ 157 | message_dialog('info', "Export", "Export info.\n" + message_); 158 | } 159 | } 160 | 161 | console.log("Export"); 162 | } 163 | 164 | const debug_menu = { 165 | label: 'debug(develop)', 166 | submenu: [ 167 | /* 168 | { 169 | label: 'Reload', 170 | accelerator: 'CmdOrCtrl+R', 171 | click: function (item, focusedWindow) { 172 | if (focusedWindow) focusedWindow.reload() 173 | } 174 | }, 175 | { 176 | label: 'Toggle Full Screen', 177 | accelerator: (function () { 178 | if (process.platform === 'darwin') { 179 | return 'Ctrl+Command+F' 180 | } else { 181 | return 'F11' 182 | } 183 | })(), 184 | click: function (item, focusedWindow) { 185 | if (focusedWindow) { 186 | focusedWindow.setFullScreen(!focusedWindow.isFullScreen()) 187 | } 188 | } 189 | }, 190 | */ 191 | { 192 | label: 'Toggle Developer Tools', 193 | accelerator: (function () { 194 | if (process.platform === 'darwin') { 195 | return 'Alt+Command+I' 196 | } else { 197 | return 'Ctrl+Shift+I' 198 | } 199 | })(), 200 | click: function (item, focusedWindow) { 201 | if (focusedWindow) focusedWindow.toggleDevTools() 202 | } 203 | } 204 | ] 205 | }; 206 | 207 | var template = [ 208 | { 209 | label: '&File', 210 | submenu: [ 211 | { 212 | label: '&Export SVG', 213 | accelerator: 'CmdOrCtrl+Shift+E', 214 | click: function () { 215 | menu_do_export_('svg'); 216 | } 217 | }, 218 | { 219 | label: 'Export PNG', 220 | click: function () { 221 | menu_do_export_('png'); 222 | } 223 | }, 224 | {type: 'separator'}, 225 | { 226 | label: '&Quit', 227 | accelerator: 'CmdOrCtrl+Q', 228 | click: function () { 229 | const {app} = require('electron').remote; 230 | app.quit(); 231 | }, 232 | }, 233 | ] 234 | }, 235 | { 236 | label: '&Edit', 237 | submenu: [ 238 | // キーボード・ショートカット表示用のダミー(js/index.js onloadにて処理) 239 | { 240 | label: '&Cut', 241 | accelerator: 'CmdOrCtrl+X', 242 | selector: "cut:" 243 | }, 244 | { 245 | label: '&Copy', 246 | accelerator: 'CmdOrCtrl+C', 247 | selector: "copy:" 248 | }, 249 | { 250 | label: '&Paste', 251 | accelerator: 'CmdOrCtrl+V', 252 | selector: "paste:" 253 | }, 254 | ] 255 | }, 256 | { 257 | label: '&Help', 258 | role: 'help', 259 | submenu: [ 260 | { 261 | label: 'daisy bell official site', 262 | click: function () { require('electron').shell.openExternal('https://daisy-bell.booth.pm/') } 263 | }, 264 | { 265 | label: 'Donate', 266 | submenu: [ 267 | { 268 | label: 'Donate(Amazon)', 269 | click: function () { require('electron').shell.openExternal('http://amzn.asia/gxaSPhE') } 270 | }, 271 | ] 272 | }, 273 | { 274 | label: 'Bug and Request', 275 | submenu: [ 276 | { 277 | label: 'mailto:michinari.nukazawa@gmail.com', 278 | click: function () { require('electron').shell.openExternal('mailto:michinari.nukazawa@gmail.com') } 279 | }, 280 | { 281 | label: 'twitter:@MNukazawa', 282 | click: function () { require('electron').shell.openExternal('https://twitter.com/MNukazawa') } 283 | }, 284 | ] 285 | }, 286 | { 287 | label: 'GitHub', 288 | click: function () { require('electron').shell.openExternal('https://github.com/MichinariNukazawa/daisy_spread_image') } 289 | }, 290 | {type: 'separator'}, 291 | debug_menu, 292 | {type: 'separator'}, 293 | { 294 | label: '&About', 295 | click: function () { 296 | openAboutWindow({ 297 | icon_path: join(__dirname, 'image/icon.png'), 298 | copyright: 'Copyright (c) 2018 project daisy bell', 299 | package_json_dir: __dirname, 300 | // open_devtools: process.env.NODE_ENV !== 'production', 301 | }); 302 | } 303 | } 304 | ] 305 | } 306 | ] 307 | 308 | function insert_window_menu(){ 309 | template.splice(2, 0, 310 | { 311 | label: 'Window', 312 | role: 'window', 313 | submenu: [ 314 | { 315 | label: 'Minimize', 316 | accelerator: 'CmdOrCtrl+M', 317 | role: 'minimize' 318 | }, 319 | { 320 | label: 'Close', 321 | accelerator: 'CmdOrCtrl+W', 322 | role: 'close' 323 | } 324 | ] 325 | }); 326 | } 327 | 328 | if (process.platform === 'darwin') { 329 | insert_window_menu(); 330 | 331 | var name = require('electron').remote.app.getName() 332 | template.unshift({ 333 | label: name, 334 | submenu: [ 335 | { 336 | label: 'About ' + name, 337 | role: 'about' 338 | }, 339 | { 340 | type: 'separator' 341 | }, 342 | { 343 | label: 'Services', 344 | role: 'services', 345 | submenu: [] 346 | }, 347 | { 348 | type: 'separator' 349 | }, 350 | { 351 | label: 'Hide ' + name, 352 | accelerator: 'Command+H', 353 | role: 'hide' 354 | }, 355 | { 356 | label: 'Hide Others', 357 | accelerator: 'Command+Alt+H', 358 | role: 'hideothers' 359 | }, 360 | { 361 | label: 'Show All', 362 | role: 'unhide' 363 | }, 364 | { 365 | type: 'separator' 366 | }, 367 | { 368 | label: 'Quit', 369 | accelerator: 'Command+Q', 370 | click: function () { 371 | const {app} = require('electron').remote; 372 | app.quit() 373 | } 374 | } 375 | ] 376 | }) 377 | // Window menu. 378 | template[3].submenu.push( 379 | { 380 | type: 'separator' 381 | }, 382 | { 383 | label: 'Bring All to Front', 384 | role: 'front' 385 | } 386 | ) 387 | } 388 | 389 | var menu = Menu.buildFromTemplate(template); 390 | Menu.setApplicationMenu(menu); 391 | 392 | -------------------------------------------------------------------------------- /daisy_spread_image/js/object-util.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class ObjectUtil{ 4 | static deepcopy(obj) 5 | { 6 | /* 7 | let r = {}; 8 | for(let name in obj){ 9 | if(typeof obj[name] === 'object'){ 10 | r[name] = this.deep_clone_(obj[name]); 11 | }else{ 12 | r[name] = obj[name]; 13 | } 14 | } 15 | return r; 16 | */ 17 | 18 | return JSON.parse(JSON.stringify(obj)) 19 | } 20 | 21 | static remove_key(obj, keys) 22 | { 23 | ObjectUtil.removeKey(obj, keys); 24 | } 25 | 26 | static removeKey(obj, keys) 27 | { 28 | if(obj instanceof Array){ 29 | obj.forEach(function(item){ 30 | ObjectUtil.removeKey(item,keys) 31 | }); 32 | } 33 | else if(typeof obj === 'object'){ 34 | Object.getOwnPropertyNames(obj).forEach(function(key){ 35 | if(keys.indexOf(key) !== -1)delete obj[key]; 36 | else ObjectUtil.removeKey(obj[key],keys); 37 | }); 38 | } 39 | } 40 | 41 | static make_member(obj, path, value) 42 | { 43 | return ObjectUtil.makeMember(obj, path, value); 44 | } 45 | 46 | static makeMember(obj, path, value) 47 | { 48 | const keys = path.split('.'); 49 | let o = obj; 50 | for(let i = 0; i < keys.length; i++){ 51 | if(undefined === o || null === o || typeof o !== 'object'){ 52 | return false; 53 | } 54 | 55 | if(! o.hasOwnProperty(keys[i])){ 56 | if(i !== (keys.length - 1)){ 57 | o[keys[i]] = {}; 58 | }else{ 59 | o[keys[i]] = value; 60 | } 61 | } 62 | 63 | o = o[keys[i]]; 64 | } 65 | 66 | return true; 67 | } 68 | 69 | static get_property_from_path(obj, path) 70 | { 71 | return ObjectUtil.getPropertyFromPath(obj, path); 72 | } 73 | 74 | static getPropertyFromPath(obj, path) 75 | { 76 | const keys = (typeof path === 'string')? path.split('.') : [path]; 77 | let o = obj; 78 | for(let i = 0; i < keys.length; i++){ 79 | if(undefined === o || null === o || typeof o !== 'object'){ 80 | return null; 81 | } 82 | if(! o.hasOwnProperty(keys[i])){ 83 | return null; 84 | }else{ 85 | o = o[keys[i]]; 86 | } 87 | } 88 | 89 | return o; 90 | } 91 | }; 92 | 93 | -------------------------------------------------------------------------------- /daisy_spread_image/js/preference.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class Preference{ 4 | static get_filepath(){ 5 | const {app} = require('electron').remote; 6 | const fileex = require('./fileex'); 7 | return fileex.join(app.getPath('userData'), "preference.json"); 8 | } 9 | 10 | static init(){ 11 | const fs = require("fs"); 12 | const fileex = require('./fileex'); 13 | 14 | const filepathDefaultPreference = fileex.join(__dirname, '../resource/default-preference.json'); 15 | console.log(filepathDefaultPreference); 16 | const filepathPreference = Preference.get_filepath(); 17 | let defaultPreference = fileex.read_json(filepathDefaultPreference); 18 | let preference = fileex.read_json(filepathPreference); 19 | //console.log(defaultPreference, preference); 20 | preference = Object.assign(defaultPreference, preference); 21 | 22 | fs.writeFileSync(filepathPreference, JSON.stringify(preference, null, '\t')); 23 | } 24 | 25 | static get_preference(){ 26 | const fileex = require('./fileex'); 27 | 28 | const filepathPreference = Preference.get_filepath(); 29 | return fileex.read_json(filepathPreference); 30 | } 31 | 32 | static delete_preference(){ 33 | const filepath = Preference.get_filepath(); 34 | try{ 35 | fs.unlinkSync(filepath); 36 | } catch (err) { 37 | console.error(filepath); 38 | return "delete error:\n" + err.message; 39 | } 40 | return "success."; 41 | } 42 | 43 | static get_filepath_user_css(){ 44 | const {app} = require('electron').remote; 45 | const fileex = require('./fileex'); 46 | return fileex.join(app.getPath('userData'), "user.css"); 47 | } 48 | 49 | static save_preference_of_keypath(keypath, value){ 50 | const fs = require("fs"); 51 | 52 | let preference = Preference.get_preference(); 53 | 54 | //今回は深い階層は無視する 55 | if(! preference.hasOwnProperty(keypath)){ 56 | console.error(keypath); 57 | } 58 | preference[keypath] = value; 59 | console.log("save keypath:", keypath, value); 60 | 61 | const filepathPreference = Preference.get_filepath(); 62 | fs.writeFileSync(filepathPreference, JSON.stringify(preference, null, '\t')); 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /daisy_spread_image/js/renderer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports.RenderingHandle = class RenderingHandle{ 4 | constructor(elemId) 5 | { 6 | this.draw = null; 7 | this.groups = []; 8 | 9 | this.draw = SVG(elemId).size(0, 0); 10 | this.clear(); 11 | 12 | this.resource = RenderingHandle.generate_resource(); 13 | } 14 | 15 | static generate_resource() 16 | { 17 | let resource = {}; 18 | /* 19 | try{ 20 | const fs = require("fs"); 21 | const path = require('path'); 22 | const filepath = path.join(__dirname, '../image/edge.svg'); 23 | resource.edge_icon_svg = fs.readFileSync(filepath, 'utf8'); 24 | }catch(err){ 25 | console.error(err); 26 | } 27 | */ 28 | return resource; 29 | } 30 | 31 | get_draw() 32 | { 33 | return this.draw; 34 | } 35 | 36 | get_other_group() 37 | { 38 | return this.groups.other_group; 39 | } 40 | 41 | get_root_group() 42 | { 43 | return this.groups.root_group; 44 | } 45 | 46 | get_background_group() 47 | { 48 | return this.groups.background_group; 49 | } 50 | 51 | get_diagram_group() 52 | { 53 | return this.groups.diagram_group; 54 | } 55 | 56 | get_editor_group() 57 | { 58 | return this.groups.editor_group; 59 | } 60 | 61 | get_focus_group() 62 | { 63 | return this.groups.focus_group; 64 | } 65 | 66 | clear() 67 | { 68 | this.groups = []; 69 | this.draw.clear(); 70 | 71 | this.groups.root_group = this.draw.group().addClass('dd__root-group'); 72 | this.groups.background_group = this.get_root_group().group().addClass('dd__background-group'); 73 | this.groups.diagram_group = this.get_root_group().group().addClass('dd__diagram-group'); 74 | this.groups.other_group = this.get_root_group().group().addClass('dd__other-group'); 75 | 76 | this.groups.editor_group = this.get_root_group().group().addClass('dd__editor-group'); 77 | this.groups.focus_group = this.get_editor_group().group().addClass('dd__focus-group'); 78 | } 79 | }; 80 | 81 | module.exports.Renderer = class Renderer{ 82 | static rerendering(rendering_handle, src_diagram, focus, mouse_state, tool_kind) 83 | { 84 | rendering_handle.clear(); 85 | 86 | const deepcopy = function(obj){ 87 | return JSON.parse(JSON.stringify(obj)) 88 | }; 89 | let diagram = deepcopy(src_diagram); 90 | diagram.width = diagram.property.document_width; 91 | diagram.height = diagram.property.document_height; 92 | 93 | if(null === diagram){ 94 | return null; 95 | } 96 | 97 | const diagram_size = { 98 | 'x': diagram.property.document_width , 99 | 'y': diagram.property.document_height, 100 | }; 101 | 102 | const opt = {}; 103 | const svgstr_diagram = Renderer.generate_svgstr_from_diagram(diagram, opt); 104 | rendering_handle.thumbnail_info = { 105 | 'svgstr_diagram': svgstr_diagram, 106 | 'diagram_size': diagram_size, 107 | }; 108 | 109 | 110 | const canvas_scale = diagram.property.canvas_scale_par / 100; 111 | const canvas_info = { 112 | 'canvas_size': { 113 | 'x': diagram.property.document_width * canvas_scale, 114 | 'y': diagram.property.document_height * canvas_scale, 115 | }, 116 | 'diagram_size': diagram_size, 117 | 'scale': canvas_scale, 118 | 'margin': 2, 119 | }; 120 | console.debug(canvas_info, diagram.property.canvas_scale_par); 121 | 122 | Renderer.rendering_canvas_(rendering_handle, svgstr_diagram, canvas_info, focus, mouse_state, tool_kind); 123 | } 124 | 125 | static rendering_thumbnail(rendering_handle, rendering_handle_src, thumbnail_size) 126 | { 127 | rendering_handle.clear(); 128 | 129 | const scale_x = thumbnail_size.x / rendering_handle_src.thumbnail_info.diagram_size.x; 130 | const scale_y = thumbnail_size.y / rendering_handle_src.thumbnail_info.diagram_size.y; 131 | const scale = Math.min(scale_x, scale_y); 132 | const canvas_info = { 133 | 'canvas_size': { 134 | 'x': thumbnail_size.x, 135 | 'y': thumbnail_size.y, 136 | }, 137 | 'diagram_size': rendering_handle_src.thumbnail_info.diagram_size, 138 | 'scale': scale, 139 | 'margin': 2, 140 | }; 141 | console.debug('thumb info', canvas_info); 142 | const svgstr_diagram = rendering_handle_src.thumbnail_info.svgstr_diagram; 143 | Renderer.rendering_canvas_(rendering_handle, svgstr_diagram, canvas_info, null, null, null); 144 | } 145 | 146 | static rendering_canvas_(rendering_handle, svgstr_diagram, canvas_info, focus, mouse_state, tool_kind){ 147 | rendering_handle.get_draw().size( 148 | canvas_info.canvas_size.x + (canvas_info.margin * 2), 149 | canvas_info.canvas_size.y + (canvas_info.margin * 2), 150 | ); 151 | 152 | // diagramの描画サイズ 153 | const diagram_rendering_size = { 154 | 'x': canvas_info.diagram_size.x * canvas_info.scale, 155 | 'y': canvas_info.diagram_size.y * canvas_info.scale, 156 | }; 157 | 158 | // canvas内でdiagramをセンタリング表示する際の位置(左上座標) 159 | const diagram_position = { 160 | 'x': canvas_info.margin + ((canvas_info.canvas_size.x - diagram_rendering_size.x) / 2), 161 | 'y': canvas_info.margin + ((canvas_info.canvas_size.y - diagram_rendering_size.y) / 2), 162 | }; 163 | 164 | rendering_handle.get_diagram_group().svg(svgstr_diagram); 165 | rendering_handle.get_diagram_group().move(diagram_position.x, diagram_position.y); 166 | rendering_handle.get_diagram_group().scale(canvas_info.scale, canvas_info.scale, 0, 0); 167 | /* 168 | Renderer.draw_focus_(rendering_handle, focus); 169 | 170 | Renderer.draw_mouse_state_(rendering_handle, mouse_state); 171 | 172 | Renderer.draw_tool_(rendering_handle, diagram, mouse_state, tool_kind); 173 | */ 174 | // ** frame 175 | { 176 | let background_group = rendering_handle.get_background_group(); 177 | if(null === background_group){ 178 | console.error('bug'); 179 | return; 180 | } 181 | 182 | let rect = { 183 | 'x': diagram_position.x, 184 | 'y': diagram_position.y, 185 | 'width': diagram_rendering_size.x, 186 | 'height': diagram_rendering_size.y, 187 | }; 188 | background_group.rect(rect.width, rect.height) 189 | .move(rect.x, rect.y) 190 | .attr({ 191 | 'stroke': '#ddd', 192 | 'fill-opacity': '0', 193 | 'stroke-width': '2', 194 | }); 195 | } 196 | } 197 | 198 | static groupdrawing_circle_svg_(circle_group, diagram, elem){ 199 | console.debug(diagram.property.magickcircle_dirpath, elem.subfilepath); 200 | 201 | const filepath = path.join(diagram.property.magickcircle_dirpath, elem.subfilepath); 202 | let circleimage_svg = fs.readFileSync(filepath, 'utf8'); 203 | let diagram_group_ = circle_group.group().addClass('dd__circle_group__AA'); 204 | diagram_group_.move(elem.x, elem.y) 205 | diagram_group_.scale(elem.scale, elem.scale) 206 | diagram_group_.skew(elem.skew.x, elem.skew.y) 207 | ; 208 | diagram_group_.svg(circleimage_svg) 209 | .rotate(elem.rotate_degree, 1000 / 2, 1000 / 2) 210 | .attr({ 211 | 'opacity': 1.0, 212 | }); 213 | } 214 | 215 | static generate_svgjsdraw_from_diagram(diagram, opt){ 216 | console.debug("diag", diagram.property.document_width, diagram.property.document_height); 217 | 218 | let dummy_elem = document.createElementNS('http://www.w3.org/2000/svg','svg'); 219 | let draw = SVG(dummy_elem).size(0, 0); 220 | 221 | let root_group = draw.group().addClass('dd__root_group'); 222 | 223 | if(opt.hasOwnProperty('scale')){ 224 | draw.size(diagram.property.document_width * opt.scale, diagram.property.document_height * opt.scale); 225 | root_group.scale(opt.scale, opt.scale); 226 | }else{ 227 | draw.size(diagram.property.document_width, diagram.property.document_height); 228 | } 229 | 230 | if(opt.hasOwnProperty('background_color')){ 231 | let backgroud_group = root_group.group().addClass('dd__background'); 232 | backgroud_group.rect('100%','100%') 233 | .attr({ 234 | 'fill': opt.background_color, 235 | }); 236 | } 237 | 238 | let circle_group = root_group.group().addClass('dd__circle_group'); 239 | 240 | for(let i = 0; i < diagram.diagram_elements.length; i++){ 241 | const diagram_element = diagram.diagram_elements[i]; 242 | console.debug(i, diagram_element); 243 | 244 | switch(diagram_element.kind){ 245 | case 'circle_svg': 246 | Renderer.groupdrawing_circle_svg_(circle_group, diagram, diagram_element); 247 | break; 248 | default: 249 | console.error("bug", i, diagram_element); 250 | alert(diagram_element); 251 | } 252 | } 253 | 254 | return draw; 255 | } 256 | 257 | static generate_svgstr_from_diagram(diagram, opt){ 258 | const draw = Renderer.generate_svgjsdraw_from_diagram(diagram, opt); 259 | return draw.svg(); 260 | } 261 | }; 262 | 263 | -------------------------------------------------------------------------------- /daisy_spread_image/js/version.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class Version{ 4 | static get_name() 5 | { 6 | const Package = require('../package.json'); 7 | return Package.name; 8 | } 9 | 10 | static get_version() 11 | { 12 | const Package = require('../package.json'); 13 | const v = { 14 | "version": Package.version, 15 | }; 16 | return v.version; 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /daisy_spread_image/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const {app, BrowserWindow} = require('electron') 4 | const path = require('path') 5 | const url = require('url') 6 | 7 | // MacOSX 8 | global.sharedObject = {'osx_open_file': null}; 9 | let openFileHandler = function(event, path) { 10 | event.preventDefault(); 11 | global.sharedObject.osx_open_file = path; 12 | }; 13 | app.on('open-file', openFileHandler); 14 | 15 | // Keep a global reference of the window object, if you don't, the window will 16 | // be closed automatically when the JavaScript object is garbage collected. 17 | let win 18 | 19 | function createWindow () { 20 | 21 | // Create the browser window. 22 | win = new BrowserWindow({ 23 | width: 1200, 24 | height: 700, 25 | webPreferences: { 26 | enableRemoteModule: true, 27 | nodeIntegration: true 28 | }, 29 | icon: path.join(__dirname, 'image/icon.png') 30 | }) 31 | 32 | // and load the index.html of the app. 33 | win.loadURL(url.format({ 34 | pathname: path.join(__dirname, 'index.html'), 35 | protocol: 'file:', 36 | slashes: true 37 | })) 38 | 39 | // Open the DevTools. 40 | // win.webContents.openDevTools() 41 | 42 | // Emitted when the window is closed. 43 | win.on('closed', () => { 44 | // Dereference the window object, usually you would store windows 45 | // in an array if your app supports multi windows, this is the time 46 | // when you should delete the corresponding element. 47 | win = null 48 | }) 49 | } 50 | 51 | // This method will be called when Electron has finished 52 | // initialization and is ready to create browser windows. 53 | // Some APIs can only be used after this event occurs. 54 | app.on('ready', createWindow) 55 | 56 | // Quit when all windows are closed. 57 | app.on('window-all-closed', () => { 58 | // On macOS it is common for applications and their menu bar 59 | // to stay active until the user quits explicitly with Cmd + Q 60 | if (process.platform !== 'darwin') { 61 | app.quit() 62 | } 63 | }) 64 | 65 | app.on('activate', () => { 66 | // On macOS it's common to re-create a window in the app when the 67 | // dock icon is clicked and there are no other windows open. 68 | if (win === null) { 69 | createWindow() 70 | } 71 | }) 72 | 73 | // In this file you can include the rest of your app's specific main process 74 | // code. You can also put them in separate files and require them here. 75 | -------------------------------------------------------------------------------- /daisy_spread_image/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "daisy_spread_image", 3 | "version": "0.0.4", 4 | "description": "spread image in image generator", 5 | "main": "main.js", 6 | "dependencies": { 7 | "about-window": "^1.13.4", 8 | "data-uri-to-buffer": "^3.0.1", 9 | "save-svg-as-png": "^1.4.17", 10 | "sprintf-js": "^1.1.2", 11 | "svg.js": "^2.7.1", 12 | "xml-formatter": "^2.4.0" 13 | }, 14 | "devDependencies": { 15 | "electron": "^11.1.1", 16 | "electron-installer-debian": "^3.1.0", 17 | "electron-packager": "^15.2.0", 18 | "intelli-espower-loader": "^1.0.1", 19 | "mocha": "^8.2.1", 20 | "power-assert": "^1.6.1", 21 | "spectron": "^13.0.0" 22 | }, 23 | "scripts": { 24 | "running": "electron .", 25 | "debian_installer_debian": "electron-installer-debian --config ../release/installer_debian_amd64_config.json", 26 | "test": "mocha --require intelli-espower-loader", 27 | "clean": "rm -rf ./release", 28 | "pack:win": "electron-packager . --out=./release/win --platform=win32 --arch=x64 --icon='./image/icon.ico' --ignore='release' --ignore='object/' --ignore='obj/' --ignore='work/' --ignore='test/'", 29 | "pack:osx": "rm -rf ./release/osx/ && electron-packager . --out=./release/osx --platform=darwin --arch=x64 --icon='./image/icon.icns' --ignore='release/' --ignore='object/' --ignore='obj/' --ignore='work/' --ignore='test/'", 30 | "pack:linux": "rm -rf ./release/linux/ && electron-packager . --out=./release/linux --platform=linux --arch=x64 --icon='./image/icon.png' --ignore='release/' --ignore='object/' --ignore='obj/' --ignore='work/' --ignore='test/'", 31 | "testtotest": "mocha test/mocha.js" 32 | }, 33 | "author": "michinari.nukazawa@gmail.com", 34 | "license": "MIT" 35 | } 36 | -------------------------------------------------------------------------------- /daisy_spread_image/resource/circle/MagicCircle_RuneAMN_20141111.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 12 | 15 | 17 | 19 | 22 | 23 | 25 | 27 | 29 | 32 | 35 | 38 | 40 | 43 | 45 | 47 | 48 | 50 | 52 | 55 | 57 | 59 | 61 | 64 | 66 | 68 | 70 | 72 | 74 | 76 | 78 | 80 | 82 | 84 | 87 | 88 | 90 | 91 | 93 | 94 | 96 | 97 | 99 | 103 | 105 | 107 | 108 | 110 | 112 | 114 | 117 | 120 | 123 | 125 | 126 | 128 | 130 | 133 | 136 | 139 | 140 | 141 | 142 | 143 | 145 | 147 | 149 | 150 | 152 | 154 | 155 | -------------------------------------------------------------------------------- /daisy_spread_image/resource/circle/MagicCircle_RuneAMN_20141116.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 27 | 28 | 29 | 31 | 33 | 35 | 38 | 39 | 41 | 43 | 45 | 48 | 51 | 53 | 54 | 56 | 58 | 60 | 61 | 63 | 65 | 68 | 70 | 72 | 74 | 76 | 78 | 80 | 82 | 84 | 86 | 88 | 90 | 92 | 94 | 96 | 99 | 100 | 102 | 103 | 105 | 106 | 108 | 109 | 111 | 115 | 117 | 118 | 119 | 121 | 123 | 125 | 128 | 131 | 133 | 134 | 137 | 139 | 141 | 142 | 143 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /daisy_spread_image/resource/circle/MagicCircle_RuneAMN_20141120.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | 22 | 24 | 26 | 28 | 31 | 32 | 34 | 36 | 38 | 41 | 44 | 46 | 48 | 50 | 52 | 54 | 55 | 57 | 59 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 76 | 78 | 80 | 82 | 84 | 86 | 88 | 90 | 93 | 94 | 96 | 97 | 99 | 100 | 102 | 103 | 105 | 108 | 110 | 112 | 113 | 115 | 117 | 119 | 122 | 125 | 127 | 129 | 130 | 132 | 134 | 137 | 139 | 142 | 144 | 146 | 149 | 151 | 153 | 155 | 156 | 158 | 160 | 161 | 164 | 165 | 168 | 170 | 172 | 174 | 176 | 178 | 180 | 182 | 185 | 187 | 189 | 191 | 193 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | Lorem ipsum dolor sit amet 206 | 207 | consectetur adipisicing elit 208 | 209 | 210 | sed do eiusmod tempor 211 | 212 | incididunt ut labore et dolore 213 | 214 | magna aliqua Ut enim ad minim 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /daisy_spread_image/resource/circle/MagicCircle_RuneAMN_20141121.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 21 | 22 | 23 | 28 | 32 | 33 | Lorem ipsum dolor sit amet consectetur adipisicing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua Ut enim ad 34 | 39 | 43 | 44 | 45 | 46 | 47 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /daisy_spread_image/resource/circle/MagicCircle_RuneAMN_20141122.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 10 | 14 | 18 | 22 | 27 | 30 | 33 | 36 | 40 | 46 | 50 | 54 | 57 | 61 | 65 | 68 | 71 | 73 | 77 | 83 | 88 | 90 | 93 | 97 | 102 | 105 | 110 | 113 | 115 | 120 | 122 | 126 | 130 | 134 | 138 | 141 | 144 | 147 | 150 | 153 | 156 | 159 | 165 | 172 | 177 | 180 | 183 | 185 | 188 | 192 | 196 | 200 | 204 | 208 | 211 | 215 | 218 | 223 | 227 | 231 | 232 | 233 | 234 | 235 | 250 | 251 | 252 | 253 | 256 | 257 | 258 | 259 | 260 | -------------------------------------------------------------------------------- /daisy_spread_image/resource/default-document.daisyspreadimage: -------------------------------------------------------------------------------- 1 | { 2 | "editor_info": { 3 | "application_name": "daisy_spread_image", 4 | "version": "none" 5 | }, 6 | "filetype": "daisy spread image", 7 | "diagram": { 8 | "property": { 9 | "canvas_scale_par": 25, 10 | "document_width": 2400, 11 | "document_height": 1800, 12 | "randomseed_value": 128, 13 | "magickcircle_num": 7, 14 | "magickcircle_source_kind": "BuiltIn", 15 | "magickcircle_source_directory_path": "", 16 | "magickcircle_unique_picking": true, 17 | "magickcircle_not_collision": true, 18 | "magickcircle_imagescale": 0.4, 19 | "magickcircle_randomsize": true, 20 | "magickcircle_randomrotate": true, 21 | "magickcircle_randomskew": false, 22 | "magickcircle_skewdegree": 20 23 | }, 24 | "diagram_elements": [ 25 | ] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /daisy_spread_image/resource/default-preference.json: -------------------------------------------------------------------------------- 1 | { 2 | "magickcircle_source_directory_path": "" 3 | } 4 | -------------------------------------------------------------------------------- /daisy_spread_image/test/mocha.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | describe('Array', function() { 3 | describe('#indexOf()', function() { 4 | it('should return -1 when the value is not present', function() { 5 | assert.equal(-1, [1,2,3].indexOf(4)); 6 | }); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /daisy_spread_image/test/spec.js: -------------------------------------------------------------------------------- 1 | const Application = require('spectron').Application 2 | const assert = require('assert') 3 | const electronPath = require('electron') // Require Electron from the binaries included in node_modules. 4 | const path = require('path') 5 | 6 | describe('Application launch', function () { 7 | this.timeout(10000) 8 | 9 | beforeEach(function () { 10 | this.app = new Application({ 11 | // Your electron path can be any binary 12 | // i.e for OSX an example path could be '/Applications/MyApp.app/Contents/MacOS/MyApp' 13 | // But for the sake of the example we fetch it from our node_modules. 14 | path: electronPath, 15 | 16 | // Assuming you have the following directory structure 17 | 18 | // |__ my project 19 | // |__ ... 20 | // |__ main.js 21 | // |__ package.json 22 | // |__ index.html 23 | // |__ ... 24 | // |__ test 25 | // |__ spec.js <- You are here! ~ Well you should be. 26 | 27 | // The following line tells spectron to look and use the main.js file 28 | // and the package.json located 1 level above. 29 | args: [path.join(__dirname, '..')] 30 | }) 31 | return this.app.start() 32 | }) 33 | 34 | afterEach(function () { 35 | if (this.app && this.app.isRunning()) { 36 | return this.app.stop() 37 | } 38 | }) 39 | 40 | it('shows an initial window', function () { 41 | return this.app.client.getWindowCount().then(function (count) { 42 | assert.equal(count, 1) 43 | // Please note that getWindowCount() will return 2 if `dev tools` are opened. 44 | // assert.equal(count, 2) 45 | }) 46 | }) 47 | }) 48 | -------------------------------------------------------------------------------- /document/image/daisy_spread_image_0.0.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MichinariNukazawa/daisy_spread_image/ca71a9869bece5b9477d40bce8dd085500d63477/document/image/daisy_spread_image_0.0.1.png -------------------------------------------------------------------------------- /release/installer_darwin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # cross build 4 | # host: Ubuntu (Ubutn16.04 LTS amd64) 5 | # target: Win64 6 | # 7 | # Author: michinari.nukazawa@gmail.com 8 | # 9 | 10 | set -eu 11 | set -o pipefail 12 | 13 | trap 'echo "error:$0($LINENO) \"$BASH_COMMAND\" \"$@\""' ERR 14 | 15 | 16 | SCRIPT_DIR=$(cd $(dirname $0); pwd) 17 | ROOT_DIR=${SCRIPT_DIR}/.. 18 | SOURCE_DIR=${ROOT_DIR}/daisy_spread_image 19 | 20 | APP_NAME=$(cat ${SOURCE_DIR}/package.json | grep '"name"' | sed -e 's/.*:.*"\(.*\)".*/\1/g') 21 | 22 | BUILD_DIR=${SOURCE_DIR}/release/osx/${APP_NAME}-darwin-x64 23 | PACKAGE_DIR=${SOURCE_DIR}/release/osx/${APP_NAME}-darwin-x64 24 | RELEASE_DIR=${ROOT_DIR}/release/release 25 | 26 | PACKAGE_POSTFIX= 27 | if [ 1 -eq $# ] ; then 28 | PACKAGE_POSTFIX="-$1" 29 | fi 30 | 31 | SHOW_VERSION=$(cat ${SOURCE_DIR}/package.json | grep '"version"' | sed -e 's/.*:.*"\(.*\)".*/\1/g') 32 | 33 | GIT_HASH=$(git log --pretty=format:'%h' -n 1) 34 | GIT_STATUS_SHORT=$(git diff --stat | tail -1) 35 | EX="" 36 | if [ -n "${GIT_STATUS_SHORT}" ] ; then 37 | EX="develop" 38 | fi 39 | PACKAGE_NAME=${APP_NAME}-macosx-${SHOW_VERSION}${EX}-${GIT_HASH}${PACKAGE_POSTFIX} 40 | 41 | ## build 42 | rm -rf ${BUILD_DIR} 43 | pushd ${SOURCE_DIR} 44 | npm run pack:osx 45 | popd 46 | 47 | 48 | ## packaging 49 | #rm -rf ${PACKAGE_DIR} 50 | #mv ${BUILD_DIR} ${PACKAGE_DIR} 51 | 52 | cp ${ROOT_DIR}/README.md ${PACKAGE_DIR}/ 53 | 54 | pushd ${PACKAGE_DIR} 55 | 56 | rm -f ${RELEASE_DIR}/${PACKAGE_NAME}.zip 57 | mkdir -p ${RELEASE_DIR} 58 | zip -r9 ${RELEASE_DIR}/${PACKAGE_NAME}.zip * 59 | 60 | popd 61 | 62 | -------------------------------------------------------------------------------- /release/installer_debian.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Author: michinari.nukazawa@gmail.com 4 | # 5 | 6 | set -eu 7 | set -o pipefail 8 | 9 | trap 'echo "error:$0($LINENO) \"$BASH_COMMAND\" \"$@\""' ERR 10 | 11 | # cd daisy_spread_image && npm run installer_debian_amd64 12 | # "installer_debian_amd64": "node ./build_linux_x64.js && electron-installer-debian --config ./installer_debian_amd64_config.json", 13 | pushd ../daisy_spread_image/daisy_spread_image 14 | npm run pack:linux 15 | npm run debian_installer_debian 16 | popd 17 | 18 | -------------------------------------------------------------------------------- /release/installer_debian_amd64_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "daisy-spread-image", 3 | "src": "./release/linux/daisy_spread_image-linux-x64/", 4 | "dest": "../release/release/", 5 | "arch": "amd64", 6 | "icon": "image/icon.png", 7 | "categories": [ 8 | "Utility" 9 | ], 10 | "lintianOverrides": [ 11 | "changelog-file-missing-in-native-package" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /release/installer_win32_x64.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # cross build 4 | # host: Ubuntu (Ubutn16.04 LTS amd64) 5 | # target: Win64 6 | # 7 | # Author: michinari.nukazawa@gmail.com 8 | # 9 | 10 | set -eu 11 | set -o pipefail 12 | 13 | trap 'echo "error:$0($LINENO) \"$BASH_COMMAND\" \"$@\""' ERR 14 | 15 | 16 | SCRIPT_DIR=$(cd $(dirname $0); pwd) 17 | ROOT_DIR=${SCRIPT_DIR}/.. 18 | SOURCE_DIR=${ROOT_DIR}/daisy_spread_image 19 | 20 | APP_NAME=$(cat ${SOURCE_DIR}/package.json | grep '"name"' | sed -e 's/.*:.*"\(.*\)".*/\1/g') 21 | 22 | BUILD_DIR=${SOURCE_DIR}/release/win/${APP_NAME}-win32-x64 23 | PACKAGE_DIR=${SOURCE_DIR}/release/win/${APP_NAME}-win32-x64 24 | RELEASE_DIR=${ROOT_DIR}/release/release 25 | 26 | PACKAGE_POSTFIX= 27 | if [ 1 -eq $# ] ; then 28 | PACKAGE_POSTFIX="-$1" 29 | fi 30 | 31 | SHOW_VERSION=$(cat ${SOURCE_DIR}/package.json | grep '"version"' | sed -e 's/.*:.*"\(.*\)".*/\1/g') 32 | 33 | GIT_HASH=$(git log --pretty=format:'%h' -n 1) 34 | GIT_STATUS_SHORT=$(git diff --stat | tail -1) 35 | EX="" 36 | if [ -n "${GIT_STATUS_SHORT}" ] ; then 37 | EX="develop" 38 | fi 39 | PACKAGE_NAME=${APP_NAME}-win64-${SHOW_VERSION}${EX}-${GIT_HASH}${PACKAGE_POSTFIX} 40 | 41 | ## build 42 | rm -rf ${BUILD_DIR} 43 | pushd ${SOURCE_DIR} 44 | npm run pack:win 45 | popd 46 | 47 | 48 | ## packaging 49 | #rm -rf ${PACKAGE_DIR} 50 | #mv ${BUILD_DIR} ${PACKAGE_DIR} 51 | 52 | cp ${ROOT_DIR}/README.md ${PACKAGE_DIR}/ 53 | 54 | pushd ${PACKAGE_DIR} 55 | 56 | rm -f ${RELEASE_DIR}/${PACKAGE_NAME}.zip 57 | mkdir -p ${RELEASE_DIR} 58 | zip -r9 ${RELEASE_DIR}/${PACKAGE_NAME}.zip * 59 | 60 | popd 61 | 62 | --------------------------------------------------------------------------------