API

Сценарии на JavaScript

Если у вас Pro аккаунт и программирование для вас это не пустой звук, вы можете писать сценарии прямо на JavaScript. Это дает более широкие возможности и гибкость, вы не ограничены только теми блоками, которые есть в редакторе блоков, но взаимодействие с туром все равно идет только по API.

Использовать JavaScript можно только на Pro аккаунте.

API одинаковое для использования в сценариях и вставки своего кода для тура. Почитать о нем можно в разделе "API", а здесь мы приведет только общие рекомендации именно для сценариев. 

Скрипт сценария не живет в глобальной области видимости, но мы даем все самое необходимое:

runtime - общая память (словарь) на весь тур или сцену. 

runtime.tour   // общая память на весь тур
runtime.scene  // память текущей сцены
runtime.tour.score = runtime.tour.score || 0
runtime.tour.score += 1
ipano.toast('Очки: ' + runtime.tour.score)

trigger - что запустило сценарий.

utils.log('Запуск сценария', trigger)
if (trigger.type === 'start') {
  ipano.toast('Сценарий запущен при старте сцены')
}
if (trigger.type === 'click') {
  ipano.toast('Сценарий запущен кликом')
  if (trigger.source === 'media') {
    utils.log('Кликнули медиа-точку', {
      pointPk: trigger.pointPk,
      mediaPk: trigger.mediaPk
    })
  }
}
if (trigger.type === 'manual') {
  ipano.toast('Сценарий запущен вручную')
}

utils - функции, необходимые для работы

// utils.log: лог с префиксом сценария
utils.log('Сообщение', { sceneId })
// utils.sleep: пауза, всегда в миллисекундах
await utils.sleep(1000)
// utils.setTimeout: выполнить один раз через N мс
utils.setTimeout(function () {
  ipano.toast('Прошла 1 секунда')
}, 1000)
// utils.setInterval: повторять каждые N мс
utils.setInterval(function () {
  utils.log('tick')
}, 2000)
// Если внутри interval есть await, ставь защиту от наложения запусков
let busy = false
utils.setInterval(async function () {
  if (busy) return
  busy = true
  try {
    utils.log('Делаем долгую задачу')
    await utils.sleep(1500)
  } finally {
    busy = false
  }
}, 1000)
// utils.fetchJson: загрузить JSON
const data = await utils.fetchJson('/api/data.json')
// По умолчанию JSON кешируется. Чтобы всегда грузить свежий:
const freshData = await utils.fetchJson('/api/data.json', {
  cache: false
})
// POST JSON
const result = await utils.fetchJson('/api/check', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ answer: 'A' }),
  cache: false
})
// utils.jsonGetField: взять поле объекта
const title = utils.jsonGetField(data, 'title')
// utils.jsonGetIndex: взять элемент массива
const firstItem = utils.jsonGetIndex(data.items, 0)
// utils.jsonGetPath: взять значение по пути
const name = utils.jsonGetPath(data, 'items[0].name')
// utils.on: подписка на событие
utils.on('scenechange', function (payload) {
  utils.log('Смена сцены', payload)
})
// utils.once: подписка один раз
utils.once('scenechange', function (payload) {
  ipano.toast('Сцена сменилась один раз')
})
// utils.watchObjectVisibility: следить за видимостью объекта "Меня видно"
utils.watchObjectVisibility('interactive:42', function (payload) {
  utils.log('Видимость:', payload.visible)
})
// utils.onObjectEnterView: объект попал в поле зрения
utils.onObjectEnterView('interactive:42', function (payload) {
  ipano.toast('Объект в кадре')
})
// utils.onObjectLeaveView: объект ушел из поля зрения
utils.onObjectLeaveView('interactive:42', function (payload) {
  ipano.toast('Объект не в кадре')
})