Калькулятор стоимости междугороднего такси на Тильде

Актуально на декабрь 2025 года

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

Мануал подойдёт:

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

Предполагается, что вы уже знакомы с базовой работой в Tilda (создание страницы, блоки, формы), но подробно в JavaScript разбираться не обязательно — готовый код можно просто вставить и слегка адаптировать под свой проект.

Как это работает в общих чертах

Схема работы калькулятора выглядит так:

  1. На странице Тильды есть обычная форма с полями "Откуда" и "Куда".
  2. При вводе названий городов срабатывают подсказки — мы берём их из API Avtodispetcher.
  3. Когда оба поля заполнены, наш JavaScript в фоне вызывает API построения маршрута.
  4. API возвращает расстояние по дорогам (в километрах), а не "по прямой".
  5. JavaScript записывает это расстояние в поле формы "Расстояние".
  6. Встроенный тильдовский блок "Калькулятор" подставляет расстояние из поля в формулу тарифа и считает цену.
  7. Пользователь видит предварительную стоимость поездки, а при отправке формы все данные (города, расстояние, цена) уходят в почту и/или CRM в соответствии с настройками формы Тильды.

Как выглядит результат на Тильде

Как выглядит результат на Тильде

Важный акцент: вся визуальная часть и итоговая формула тарифа находятся на стороне Тильды, а API Avtodispetcher отвечает только за одно — точно посчитать расстояние между указанными городами.

Что понадобится перед началом

1. Тариф Тильды с поддержкой HTML-блоков

Для вставки собственного JavaScript понадобится тариф Tilda, в котором доступен блок "Т123. HTML" или возможность вставить код в настройках страницы (HTML-код для вставки внутрь head). На бесплатном тарифе этого нет, поэтому по состоянию на момент написания статьи описанная ниже схема там не заработает. Проверьте тарифы и возможности Тильды здесь.

2. API-ключ для Avtodispetcher

Калькулятор использует два метода API:

  • подсказки городов (autocomplete),
  • построение маршрута и получение расстояния.

Если API-ключа ещё нет, получить его можно здесь. Без ключа калькулятор работать не будет — запросы к API будут возвращать ошибки авторизации.

Понадобится настроенный CORS для вашего домена — при получении API-ключа сообщите в поддержку домен сайта, чтобы мы добавили его в белый список.

3. Минимальные знания

  • умение редактировать блок формы в Тильде;
  • умение задать полю формы атрибут "name" (это важно для формулы калькулятора);
  • умение вставить готовый JS-код в HTML-блок или в настройки страницы.

Весь JavaScript мы дадим в готовом виде, достаточно будет:

  1. подставить свой API-ключ,
  2. убедиться, что названия полей в форме совпадают с теми, что используются в коде.

Общий план интеграции

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

  1. Создаём на странице Тильды форму заказа поездки.
  2. Настраиваем в этой форме поля:
    • "from_city" — откуда едем;
    • "to_city" — куда едем;
    • "distance" — расстояние в километрах (будет заполняться скриптом);
    • калькулятор Тильды - настраиваем в нем формулу тарифа, например "500 + distance * 35"
    • дополнительные поля: имя, телефон, комментарий и т.п.
  3. Вставляем на страницу JavaScript, который:
    • подключает подсказки городов к полям "from_city" и "to_city";
    • после выбора городов вызывает API маршрута;
    • записывает полученное расстояние в поле "distance".
  4. Проверяем: вводим города, убеждаемся, что расстояние и цена считаются автоматически.

Дальше по шагам мы развернём каждый пункт, начнём с формы.

Подготовка формы на Тильде

1. Создаём форму заказа

Добавьте на страницу стандартный блок формы Тильды (любой, который вам нравится визуально):

  • поле "Откуда" — текстовое поле,
  • поле "Куда" — текстовое поле,
  • поле "Расстояние в км" — текстовое поле,
  • поле "Предварительная стоимость поездки" — с типом "Калькулятор",
  • остальные поля (имя, телефон, комментарий) — по вашему усмотрению.

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

2. Важные имена полей (html-атрибут name)

Последовательно открывайте настройки каждого поля формы и задавайте следующие имена переменных:

  • поле "Откуда" - имя переменной "from_city"
  • поле "Куда" - имя переменной "to_city"
  • поле "Расстояние в км" - имя переменной "distance"

Текстовые подписи, placeholder'ы и внешний вид могут быть любыми — критично именно значение "имя переменной".

3. Почему поле distance должно быть видимым

Логично захотеть спрятать расстояние от пользователя и сделать поле "distance" скрытым: <input type="hidden">. К сожалению, на практике это не работает.

По состоянию на момент написания статьи компонент "Калькулятор" в Тильде не подставляет значения из скрытых полей в формулу. То есть JavaScript сможет записать расстояние в hidden-поле, но калькулятор это значение оттуда не подхватит.

Поэтому поле "distance" должно быть обычным текстовым полем. Чтобы пользователь не мог вручную изменить расстояние и занизить цену, JavaScript сделает поле доступным только для чтения: <input type="text" name="distance" readonly>

В результате:

  • пользователь видит рассчитанное расстояние в километрах (что само по себе полезно);
  • не может его изменить руками;
  • калькулятор корректно использует "distance" в формуле тарифа.

Настройка формы на Тильде

Настройка формы на Тильде

На этом подготовка формы завершена. На следующем шаге мы добавим JavaScript-код, который подключит подсказки городов и автоматический расчёт расстояния через API Avtodispetcher.

Добавляем JavaScript-код на страницу

Теперь нам нужно подключить логику подсказок и расчёта расстояния. Для этого мы вставим на страницу небольшой JavaScript-фрагмент. Он:

  • отслеживает ввод в полях "from_city" и "to_city";
  • подгружает подсказки городов из API;
  • после выбора городов запрашивает маршрут и расстояние по API;
  • записывает расстояние в поле "distance" (в километрах).

В Тильде (на платном тарифе) есть два варианта, куда вставить код:

  1. в блок "Т123. HTML" прямо на нужной странице;
  2. в настройках страницы, в секции "дополнительно", пункт "HTML-код для вставки внутрь head".

Ниже — JavaScript код для вставки. Нужно подставить свой API-ключ вместо "YOUR_BASE64_KEY_HERE".

<script>
(function () {
  'use strict';

  // === НАСТРОЙКИ ===
  const API_BASE = 'https://api.avtodispetcher.ru/v1';
  const API_KEY  = 'YOUR_BASE64_KEY_HERE'; // сюда подставьте свой ключ base64(login:password)

  // Имена полей формы (атрибут name)
  const FIELD_FROM_NAME     = 'from_city';
  const FIELD_TO_NAME       = 'to_city';
  const FIELD_DISTANCE_NAME = 'distance';

  // ID контейнеров для подсказок
  const SUGGESTIONS_FROM_ID = 'from-suggestions';
  const SUGGESTIONS_TO_ID   = 'to-suggestions';

  // === ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ===

  function debounce(fn, delay) {
    let timer = null;
    return function (...args) {
      clearTimeout(timer);
      timer = setTimeout(() => fn.apply(this, args), delay);
    };
  }

  // Получение расстояния между двумя городами
  async function getDistance(from, to) {
    const url = API_BASE + '/route?from=' +
      encodeURIComponent(from) + '&to=' + encodeURIComponent(to);

    const response = await fetch(url, {
      headers: {
        'accept': 'application/json',
        'Authorization': 'Basic ' + API_KEY
      }
    });

    const data = await response.json();

    if (typeof data.kilometers === 'number') {
      return data.kilometers;
    }
    throw new Error('Не удалось определить расстояние');
  }

  // === ОСНОВНАЯ ЛОГИКА ===

  function initCalculator() {
    const fromInput = document.querySelector('input[name="' + FIELD_FROM_NAME + '"]');
    const toInput   = document.querySelector('input[name="' + FIELD_TO_NAME + '"]');
    const distanceField =
      document.querySelector('input[name="' + FIELD_DISTANCE_NAME + '"]');

    if (!fromInput || !toInput || !distanceField) {
      console.warn(
        'Не найдены поля формы: ' +
        FIELD_FROM_NAME + ', ' + FIELD_TO_NAME + ', ' + FIELD_DISTANCE_NAME
      );
      return;
    }

    distanceField.readOnly = true;

    let lastQueryId = 0;

    async function recalcIfReady() {
      const fromCity = fromInput.value.trim();
      const toCity   = toInput.value.trim();

      if (!fromCity || !toCity) {
        distanceField.value = '';
        return;
      }

      const queryId = ++lastQueryId;

      try {
        const distance = await getDistance(fromCity, toCity);

        if (queryId !== lastQueryId) return;

        distanceField.value = distance.toFixed(0);

        distanceField.dispatchEvent(new Event('input',  { bubbles: true }));
        distanceField.dispatchEvent(new Event('change', { bubbles: true }));
      } catch (err) {
        console.error(err);
      }
    }

    const recalcIfReadyDebounced = debounce(recalcIfReady, 400);

    attachCitySuggestions(fromInput, SUGGESTIONS_FROM_ID, recalcIfReadyDebounced);
    attachCitySuggestions(toInput,   SUGGESTIONS_TO_ID,   recalcIfReadyDebounced);
  }

  // Подключаем подсказки
  function attachCitySuggestions(inputEl, suggestionsId, onChangeCallback) {
    let lastQueryId = 0;
    let suppressNextSuggestions = false;

    const wrapper = document.createElement('div');
    wrapper.style.position = 'relative';
    wrapper.style.display  = 'block';
    wrapper.style.width    = '100%';

    inputEl.parentNode.insertBefore(wrapper, inputEl);
    wrapper.appendChild(inputEl);

    const cs = window.getComputedStyle(inputEl);

    const container = document.createElement('div');
    container.id = suggestionsId;

    container.style.position  = 'absolute';
    container.style.top       = cs.height || '100%';
    container.style.left      = '0';
    container.style.right     = '0';
    container.style.zIndex    = '9999';
    container.style.boxSizing = 'border-box';
    container.style.maxHeight = '200px';
    container.style.overflowY = 'auto';
    container.style.display   = 'none';
    container.style.fontFamily = cs.fontFamily;
    container.style.fontSize   = cs.fontSize;
    container.style.lineHeight = cs.lineHeight;
    container.style.backgroundColor =
      (cs.backgroundColor && cs.backgroundColor !== 'rgba(0, 0, 0, 0)')
        ? cs.backgroundColor
        : '#ffffff';
    container.style.borderStyle = cs.borderBottomStyle || 'solid';
    container.style.borderWidth = cs.borderBottomWidth || '1px';
    container.style.borderColor = cs.borderBottomColor || '#000';

    wrapper.appendChild(container);

    async function getCitySuggestionsForInput(query) {
      if (!query || query.length < 2) {
        container.style.display = 'none';
        container.innerHTML = '';
        return;
      }

      const currentId = ++lastQueryId;
      const url = API_BASE +
        '/cities?q=' + encodeURIComponent(query) +
        '&limit=5&onlyCountries[]=RU';

      try {
        const response = await fetch(url, { headers: { 'accept': 'application/json' } });
        const data = await response.json();
        if (currentId !== lastQueryId) return;
        showSuggestionsForInput(data, inputEl, container);
      } catch (err) {
        console.error('Ошибка при запросе городов:', err);
      }
    }

    function showSuggestionsForInput(suggestions, inputEl, container) {
      container.innerHTML = '';

      if (!Array.isArray(suggestions) || suggestions.length === 0) {
        container.style.display = 'none';
        return;
      }

      suggestions.forEach(city => {
        const item = document.createElement('div');
        item.className = 't-descr t-suggestion-item';
        item.style.padding = '10px 12px';
        item.style.cursor  = 'pointer';
        item.textContent   = city;

        item.addEventListener('click', () => {
          suppressNextSuggestions = true;
          inputEl.value = city;
          inputEl.dispatchEvent(new Event('input', { bubbles: true }));
          container.style.display = 'none';
        });

        container.appendChild(item);
      });

      container.style.display = 'block';
    }

    const debouncedInputHandler = debounce((e) => {
      const value = e.target.value;

      if (suppressNextSuggestions) {
        suppressNextSuggestions = false;
      } else {
        getCitySuggestionsForInput(value);
      }

      if (typeof onChangeCallback === 'function') {
        onChangeCallback();
      }
    }, 300);

    inputEl.addEventListener('input', debouncedInputHandler);
  }

  // Старт
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initCalculator);
  } else {
    initCalculator();
  }
})();
</script>
Показать полностью

Вставка JavaScript-кода в блок "Т123. HTML" в Тильде

Вставка JavaScript-кода в Тильде

Настройка калькулятора тарифа в Тильде

Ниже несколько вариантов простых формул тарифа, которые часто используются в практике:

  • Базовый междугородний тариф:
    500 + distance * 35
    где 500 ₽ — стоимость подачи, 35 ₽ — цена за 1 км.
  • Только цена за километр:
    distance * 25
  • Два класса авто (эконом / комфорт):
    Если у вас есть поле с выпадающим списком классов авто, то в нем можно задать коэффициент (или цену за километр) для последующего использования в формуле. Подробнее об использовании выпадающего списка в калькуляторе описано в хелпе Тильды.

На следующем шаге имеет смысл пройтись по чек-листу и проверить, что всё работает: подсказки городов появляются, расстояние считается, цена обновляется, данные приходят в почту.

Чек-лист: проверяем, что всё работает

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

  • На странице есть форма с полями "Откуда", "Куда", "Расстояние в км".
  • Поле "distance" — видимое текстовое поле, а не hidden.
  • JavaScript вставлен либо в HTML-блок, либо в настройки страницы.
  • В JavaScript подставлен ваш реальный API-ключ
  • После загрузки страницы в консоли браузера (F12 → вкладка Console) нет красных ошибок JavaScript.
  • При наборе первых трех-четырех букв в поле "Откуда" появляется выпадающий список городов.
  • Выбор города из списка подставляет название в поле и закрывает список.
  • Аналогично работает поле "Куда".
  • После заполнения обоих полей "Откуда" и "Куда" через секунду-другую в поле "Расстояние в км" появляется число.
  • Число выглядит реалистично (например, "Самара → Воронеж" не равно 5 км).
  • Под формой обновляется значение предварительной стоимости (калькулятор Тильды).
  • При отправке формы заявка успешно уходит (нет красных сообщений об ошибке).
  • В письме/CRM карточке заказа видно:
    • значения полей "from_city" и "to_city";
    • значение "distance" в километрах;
    • итоговую сумму, рассчитанную калькулятором (если вы выводите её как отдельное поле).

Подводные камни Тильды и способы их обойти

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

1. Скрытые поля не работают в калькуляторе

Уже упоминали, но повторим отдельно: на момент написания статьи блок "Калькулятор" в Тильде не использует значения полей типа "hidden" в формулах.

Решение — использовать обычное текстовое поле и пометить его как "readonly". Также можно сделать текстовое поле более "скромным" (меньший шрифт, меньший размер, подпись "для диспетчера", перенос вниз формы и т.п.).

На многих сайтах такси пользователю наоборот полезно видеть рассчитанное расстояние, это повышает доверие к цене.

2. Нельзя надёжно перехватить отправку формы

В Тильде свои внутренние обработчики события "submit" формы. В ряде шаблонов они срабатывают первыми, и отменить отправку формы через ваш JavaScript невозможно.

Поэтому мы сознательно не вмешиваемся в процесс отправки формы:

  • весь расчёт происходит до отправки — на этапе ввода городов;
  • мы просто записываем расстояние в поле "distance", а дальше Тильда делает своё дело.

Это делает интеграцию более устойчивой.

3. Несколько форм на странице

В базовом примере мы ориентируемся на первую форму с полями "from_city", "to_city" и "distance":

const FIELD_FROM_NAME = 'from_city';
const FIELD_TO_NAME = 'to_city';
const FIELD_DISTANCE_NAME = 'distance';

Если на странице несколько форм с похожими полями, имеет смысл:

  • либо ограничиться одной "основной" формой под калькулятор,
  • либо доработать JS так, чтобы каждый его экземпляр работал со "своими" полями.

4. Внешний вид подсказок

В разных шаблонах Тильды поля могут выглядеть по-разному: тёмная тема, большие поля, рамки только снизу и т.п. Чтобы подсказки визуально к ним подходили, скрипт использует getComputedStyle и подстраивает шрифт, фон и рамку под конкретный инпут.

Если в каком-то шаблоне подсказки выглядят "чужеродно", можно:

  • добавить к элементам подсказок собственный CSS-класс и слегка подправить отступы/фон;
  • либо, наоборот, убрать часть автоматических стилей и задать внешний вид вручную.

5. Превью-страницы Тильды могут не работать из-за CORS

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

Это нормальное поведение: в целях безопасности API отвечает только на запросы с заранее разрешённых доменов.

Как решить:

  • публикуйте страницу на вашем реальном домене (даже если это черновик);
  • убедитесь, что ваш домен добавлен в CORS-список в поддержке Avtodispetcher;
  • проверяйте работу калькулятора только на вашем домене, а не в превью Тильды.

После публикации на вашем домене и корректной настройки CORS всё будет работать штатно.

Что дальше

На этом всё необходимое для запуска калькулятора готово: форма на Тильде настроена, JavaScript подставляет расстояние, калькулятор считает цену, а заявка уходит в почту или CRM вместе с городами и километрами.

Дальше вы можете развивать эту схему под свои задачи:

  • добавлять разные тарифы (эконом / комфорт / бизнес);
  • применять надбавки за ночное время, большие группы, ожидание и другие условия;
  • использовать дополнительные переменные и формулы калькулятора Тильды;
  • расширить форму, чтобы она подходила под ваш реальный бизнес-процесс.

Нужна помощь с интеграцией?

Разработчик API

Можно написать напрямую разработчику API - Илье Гуку.

Обсудим задачу, подскажу по запросам и подводным камням интеграции. Кратко опишите проект и где планируете использовать API. Обычно отвечаю в рабочие дни в течение дня.

Telegram: @ilyaguk Email: support@avtodispetcher.ru Форма обратной связи: здесь