Генерация пошаговой формы из набора конфигураций

Контекст

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

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

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

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

Создание упрощенного редактора

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

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

Например, в нашем списке деталей и опций могут быть «6-футовая рамка для фотографий» и «3-футовые гвозди», а «3-футовая рамка для фотографий» и «6-футовые гвозди» - нет. .

Если у нас есть статическая форма, мы могли бы разрешить варианты «3 фута» / «6 футов» при выборе «высоты» и «прибивание гвоздей /« рамка рисунка »при выборе« стиля ».

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

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

Эта проблема

Наша проблема заключается в следующем:

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

Конфигурация - это набор пар ключ-значение, например:

const configurations = [
  ["height:10", "color:red"],
  ["height:8", "color:blue"],
  ["height:10", "color:green],
];
const selectedUntilNow = ["height:10"];
getNextOptions(selectedUntilNow, configurations);
// next options should be 'color:red' and 'color:green'

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

Фактически это может быть сведено к проблеме сопоставления префиксов, как мы увидим позже: `Найти все строки, соответствующие заданному префиксу`

Алгоритм

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

Идея состоит в том, чтобы преобразовать конфигурации в упорядоченную строку. Вы можете сделать что-то похожее на строку запроса в запросе GET.

const availableCars = [
 [{color: ‘red’}, {transmission: ‘automatic’}, {style: ‘coupe’}, {condition: ‘used’}],
 [{color: ‘red’}, {transmission: ‘manual’}, {style: ‘coupe’}, {condition: ‘used’}],
 [{color: ‘black’}, {transmission: ‘automatic’}, {style: ‘coupe’}, {condition: ‘new’}],
];
// transforms to:
const availableCars = [
 ‘color=red&transmission=automatic&style=coupe&condition=used’,
 ‘color=red&transmission=manual&style=coupe&condition=used’,
 ‘color=black&transmission=automatic&style=coupe&condition=new’,
];

Предполагается, что желаемый порядок ключей

[color,transmission,style,condition]

Теперь, учитывая префикс, мы хотим найти все подходящие конфиги (в примере - автомобили).

Если цвет уже выбран (предположим, «красный»), моим префиксом будет

‘color=red’

И соответствующие конфигурации

‘color=red&transmission=automatic&style=coupe&condition=used’,
‘color=red&transmission=manual&style=coupe&condition=used’,

Есть много способов выполнить эту проверку. Лучший способ сделать это - использовать структуру данных Trie.

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

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

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

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

Нашими узлами вместо символов будут строки вида attr = value.

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

Практический пример

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

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

Вы можете проверить, как это работает, на https://ergeon.github.io/trie-example/index.html

Также проверьте код на https://github.com/ergeon/trie-example

Заключительные соображения

Итак, здесь есть два контраргумента:

  1. Производительность: в этом случае использование Trie может оказаться излишним. На самом деле этого может быть достаточно для сопоставления списков конфигураций методом перебора, и он будет работать с теми же результатами. Если конфиги очень длинные и их много, мы можем использовать Trie; но старение, вероятно, предназначено для использования в уменьшенном количестве конфигураций.
  2. Порядок атрибутов: порядок шагов может иметь значение. Пользователь сможет сгенерировать все конфигурации с любым порядком шагов, но порядок зависит от цели приложения и является решением UX.

Заключение

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

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