В части 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