3. Экшены, кнопки. Создание заставки панорамы

Работа с krpano. Часть 3: Экшены, кнопки. Создание заставки панорамы.

В данной статье мы продолжим работу над предыдущим проектом. Здесь разберем планарные координаты, составные операторы, экшены и кнопки.

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

Реализуем такую заставку в нашем проекте.

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

Материалы для статьи

Project – файлы проекта krpano,  полученного в предыдущем уроке. Если вы проект создавали самостоятельно,  то  продолжайте работать над своими файлами. Здесь приводятся файлы на основе не зарегистрированной версии krpano.

Intro- файлы, которые потребуются при реализации заставки

buttoncontrol – изображение кнопок разворота панорамы на полный экран и автовращения.

Но перед тем как приступить к созданию этой заставки необходимо рассмотреть вопрос экранных координат.

 

Экранные координаты.

 

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

Помимо сферических координат существуют экранные. Они задаются при помощи координат Х ,Y и показывают расстояние от краев выводимой области панорамы.

По сути в предыдущих статьях мы уже сталкивались с атрибутами X и Y.

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

Возможные значения align: lefttop(установлен по умолчанию), left, leftbottom, top, center, bottom, righttop, right, rightbottom

Уроки по Krpano. Экранные координаты

Ось X направлена направо если в значении атрибута : lefttop(установлен по умолчанию), left, leftbottom, top, center, bottom. Т.е. во всех значениях, где отсутствует слово right.

Ось Y направлена вниз в значениях атрибута: lefttopleft, top, center, righttop, right.  Т.е. везде, где отсутствует слово bottom.

Уроки по Krpano. Экранные координаты

Соответсвенно, если в значении атрибута присутствует слова: right то ось X направлена влево; bottom- ось Y направлена вверх.

Уроки по Krpano. Экранные координаты

 

Реализация заставки

 

Код скрипта krpano, полученного с прошлого проекта:

 <krpano version="1.0.8.14">
 
  <view hlookat="0" vlookat="0" fovtype="MFOV" fov="90" maxpixelzoom="1.0" fovmax="120" limitview="auto" />
  <preview url="panorama.tiles/preview.jpg" />
 
  <image>
    <cube url="panorama.tiles/pano_%s.jpg" />
  </image>
  <plugin name="logo"
    align="righttop"
    y="5"
    x="5"
    url="logo.png"
    alpha="0.5"
    onover="tween(plugin[logo].alpha, 1.0, 0.5)"
    onout="tween(plugin[logo].alpha, 0.5, 0.5)"
    onclick="openurl('http://www.1panorama.ru',  _blank)"
  />
 
  <lensflare name="lf0" set="DEFAULT" visible="true"  ath="-138.7916" atv="-50.7045" size="0.80" blind="0.60" blindcurve="4.00" />
 
</krpano>

Из материалов к уроку скопируйте intro.png и button.png в корень проекта.

Для начала реализуем появления картинки intro.png при старте панорамы. Для этого добавим новый плагин  с элементом intro.png. Плюс к этому сделаем так, чтобы изображение интро плавно появлялось за 1 секунду.

<krpano version="1.0.8.14">
 
  <view hlookat="0" vlookat="0" fovtype="MFOV" fov="90" maxpixelzoom="1.0" fovmax="120" limitview="auto" />
  <preview url="panorama.tiles/preview.jpg" />
 
  <image>
    <cube url="panorama.tiles/pano_%s.jpg" />
  </image>
  <plugin name="logo"
    align="righttop"
    y="5"
    x="5"
    url="logo.png"
    alpha="0.5"
    onover="tween(plugin[logo].alpha, 1.0, 0.5)"
    onout="tween(plugin[logo].alpha, 0.5, 0.5)"
    onclick="openurl('http://www.1panorama.ru',  _blank)"
  />
  <plugin name="intro"
    url="intro.png"
    align="center"
    alpha="0"
    onloaded="tween(plugin[intro].alpha,1,1)"
  />
 
  <lensflare name="lf0" set="DEFAULT" visible="true"  ath="-138.7916" atv="-50.7045" size="0.80" blind="0.60" blindcurve="4.00" />
 
</krpano>

У плагина intro создан атрибут alpha=”0″, и событие onloaded, которое при загрузке плагина изменяет атрибут alpha с 0 до 1 за 1 секунду (подробнее об анимации и событиях описывалось в предыдущей статье).

Теперь если запустить панораму то можно увидеть что изображение интро появилось по центру панорамы

Запуск скрипта krpano

Пока еще не реализована функция закрытия интро. Реализуем  кнопку его закрытия.

 

Создание кнопок в krpano

 

Кнопки в krpano реализуются как обычные плагины. Фактически любой плагин может выступать в качестве кнопки. Что мы видели в предыдущей статье при работе с логотипом.

Т.е. если плагину прописать событие onclick, то элемент плагина, при клике на него, будет вызывать событие – что по сути и является реализации кнопки.

Для каждой кнопки необходимо подготовить изображение для обычного состояния, когда пользователь не нажал на нее  и не навелся мышкой. Это состояние кнопки обычно называют Up.

Также желательно подготовить изображения для состояний over (пользователь навелся мышкой) и down (пользователь нажал на кнопку).

krpano. Состояния кнопок.

Файлы изображение состояний кнопок можно хранить по отдельности, но удобнее их объединить в одно изображение, что и было сделано в файле button.png. Здесь состояния up, over и down расположены последовательно столбиком. Для того чтобы указать krpano какому состоянию соответствует какая часть изображения применяется запись следующего вида:

атрибут состояния=”X|Y|W|H”

Где X,Y – координаты верхнего левого угла прямоугольной части изображения. W,H – его ширина и высота

krpano. Обрезка изображения кнопок.

атрибуты состояния могут быть следующими:

crop – соответсвует состоянию Up

onovercrop= соответсвует состоянию Over

ondowncrop=состоянию Down

На основе этих сведений, и учитывая что высота и ширина кнопки=24px, оформим кнопку в виде плагина

  <plugin name="button"
    url="button.png"
    align="center"
    alpha="0"
    x="150"
    y="-50"
    crop="0|0|24|24"
    onovercrop="0|24|24|24"
    ondowncrop="0|48|24|24"
    onloaded="tween(plugin[button].alpha,1,1)"
  />

Здесь мы описали в частности: выравнивание; координаты относительно центра; атрибуты состояния и реализовали события плавного появления кнопки из непрозрачности.

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

 

Реализация функциональности кнопки

 

Сделаем чтобы кнопка закрывала заставку. По сути можно было добавить в описание плагина button событие вида.

onclick=”tween(plugin[intro].alpha,0,1)”

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

В krpano можно создавать несколько действий, которые будут выполняться набором. В этом случае их необходимо описывать через “;” (в программировании такой набор команд называется составным оператором).

Модифицируем строку.

onclick=”tween(plugin[intro].alpha,0,1); tween(plugin[button].alpha,0,1);

Теперь при нажатие на кнопку, исчезнет изображение интро и сама кнопка.

 

Важно. Часто попервой можно забыть поставить точку с запятой между отдельными командами. Особенно когда запись разбита на несколько строк. Например:

onclick=”tween(plugin[intro].alpha,0,1)

tween(plugin[button].alpha,0,1);”

Отсутствие “;” приведет либо к непредвиденной ошибке, либо какая-то часть кода просто не будет выполняться (при этом krpano не всегда указывает что есть ошибка).

Всегда проверяйте наличие “;”

 

Итак, код скрипта на данный момент у нас следующий:

 
<krpano version="1.0.8.14">
 
  <view hlookat="0" vlookat="0" fovtype="MFOV" fov="90" maxpixelzoom="1.0" fovmax="120" limitview="auto" />
  <preview url="panorama.tiles/preview.jpg" />
 
  <image>
    <cube url="panorama.tiles/pano_%s.jpg" />
  </image>
  <plugin name="logo"
    align="righttop"
    y="5"
    x="5"
    url="logo.png"
    alpha="0.5"
    onover="tween(plugin[logo].alpha, 1.0, 0.5)"
    onout="tween(plugin[logo].alpha, 0.5, 0.5)"
    onclick="openurl('http://www.1panorama.ru',  _blank)"
  />
  <plugin name="intro"
    url="intro.png"
    align="center"
    alpha="0"
    onloaded="tween(plugin[intro].alpha,1,1)"
  />
  <plugin name="button"
    url="button.png"
    align="center"
    alpha="0"
    x="150"
    y="-50"
    crop="0|0|24|24"
    onovercrop="0|24|24|24"
    ondowncrop="0|48|24|24"
    onloaded="tween(plugin[button].alpha,1,1)"
    onclick="tween(plugin[intro].alpha,0,1); tween(plugin[button].alpha,0,1);"
  />
 
  <lensflare name="lf0" set="DEFAULT" visible="true"  ath="-138.7916" atv="-50.7045" size="0.80" blind="0.60" blindcurve="4.00" />
 
</krpano>

 

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

За активность плагина отвечает атрибут enabled, который может принимать значение true (активен), false (неактивен).

Для того чтобы изменить значение переменных (а атрибуты по сути тоже являются переменными) существует функция set()

set(переменная, значение);

Данная функция похожа на tween(), но изменяет значение переменной не за какое-то время, а мгновенно.

Чтобы изменить значение атрибута плагина необходимо написать строку:

set(plugin[intro].enabled, false);

Также надо будет отключить и плагин отвечающий за кнопку.

set(plugin[button].enabled, false);

Получится у нас следующая строка:

onclick="tween(plugin[intro].alpha,0,1); set(plugin[intro].enabled, false); tween(plugin[button].alpha,0,1); set(plugin[button].enabled, false);"

Здесь, по нажатию кнопки мы сразу отключаем плагины кнопки и интро, и плюс к этому плавно уводим изображения плагинов в непрозрачность.

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

Т.е. если строку перевести на человеческий язык – получится нечто подобное:

Запустить анимацию плагина intro, не дожидаясь окончания анимации – сделать плагин intro неактивным, запустить анимацию плагина button, и сразу сделать его неактивным.

Но так как krpano очень быстро обрабатывает строку, то мы видим, что интро и кнопка исчезают одновременно. 
 

Экшены

 

Видно, что длинная строка на событие onclick не сильно удобна для работы. А если бы у нас была бы работа с 10-20 плагинами в событие, то она бы выросла до вообще неимоверных размеров.

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

Для решения таких вопросов в krpano  были введены так называемые экшены (функции).

Набор команд можно вынести в отдельный блок команд (экшен), и потом просто его вызывать обращаясь к имени блока.

Экшены оформляются при помощи тега action:

  <action name="имя_экшена">
    ...
    блок команд
    ...
  </action>

Вызов экшена производится по его имени

имя_экшена();

 

В нашем проекты выведем блок команд из длинной строчки события onclick в экшен hideintro()

  <action name="hideintro">
    tween(plugin[intro].alpha,0,1);
    set(plugin[intro].enabled, false);
    tween(plugin[button].alpha,0,1);
    set(plugin[button].enabled, false);
  </action>

А событие onclick напишем вызов экшена:

onclick=”hideintro();”

Общий вид кода:

<krpano version="1.0.8.14">
 
  <view hlookat="0" vlookat="0" fovtype="MFOV" fov="90" maxpixelzoom="1.0" fovmax="120" limitview="auto" />
  <preview url="panorama.tiles/preview.jpg" />
 
  <image>
    <cube url="panorama.tiles/pano_%s.jpg" />
  </image>
  <plugin name="logo"
    align="righttop"
    y="5"
    x="5"
    url="logo.png"
    alpha="0.5"
    onover="tween(plugin[logo].alpha, 1.0, 0.5)"
    onout="tween(plugin[logo].alpha, 0.5, 0.5)"
    onclick="openurl('http://www.1panorama.ru',  _blank)"
  />
  <plugin name="intro"
    url="intro.png"
    align="center"
    alpha="0"
    onloaded="tween(plugin[intro].alpha,1,1)"
  />
  <plugin name="button"
    url="button.png"
    align="center"
    alpha="0"
    x="150"
    y="-50"
    crop="0|0|24|24"
    onovercrop="0|24|24|24"
    ondowncrop="0|48|24|24"
    onloaded="tween(plugin[button].alpha,1,1)"
    onclick="hideintro();"
  />
 
  <action name="hideintro">
    tween(plugin[intro].alpha,0,1);
    set(plugin[intro].enabled, false);
    tween(plugin[button].alpha,0,1);
    set(plugin[button].enabled, false);
  </action>
 
  <lensflare name="lf0" set="DEFAULT" visible="true"  ath="-138.7916" atv="-50.7045" size="0.80" blind="0.60" blindcurve="4.00" />
 
</krpano>

 
 

Доработка заставки панорамы.

 

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

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

Оформляются они при помощи тега event.

  <events событие="реакция на событие"  />

 

Интересующее нас событие называется onloadcomplete (загрузка панорамы было завершено)

После того как событие произойдет,  необходимо с задержкой 10 сек выполнить закрытие кнопки и заставки, т.е. вызвать уже написанный экшен hideintro().

За отложенный вызов отвечает функция

delayedcall(задержка в сек, имя экшена);

Таким образом полностью событие будет описано следующим образом:

  <events onloadcomplete="delayedcall(10, hideintro() );" />

Общий вид полученного скрипта krpano:

<krpano version="1.0.8.14">
 
  <view hlookat="0" vlookat="0" fovtype="MFOV" fov="90" maxpixelzoom="1.0" fovmax="120" limitview="auto" />
  <preview url="panorama.tiles/preview.jpg" />
 
  <image>
    <cube url="panorama.tiles/pano_%s.jpg" />
  </image>
  <plugin name="logo"
    align="righttop"
    y="5"
    x="5"
    url="logo.png"
    alpha="0.5"
    onover="tween(plugin[logo].alpha, 1.0, 0.5)"
    onout="tween(plugin[logo].alpha, 0.5, 0.5)"
    onclick="openurl('http://www.1panorama.ru',  _blank)"
  />
  <plugin name="intro"
    url="intro.png"
    align="center"
    alpha="0"
    onloaded="tween(plugin[intro].alpha,1,1)"
  />
  <plugin name="button"
    url="button.png"
    align="center"
    alpha="0"
    x="150"
    y="-50"
    crop="0|0|24|24"
    onovercrop="0|24|24|24"
    ondowncrop="0|48|24|24"
    onloaded="tween(plugin[button].alpha,1,1)"
    onclick="hideintro();"
  />
 
  <action name="hideintro">
    tween(plugin[intro].alpha,0,1);
    set(plugin[intro].enabled, false);
    tween(plugin[button].alpha,0,1);
    set(plugin[button].enabled, false);
  </action>
 
  <events onloadcomplete="delayedcall(10, hideintro() );" />
 
  <lensflare name="lf0" set="DEFAULT" visible="true"  ath="-138.7916" atv="-50.7045" size="0.80" blind="0.60" blindcurve="4.00" />
 
</krpano>

 

 

Кнопки полноэкранного режима и автовращения панорамы

 

Теперь реализуем кнопки полноэкранного режима и автовращения панорамы.

Скопируйте в корень проекта krpano файл из папки материалов buttoncontrol.

В файле buttoncontrol.png  располагаются кнопки: развернуть на полный экран, свернуть в оконный режим, включить автовращение, отключить автовращение.

На верхней строке – кнопки в состоянии Up, в нижней Over.

Логика работы кнопок полноэкранного режима следующая:

* Кнопка “открыть на полный экран” и “свернуть в оконный режим” располагаются на одних и тех же координатах.

* Изначально видна только “открыть на полный экран”. Другая невидима.

* При нажатии на нее происходит разворачивание панорамы на весь экран, “открыть на полный экран” становится невидима, а “свернуть в оконный режим” видима.

Логика работы кнопки режима автовращения аналогичный.

Для того чтобы реализовать переход от оконного режима в полноэкранный надо воспользоваться так называемыми глобальными переменными.

В krpano реализовано ряд переменных по умолчанию. Т.е. они “прошиты” внутри движка krpano и хранят значения определенных параметров проигрывания панорамы.

Например:

fullscreen – может иметь значения true (панорама развернута на полный экран), false (панорама находится в оконном режиме)

stagewidth,  stageheight  – в данных переменных хранится значение ширины и высоты окна krpano.

и.д.

На все том же сайте krpano.com можно ознакомиться со всеми глобальными переменными.

Здесь нам потребуется только переменная fullscreen.

Расположим кнопку полноэкранного режима в правом нижнем углу. И пусть при нажатии она исчезает.

Плагин для этой кнопки  будет выглядеть подобным образом:

  <plugin name="openfullscreen"
    url="buttoncontrol.png"
    align="bottomright"
    y="10"
    x="10"
    visible="true"
    crop="0|0|30|30"
    onovercrop="0|30|30|30"
    onclick="set(fullscreen,true); set(plugin[openfullscreen].visible,false) "
  />

Атрибут  visible у плагинов отвечает за видимость элемента плагина. В отличие от alpha оно может принимать значение true(плагин видим) и false (невидим). Когда плагин становится невидимым, он также становится неактивным. Так что в данном случае нет необходимости работать с атрибутом enabled.

Если сейчас запустить панораму, то видно, что кнопка появилась, а при ее нажатии происходит разворачивание панорамы на полный экран. При этом сама кнопка исчезает.

 

Напишем аналогичный плагин для кнопки перехода в оконный режим. Изначально она должна быть невидимой.  При ее нажатии она должна делать кнопку openfullscreen видимой, а сама становиться невидимой. И само собой она должна сбрасывать значение переменной fullscreen в false.

  <plugin name="closefullscreen"
    url="buttoncontrol.png"
    align="bottomright"
    y="10"
    x="10"
    visible="false"
    crop="30|0|30|30"
    onovercrop="30|30|30|30"
    onclick="set(fullscreen,false); set(plugin[openfullscreen].visible,true); set(plugin[closefullscreen].visible,false)"
  />

Также в плагине openfullscreen отредактируем строку отвечающее за событие onclick, чтобы при нажатии openfullscreen  кнопка closefullscreen становилась видимой

  onclick="set(fullscreen,true); set(plugin[openfullscreen].visible,false); set(plugin[closefullscreen].visible,true);"

Теперь если запустить панораму, то видно что кнопки работают как и задумывалось.

 

Реализуем работу кнопок с автовращением панорамы.

В krpano за автовращение отвечает тег autorotate.

Описание тега:

  <autorotate enabled="false" waittime="1.5"  speed="10.0" />

тег имеет 3 атрибута:

enabled – включить (true) или отключить (false) автовращение.

waittime – задержка старта автовращения после того как пользователь самостоятельно повращал панораму.

speed - скорость вращения.

Сначала запустим автовращение при просмотре панорамы. Для этого добавим строку в код:

  <autorotate enabled="true" speed="2.0" />

Теперь после запуска панорамы она начнет автоматически вращаться.

Для того чтобы реализовать кнопки включения\отключения автовращения необходимо на событие onclick прописать изменение значение атрибута enabled у тега autorotate.

У тегов, у которых нет имени (т.е. атрибута name), обращение к атрибуту происходит через “.”

autorotate.enabled

Таким образом чтобы изменить значение атрибута, необходимо написать подобную конструкцию:

set(autorotate.enabled,false);

Напишем плагины включения\отключения автовращения. Логика их работы будет полностью аналогична кнопкам полноэкранного режима.

  <plugin name="offrotate"
    url="buttoncontrol.png"
    align="bottomright"
    y="10"
    x="50"
    visible="true"
    crop="90|0|30|30"
    onovercrop="90|30|30|30"
    onclick="set(autorotate.enabled,false); set(plugin[onrotate].visible,true); set(plugin[offrotate].visible,false);"
  />
  <plugin name="onrotate"
    url="buttoncontrol.png"
    align="bottomright"
    y="10"
    x="50"
    visible="false"
    crop="60|0|30|30"
    onovercrop="60|30|30|30"
    onclick="set(autorotate.enabled,true); set(plugin[onrotate].visible,false); set(plugin[offrotate].visible,true);"
  />

 

Общий вид полученного скрипта krpano:

<krpano version="1.0.8.14">
 
  <view hlookat="0" vlookat="0" fovtype="MFOV" fov="90" maxpixelzoom="1.0" fovmax="120" limitview="auto" />
  <preview url="panorama.tiles/preview.jpg" />
 
  <image>
    <cube url="panorama.tiles/pano_%s.jpg" />
  </image>
 
  <autorotate enabled="true" speed="2.0" />
  <plugin name="logo"
    align="righttop"
    y="5"
    x="5"
    url="logo.png"
    alpha="0.5"
    onover="tween(plugin[logo].alpha, 1.0, 0.5)"
    onout="tween(plugin[logo].alpha, 0.5, 0.5)"
    onclick="openurl('http://www.1panorama.ru',  _blank)"
  />
  <plugin name="intro"
    url="intro.png"
    align="center"
    alpha="0"
    onloaded="tween(plugin[intro].alpha,1,1)"
  />
  <plugin name="button"
    url="button.png"
    align="center"
    alpha="0"
    x="150"
    y="-50"
    crop="0|0|24|24"
    onovercrop="0|24|24|24"
    ondowncrop="0|48|24|24"
    onloaded="tween(plugin[button].alpha,1,1)"
    onclick="hideintro();"
  />
  <plugin name="openfullscreen"
    url="buttoncontrol.png"
    align="bottomright"
    y="10"
    x="10"
    visible="true"
    crop="0|0|30|30"
    onovercrop="0|30|30|30"
    onclick="set(fullscreen,true); set(plugin[openfullscreen].visible,false); set(plugin[closefullscreen].visible,true);"
  />
  <plugin name="closefullscreen"
    url="buttoncontrol.png"
    align="bottomright"
    y="10"
    x="10"
    visible="false"
    crop="30|0|30|30"
    onovercrop="30|30|30|30"
    onclick="set(fullscreen,false); set(plugin[openfullscreen].visible,true); set(plugin[closefullscreen].visible,false);"
  />
  <plugin name="offrotate"
    url="buttoncontrol.png"
    align="bottomright"
    y="10"
    x="50"
    visible="true"
    crop="90|0|30|30"
    onovercrop="90|30|30|30"
    onclick="set(autorotate.enabled,false); set(plugin[onrotate].visible,true); set(plugin[offrotate].visible,false);"
  />
  <plugin name="onrotate"
    url="buttoncontrol.png"
    align="bottomright"
    y="10"
    x="50"
    visible="false"
    crop="60|0|30|30"
    onovercrop="60|30|30|30"
    onclick="set(autorotate.enabled,true); set(plugin[onrotate].visible,false); set(plugin[offrotate].visible,true);"
    />
 
  <action name="hideintro">
    tween(plugin[intro].alpha,0,1);
    set(plugin[intro].enabled, false);
    tween(plugin[button].alpha,0,1);
    set(plugin[button].enabled, false);
  </action>
 
  <events onloadcomplete="delayedcall(10, hideintro() );" />
 
  <lensflare name="lf0" set="DEFAULT" visible="true"  ath="-138.7916" atv="-50.7045" size="0.80" blind="0.60" blindcurve="4.00" />
 
</krpano>

В данном уроке были показаны примеры написания экшенов, реализации кнопок и заставок. В следующей статье будут рассмотрены вопросы реализации виртуального тура состоящего из нескольких 3d-панорам. А также как можно организовать код тура, чтобы его можно было просто редактировать.


Продолжение:

4. Виртуальный тур. Создание точек перехода

Все уроки по работе с krpano


Остались вопросы?


Задайте их на форуме