スマホやタブレットが増えてきて、Railsアプリでも手書きで書いた絵や図を取り込みたいというような案件があるのではないでしょうか?手書き画像が保存する方法はいろいろありますが、そのひとつをちょっとメモのため残しておきます。特別なgemとかは必要ありません。使うのは HTML5 の canvas だけです。
環境
- Ruby 2.0.0p353
- Rails 4.0.1
- bundler
手順
まず、Rails 環境を作成して足場をつくります。
Terminal
$
$
$
$
$
|
rails new blog --skip-bundle create
create README.rdoc
create Rakefile
create config.ru
create .gitignore
create Gemfile
create app
create app/assets/javascripts/application.js
create app/assets/stylesheets/application.css
create app/controllers/application_controller.rb
create app/helpers/application_helper.rb
create app/views/layouts/application.html.erb
create app/assets/images/.keep
create app/mailers/.keep
create app/models/.keep
create app/controllers/concerns/.keep
create app/models/concerns/.keep
create bin
create bin/bundle
create bin/rails
create bin/rake
create config
create config/routes.rb
create config/application.rb
create config/environment.rb
create config/environments
create config/environments/development.rb
create config/environments/production.rb
create config/environments/test.rb
create config/initializers
create config/initializers/backtrace_silencers.rb
create config/initializers/filter_parameter_logging.rb
create config/initializers/inflections.rb
create config/initializers/mime_types.rb
create config/initializers/secret_token.rb
create config/initializers/session_store.rb
create config/initializers/wrap_parameters.rb
create config/locales
create config/locales/en.yml
create config/boot.rb
create config/database.yml
create db
create db/seeds.rb
create lib
create lib/tasks
create lib/tasks/.keep
create lib/assets
create lib/assets/.keep
create log
create log/.keep
create public
create public/404.html
create public/422.html
create public/500.html
create public/favicon.ico
create public/robots.txt
create test/fixtures
create test/fixtures/.keep
create test/controllers
create test/controllers/.keep
create test/mailers
create test/mailers/.keep
create test/models
create test/models/.keep
create test/helpers
create test/helpers/.keep
create test/integration
create test/integration/.keep
create test/test_helper.rb
create tmp/cache
create tmp/cache/assets
create vendor/assets/javascripts
create vendor/assets/javascripts/.keep
create vendor/assets/stylesheets
create vendor/assets/stylesheets/.keep
cd blogbundle install --path vendor/bundleFetching gem metadata from https://rubygems.org/……….
Fetching gem metadata from https://rubygems.org/..
Resolving dependencies…
Installing rake (10.1.0)
Installing i18n (0.6.5)
Installing minitest (4.7.5)
Installing multi_json (1.8.2)
Installing atomic (1.1.14)
Installing thread_safe (0.1.3)
Installing tzinfo (0.3.38)
Installing activesupport (4.0.1)
Installing builder (3.1.4)
Installing erubis (2.7.0)
Installing rack (1.5.2)
Installing rack-test (0.6.2)
Installing actionpack (4.0.1)
Installing mime-types (1.25.1)
Installing polyglot (0.3.3)
Installing treetop (1.4.15)
Installing mail (2.5.4)
Installing actionmailer (4.0.1)
Installing activemodel (4.0.1)
Installing activerecord-deprecated_finders (1.0.3)
Installing arel (4.0.1)
Installing activerecord (4.0.1)
Using bundler (1.3.1)
Installing coffee-script-source (1.6.3)
Installing execjs (2.0.2)
Installing coffee-script (2.2.0)
Installing thor (0.18.1)
Installing railties (4.0.1)
Installing coffee-rails (4.0.1)
Installing hike (1.2.3)
Installing jbuilder (1.5.2)
Installing jquery-rails (3.0.4)
Installing json (1.8.1)
Installing tilt (1.4.1)
Installing sprockets (2.10.1)
Installing sprockets-rails (2.0.1)
Installing rails (4.0.1)
Installing rdoc (3.12.2)
Installing sass (3.2.12)
Installing sass-rails (4.0.1)
Installing sdoc (0.3.20)
Installing sqlite3 (1.3.8)
Installing turbolinks (1.3.1)
Installing uglifier (2.3.2)
bundle exec rails g scaffold post invoke active_record
create db/migrate/20131203101546_create_posts.rb
create app/models/post.rb
invoke test_unit
create test/models/post_test.rb
create test/fixtures/posts.yml
invoke resource_route
route resources :posts
invoke scaffold_controller
create app/controllers/posts_controller.rb
invoke erb
create app/views/posts
create app/views/posts/index.html.erb
create app/views/posts/edit.html.erb
create app/views/posts/show.html.erb
create app/views/posts/new.html.erb
create app/views/posts/_form.html.erb
invoke test_unit
create test/controllers/posts_controller_test.rb
invoke helper
create app/helpers/posts_helper.rb
invoke test_unit
create test/helpers/posts_helper_test.rb
invoke jbuilder
create app/views/posts/index.json.jbuilder
create app/views/posts/show.json.jbuilder
invoke assets
invoke coffee
create app/assets/javascripts/posts.js.coffee
invoke scss
create app/assets/stylesheets/posts.css.scss
invoke scss
create app/assets/stylesheets/scaffolds.css.scss
bundle exec rake db:migrate== CreatePosts: migrating ====================================================
– create_table(:posts)
-> 0.0010s
== CreatePosts: migrated (0.0011s) ===========================================
|
app/views/posts/_form.html.erb
を開いて次のコードを追加します。このコードが手書き入力部分(canvas)になります。
app/views/posts/_form.html.erb
1
2
3
4
5
|
<canvas id="paper" class="paper" width="400" height="400" data-target="#sign">
ご利用のブラウザではサインは表示できません。
</canvas>
<button type="button" name="clearCanvas" class="clear-canvas">クリア</button>
<input type="hidden" id="sign" name="sign" value="" />
|
app/assets/javascripts
に paint.js.coffee ファイルを作成し、次のコードをコピペします。
app/assets/javascripts/paint.js.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
jQuery ($) ->
screen2client = (e) ->
[px, py] = if e.type.startsWith('touch') then [e.originalEvent.touches[0].clientX, e.originalEvent.touches[0].clientY] else [e.clientX, e.clientY]
rect = e.target.getBoundingClientRect()
{x: px - rect.left, y: py - rect.top}
drawFlag = false
oldX = 0
oldY = 0
$canvas = $('#paper')
$canvas.on 'mousedown touchstart', (e) ->
drawFlag = true
{x, y} = screen2client(e)
[oldX, oldY] = [x, y]
$canvas.on 'mouseup mouseout touchend touchcancel', ->
drawFlag = false
data = $canvas[0].toDataURL()
$($canvas.data('target')).val(data)
$canvas.on 'mousemove touchmove', (e) ->
return unless drawFlag
{x, y} = screen2client(e)
context = $canvas[0].getContext('2d')
context.strokeStyle = '#C71C22'
context.lineWidth = 1
context.beginPath()
context.moveTo(oldX, oldY)
context.lineTo(x, y)
context.stroke()
context.closePath()
oldX = x
oldY = y
e.preventDefault()
return
$('.clear-canvas').on 'click', ->
context = $canvas[0].getContext('2d')
context.clearRect(0, 0, $canvas[0].width, $canvas[0].height)
$($canvas.data('target')).val(null)
|
app/assets/javascript/application.js
を開き、ファイルの最後に次のコードを追加します。
app/assets/javascript/application.js
1
2
3
4
5
|
if (typeof String.prototype.startsWith != 'function') {
String.prototype.startsWith = function(str) {
return this.substring(0, str.length) === str;
}
}
|
最後に、画像データを受け取って画像ファイルにする処理をコントローラに追加します。app/controllers/posts_controller.rb
を開き、def create
に次のコードを追加します。
app/controllers/posts_controller.rb
1
2
3
|
f = Tempfile.new(['sign', '.png'], encoding: Encoding::BINARY)
f.write Base64.decode64(params[:sign].sub('data:image/png;base64,', ''))
f
|
これで、一時ファイルにキャンバスデータを書き込んでファイル化できます。サーバを起動して http://localhost:3000/posts/new
にアクセスして試してみてください。