Skip to content

ADagen/scatter-plot

Repository files navigation

Scatter plot

Онлайн демо: https://adagen.github.io/scatter-plot/

Задача

Реализовать ĸомпоненту для отображения scatter plot (википедия) по входным данным, отрисовать на ней точĸи и линию тренда, полученного линейной аппроĸсимацией.

Входные данные

type Point = {
   x: number;
   y: number;
}

type APIResponse = {
    points: Point[];
    title: string;
    xTitle?: string;
    yTitle?: string;
}

Требования

  • React, Typescript, Storybook (опционально)
  • Двухмерная диаграмма, отрисованная с помощью SVG
  • Дизайн произвольный, пример уĸазан ниже.
  • Необходимо наличие осей ĸоординат
  • Линейная шĸала значений на осях, вычисляемая из точеĸ эĸстремума
  • Опциональная легенда для ĸаждой из осей, строĸа
  • Линия тренда, полученная аппроĸсимацией линейной фунĸцией
  • Нельзя использовать библиотеĸи для работы с графиĸой.

Реализация

Сборка

Для сборки/компиляции использован webpack с babel и плагином для тайпскрипта, стандартный tsc использовался только для проверки ошибок (с опцией noEmit). Для управлением сайдэффектами использована redux-saga.

yarn start

Запускает webpack-dev-server для локальной разработки. Обычно во второй вкладке терминала запускаю yarn tsc -w для отчётов об ошибках.

yarn build

Собирает статику в dist для проверки, можно использовать локально для проверки, а также используется в workflow Github Actions: при пуше в master основного репозитория происходит автоматическая сборка и деплой в gh-pages.

Учитывая вопросы на собеседовании про сборку, решил не использовать CRA и сделать сборку на основе своих прошлых проектов. Скрипты сборки написаны на js, для запуска используется babel-node. Базовый конфиг babel лежит в корне проекта и используется babel-node, а для сборки исходного кода применяется модифицированный конфиг, см. build-tools/babel-loader.webpack.config.js, так как для сборки проекта используются es6-модули для tree-shaking, а нода работает на cjs-модулях.

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

Интерфейс

Три кнопки над диаграммой вызывают сценарии загрузки готовых датасетов (датасеты добавлены в репозиторий, но по кнопке загружаются http-запросом). Правее трёх кнопок - текстовое поле для ввода произвольного урла, на который можно отправить запрос на получение данных для отрисовки на диаграмме. Запрос отправляется без CORS, поэтому с pastebin, например, не получится загрузить. Зато получится с гитхаба.

Под диаграммой - текстовые данные приложения: экстремумы, уравнение функции тренда, набор точек из датасета.

Отрисовка диаграммы

Для управлением отрисовки и преобразования мировых координат в экранные используется стек трансформаций (SVG атрибуты вместо CSS-трансформаций, так как Edge только с 17-й версии поддерживает CSS-трансформации для SVG). Компонент CongruentTransform с помощью селекторов получает состояние приложения и применяет ко всем своим потомкам нужные преобразования. Далее точки и линия тренда могут рисоваться с мировыми координатами. Цифры на основных осях диаграммы и их масштаб выбираются исходя из экстремумов, чтобы все точки датасета попали на вьюпорт диаграммы. Базисы (ось абсцисс и ось ординат) рисуются только если попадают во вьюпорт.

Точки улучшения

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

  1. Вышел babel@7.8.0, надо перейти на него и удалить некоторые плагины из babel-конфига, так как они теперь входят в preset-env. Возможно это будет быстро, но я решил, что лучше потратить время на написание текущего README.md.
  2. Уменьшить связность компонентов и dataLayer. Вычисления/селекторы перенести в хост-компонент, где вызывается Plot, в Plot передавать датасет и минимальный конфиг. Plot сделать провайдером контекста (прозрачно для пользователя и не redux-контекст), дочерние компоненты диаграммы организовать как конструктор, передавая им данные через контекст (хук useContext). Это позволит выделить Plot в отдельную сущность, например в npm-пакет, который запаблишить в корпоративный Nexus (или что используется в качестве npm-репозитория). В children накидывать компоненты, например Plot.Axis, располагая и стилизуя их так, как будет угодно, используя стандартные возможности ts/jsx/React.
  3. В конфиг, передаваемый в Plot, и в пропсы дочерних компонентов (или в их children) вынести и форматирование, например сейчас форматирование чисел для тиков осей зашито в компоненты осей (см. numberFormatter).
  4. Storybook. Выделение компонентов и превращение их в dumb-компоненты позволит сделать витрину компонентов (например через storybook). Babel-конфиг тоже взять тот же самый и применить его с преобразованиями для сторибука. Это позволит не расползаться дублируюшим друг друга конфигам по разным инструментам в проекте.
  5. Добавить линтер. Мне одному это не критично, но в команде без этого никак. Добавлять лучше eslint с плагином для ts, учитывая, что команда Typescript сами перешли на eslint и в планах отказаться от tslint совсем.
  6. Посмотреть на redux-utils и возможно заменить им текущий unionize. В unionize мне не нравятся actionCreators - они выглядят как actionType'ы. Привычный мне react-create-reducer (паттерн из доки к ридаксу) внезапно имеет ts-тайпинги для actions и actionCreators, не совместимые с FSA и с redux-saga, поэтому пришлось искать замену. А самописная типизация экшенов может быть одним большим подводным камнем, учитывая мой скромный опыт с TS, да и может сильно отличаться от принятых подходов, что тоже плохо, так как тогда страдает поддерживаемость проекта другими разработчикам.
  7. Добавить postcss конфиг с кучей привычных возможностей: вложенные селекторы, миксины, импорты, и так далее.
  8. Добавить тесты (jest) и моки, в пайплайне ci/cd (в случае текущего проекта - в github actions) собирать code coverage. Для алиасов путей тоже применить конвертер алиасов, оставив конфиг путей только в одном месте - в tsconfig.
  9. Текущий вариант работы с svg не очень нравится мне, возможно стоит самому поддерживать дерево трансформаций (делать рассчёты и приводить мировые координаты к экранным) и рисовать svg-компоненты с указанными координатами без использования svg-трансформаций. Потребует значительно больше кода. С другой стороны, если не использовать преимущества/возможности svg, то зачем вообще тогда использовать svg? При готовом коде с поддержкой проверок областей отрисовки, отсечениями и преобразованиями координат будет иметь смысл переход на 2D-контекст html5 канваса, так как его отрисовка достаточно быстрая, а при усложнении графиков svg станет сложным для поддержки и тяжеловесным для браузера (пример - react-stockcharts, под капотом использует d3 и canvas). С учётом того, что webgl сейчас широко распространён в браузерах, то вполне можно посмотреть и на 2D-рендеринг через шейдеры.
  10. Проверить работу на старых браузерах и legacy-бандла. Вообще не проверял это. А в коде точно есть места, которые потребуют полифилов.
  11. Причесать сборку. Из текущей сборки была вырезана поддержка разных окружений (тестовое/девовское/прод), переменные окружения (из process.env, устанавливаемые через конфиг), поддержка SSR. Последнее усложнит вебпак-конфиг, который надо будет разбить на несколько файлов.
  12. SSR. Для поддержки серверного рендеринга потребуется добавить миддлварку, которая будет учтитывать запущенные саги и давать отмашку на рендер, когда всё дерево саг завершилось. Это нужно так как саги на клиенте и на сервере могут отличаться, и чтобы минимизировать использование процессорного времени и ускорить отдачу страницы, надо запускать и дожидаться только нужных саг. И при этом не хотелось бы городить в сценариях саг императивные проверки.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published