Статьи

Движущиеся картинки с Синатрой, часть III

mp_sinatra

В части I мы сделали небольшое приложение для чтения jpegs из каталога. Во второй части мы создали загрузчик, чтобы мы могли добавлять новые картинки. Все, что осталось сделать, это сделать слайд-шоу.

Давайте оживим картинки

В этой статье Крейг рассказывает о CSS-анимации. Давайте используем описанную там технику ключевых кадров , чтобы изменить непрозрачность изображений. Начните с непрозрачности с нуля и перейдите к единице, чтобы показать изображение во всей его красе.

Мы хотим, чтобы изображение отображалось в течение примерно пяти секунд и проходило по ним бесконечно. Вот пример кода.

img#animation1 { -webkit-animation:cycleone 5s infinite; } @-webkit-keyframes cycleone { 0% {opacity:0} /* not visible */ 10% {opacity:1} /* visible */ 90% {opacity:1} /* visible */ 100% {opacity:0} /* not visible */ } 

В продолжительности анимации 100 ключевых кадров. Разделите это на то, как долго мы хотим отображать картинку, и мы узнаем, сколько ключевых кадров нам нужно в секунду.

 100 keyframes / 5 seconds = 20 keyframes 20 keyframes = 1 second 

В приведенном выше примере кода происходит увеличение на полсекунды, изображение отображается в течение четырех секунд, а затем исчезает на полсекунды.

Что происходит, когда есть две или семь картин?

Время для математики

Если мы хотим 5 секунд для каждого изображения и у нас есть 2 изображения, как бы вы нашли правильный процент ключевых кадров?

Мы можем разделить исходные проценты ключевых кадров на количество картинок, чтобы определить, какие проценты ключевых кадров необходимы для установки первой картинки.

 * 0/2 => 0 * 10/2 => 5 * 90/2 => 45 * 100/2 => 50 

На втором рисунке нам нужно начать с того места, где мы остановились ранее.

 * 0/2 + 50 => 50 * 10/2 + 50 => 55 * 90/2 + 50 => 95 * 100/2 + 50 => 100 

Время стать реальностью.

Давайте создадим новый файл, чтобы программно выяснить это. Я позвоню в мое слайд-шоу.rb

 $ touch slideshow.rb 

Нам нужно написать CSS для каждого тега img . Каждое изображение будет иметь идентификатор, который можно использовать в цикле для записи CSS.
Узнайте общую продолжительность слайд-шоу. Две картинки и каждая картинка по пять секунд.

 puts 2 * 5 

Если вы запустите это, вы увидите ответ. 10. Дух. Да, это общая продолжительность, но это не сильно помогает. Как насчет этого кода?

slideshow.rb

 PICTURES = 2 for i in 1..PICTURES puts "img\#animation" + i.to_s + " {" puts " -webkit-animation:cycle" + i.to_s + " " + ( 2 * 5 ).to_s + "s infinite;" puts "}" end 

Запустите его и посмотрите, что мы получим.

 $ ruby slideshow.rb img#animation1 { -webkit-animation:cycle1 10s infinite; } img#animation2 { -webkit-animation:cycle2 10s infinite; } 

Здорово. Теперь все, что нам нужно сделать, это написать правила анимации. Помните, нам нужно добавить последний номер первого цикла ко второму циклу

slideshow.rb

 PICTURES = 2 @offset = 0 for i in 1..PICTURES puts "img\#animation" + i.to_s + " {" puts " -webkit-animation:cycle" + i.to_s + " " + ( 2 * 5 ).to_s + "s infinite;" puts "}" puts "@-webkit-keyframes cycle" + i.to_s + " {" puts " #{@offset}% {opacity:0}" puts " " + (10 / PICTURES + @offset).to_s + "% {opacity:1}" puts " " + (90 / PICTURES + @offset).to_s + "% {opacity:1}" puts " " + (100 / PICTURES + @offset).to_s + "% {opacity:0}" puts "}" #reset offset @offset = 100 / PICTURES + @offset end 

Мы добавили переменную для обработки смещения для следующего цикла.

Давай, беги.

 $ ruby slideshow.rb img#animation1 { -webkit-animation:cycle1 10s infinite; } @-webkit-keyframes cycle1 { 0% {opacity:0} 5% {opacity:1} 45% {opacity:1} 50% {opacity:0} } img#animation2 { -webkit-animation:cycle2 10s infinite; } @-webkit-keyframes cycle2 { 50% {opacity:0} 55% {opacity:1} 95% {opacity:1} 100% {opacity:0} } 

Неплохо. Он делает то, что мы хотим, но я думаю, что это нужно очистить. Во-первых, мы жестко запрограммировали продолжительность, поэтому переведите ее в постоянную. Может быть, мы должны перейти к этим методам тоже. Да, я придирчив

slideshow.rb

 PICTURES = 2 SLIDEDURATION = 5 @offset = 0 def slideShowDuration (PICTURES * SLIDEDURATION).to_s end def setIDs i a = "img\#animation" + i.to_s + " {\n" a = a + " -webkit-animation:cycle" + i.to_s + " " + slideShowDuration + "s infinite;\n" a = a + "}" puts a end def animation i a = "@-webkit-keyframes cycle" + i.to_s + " {\n" a = a + " #{@offset}% {opacity:0}\n" a = a + " " + (10 / PICTURES + @offset).to_s + "% {opacity:1}\n" a = a + " " + (90 / PICTURES + @offset).to_s + "% {opacity:1}\n" a = a + " " + (100 / PICTURES + @offset).to_s + "% {opacity:0}\n" a = a + "}" puts a # increase the offset @offset = 100 / PICTURES + @offset end for i in 1..PICTURES setIDs i animation i end 

При запуске вы должны увидеть тот же вывод, что и раньше. Измените константы и перезапустите файл. Обратите внимание на процент и изменение продолжительности.

Связывая все вместе

В файле main.rb мы отображаем картинки, просматривая их по очереди.

 <% @pictures.each do |picture| %> <img src="<%= picture.sub!(/public\//, '') %>" /> <% end %> 

Нам нужно добавить селектор идентификатора к ним. В файле slideshow.rb мы использовали анимацию img # , Идите вперед и закодируйте это.

 <% @pictures.each_with_index do |picture, i| %> <img id="animation<%= i %>" src="<%= picture.sub!(/public\//, '') %>" /> <% end %> 

Я использовал .each_with_index, чтобы легко добавлять числа к идентификаторам для тегов изображений.

Ничего не теряй.

Помните файл slideshow.rb, который мы написали? Давайте свяжем это с этим. У нас там была пара констант, и одну из них необходимо заменить переменной. Я заменил PICTURES на @pictureslength . Я также удалил петлю внизу.

Если мы оставим это так, у нас будут проблемы. @offset экземпляра @offset никогда не инициализируется. Поскольку у nil нет метода #+ мы получим ошибку. nil can't be coerced into Fixnum Мы должны правильно инициализировать @offset.

 def initialize @offset = 0 end 

Вот что у меня есть для слайдшоу.рб

 SLIDEDURATION = 5 def initialize @offset = 0 end def slideShowDuration (@pictureslength * SLIDEDURATION).to_s end def setIDs i a = "img\#animation" + i.to_s + " {\n" a = a + " -webkit-animation:cycle" + i.to_s + " " + slideShowDuration + "s infinite;\n" a = a + "}" a end def animation i a = "@-webkit-keyframes cycle" + i.to_s + " {\n" a = a + " #{@offset}% {opacity:0}\n" a = a + " " + (10 / @pictureslength + @offset).to_s + "% {opacity:1}\n" a = a + " " + (90 / @pictureslength + @offset).to_s + "% {opacity:1}\n" a = a + " " + (100 / @pictureslength + @offset).to_s + "% {opacity:0}\n" a = a + "}" # increase the offset @offset = 100 / @pictureslength + @offset a end 

Вернувшись в файл @pictureslength вы должны установить для переменной @pictureslength длину изображений.

 get '/' do @pictures = load_pictures @pictureslength = @pictures.length erb :index end 

Давайте посмотрим на шаблон @@index . Нам нужно добавить наш CSS к нему. После тега title добавьте следующий код:

 <style> <% @pictures.each_with_index do |picture, i| %> <%= setIDs i %> <% end %> <% @pictures.each_with_index do |picture, i| %> <%= animation i %> <% end %> </style> 

Не забывайте, что main.rb теперь требует файл slideshow.rb . Идите дальше и добавьте это вверху файла.

Теперь, если вы запустите приложение, картинки исчезают и исчезают?

Сделайте его лучше с помощью CSS.

Поскольку это слайд-шоу, мы хотим видеть только одну фотографию за раз. Мы можем установить непрозрачность на ноль для всех изображений, и переходы заставят их появиться. Изображения также должны быть в верхней части страницы и ширины окна браузера. Ох, и хороший темный фон

 html, body { background-color: #333; margin:0; padding:0; } img { position: absolute; width: 100%; opacity:0 } 

Это делает все это. Поместите это в индексную страницу в начале вашего раздела style .

main.rb

 require 'sinatra' require './slideshow' def load_pictures Dir.glob("public/slideshow_pictures/*.{jpg,JPG}") end get '/' do @pictures = load_pictures @pictureslength = @pictures.length erb :index end get '/upload' do erb :upload end post "/upload" do File.open('public/slideshow_pictures/' + params['file'][:filename], "w") do |f| f.write(params['file'][:tempfile].read) end "uploaded." end __END__ @@index <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="user-scalable=yes, width=device-width" /> <title>Moving Pictures</title> <style> html, body { background-color: #333; margin:0; padding:0; } img { position: absolute; width: 100%; opacity:0 } <% @pictures.each_with_index do |picture, i| %> <%= setIDs i %> <% end %> <% @pictures.each_with_index do |picture, i| %> <%= animation i %> <% end %> </style> </head> <body> <% @pictures.each_with_index do |picture, i| %> <img id="animation<%= i %>" src="<%= picture.sub!(/public\//, '') %>" /> <% end %> </body> </html> @@upload <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="user-scalable=yes, width=device-width" /> <title>Upload Moving Pictures</title> </head> <body> <form action="/upload" enctype="multipart/form-data" method="post"> <label for="file">File to upload:</label> <input id="file" type="file" name="file"> <input id="submit" type="submit" name="submit" value="Upload picture!"> </form> </body> </html> . require 'sinatra' require './slideshow' def load_pictures Dir.glob("public/slideshow_pictures/*.{jpg,JPG}") end get '/' do @pictures = load_pictures @pictureslength = @pictures.length erb :index end get '/upload' do erb :upload end post "/upload" do File.open('public/slideshow_pictures/' + params['file'][:filename], "w") do |f| f.write(params['file'][:tempfile].read) end "uploaded." end __END__ @@index <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="user-scalable=yes, width=device-width" /> <title>Moving Pictures</title> <style> html, body { background-color: #333; margin:0; padding:0; } img { position: absolute; width: 100%; opacity:0 } <% @pictures.each_with_index do |picture, i| %> <%= setIDs i %> <% end %> <% @pictures.each_with_index do |picture, i| %> <%= animation i %> <% end %> </style> </head> <body> <% @pictures.each_with_index do |picture, i| %> <img id="animation<%= i %>" src="<%= picture.sub!(/public\//, '') %>" /> <% end %> </body> </html> @@upload <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="user-scalable=yes, width=device-width" /> <title>Upload Moving Pictures</title> </head> <body> <form action="/upload" enctype="multipart/form-data" method="post"> <label for="file">File to upload:</label> <input id="file" type="file" name="file"> <input id="submit" type="submit" name="submit" value="Upload picture!"> </form> </body> </html> 

Когда в последний раз мы проводили тесты? Как вы думаете, они пройдут?

 $ ruby test/test.rb Run options: --seed 42735 # Running tests: .... Finished tests in 0.073608s, 54.3419 tests/s, 81.5129 assertions/s. 4 tests, 6 assertions, 0 failures, 0 errors, 0 skips 

Уф. Позвольте запустить приложение и просматривать все различные этапы в прямом эфире

Теперь у нас есть приложение, которое может загружать изображения и просматривать их в виде слайд-шоу.

Давайте рассмотрим, что мы сделали в этой серии.

  • Чтение файлов из каталога.
  • Ограничить типы файлов.
  • Структура папок по умолчанию для приложения Sinatra.
  • Создайте наши собственные сообщения об ошибках.
  • Как написать плохой тест.
  • Посмотрите, существуют ли файлы.
  • Удалить файлы.
  • Включите другие файлы.
  • Анимация и ключевые кадры в CSS.

Надеюсь, вам понравилась эта серия и вы узнали что-то о Sinatra, Ruby и / или CSS