Задать вопрос
  • Как сделать эффект текста на кривой безье?

    sfi0zy
    @sfi0zy
    Creative frontend developer
    На картинках мы видим эффект, в котором есть только вертикальные смещения букв по ходу движения. Нет никаких поворотов, растяжений, и.т.д. Только сдвиг по одной оси. Это упрощает задачу, сводя ее суть к описанному в соседнем ответе, но дальше вы там куда-то ушли в сторону трансформаций и горы масок. Это все сложно для восприятия и производительность будет оставлять желать лучшего. В контексте JS и 2D-канвасов можно пойти другим, более традиционным, путем:

    1. Определить разумную максимальную длину текста в пикселях.
    2. Сделать канвас этого размера, залить белым.
    3. Нарисовать на нем черный текст стандартным методом, чтобы он занимал 100% ширины. Подгонка текста по ширине - типовая задача, легко гуглится.
    4. Достать содержимое канваса в виде imageData. На этом этапе у нас есть текстура с нарисованным текстом.
    5. Сделать второй канвас, на котором пользователь работает. Залить белым.
    6. Достать его imageData или создать новую под его размер.
    7. Взять кривую в формате x(t), y(t). Пройти циклом по t. Разумный шаг определяется в зависимости от длины кривой на канвасе, он должен давать смещение не больше 1 по x. Для абсолютной надежности можно сделать шаг меньше, и на каждой итерации проверять, сместились ли мы. Своего рода трассировка луча по кривой.
    8. Сопоставить диапазон t и координату u в текстуре с текстом. Проход по t должен логически соответствовать проходу по горизонтали по всей текстуре.
    9. На каждой итерации цикла взять столбец из imageData текстуры с текущим u, скопировать его в imageData рабочего канваса по координатам x, y. Копируем не 1 в 1, а с учетом масштабирования, которое мы уже знаем из соотношений t и u, чтобы сохранить пропорции букв. С учетом наложений вероятно имеет смысл копировать только черное, не перекрашивая черное обратно в белое.
    10. Обновить imageData рабочего канваса.
    11. При обновлении данных повторять от п.6. Вероятно будет хорошей идеей не создавать imageData каждый раз заново, чтобы не перевыделять память под нее каждый раз.

    Очевидно, что тут будут циклы в циклах, что тоже не идеально, хотя оверхед будет заметно меньше, чем у бесконечных вызовов штатных методов канваса для рисований текста и его обрезания. В целом для таких вещей можно было бы использовать webgl, чтобы происходящее с п.6 уже происходило в шейдерах и распараллеливалось. Но вполне вероятно, что и так сойдет.
    Ответ написан
  • Как лучше отобразить создаваемый нажатием div в grid контейнере?

    sfi0zy
    @sfi0zy Куратор тега CSS
    Creative frontend developer
    при нажатии на дату в div недели добавляется div card... есть вариант удобнее?

    С точки зрения CSS будет практично иметь элементы с одинаковым поведением на одном уровне вложенности в HTML. Например неделя, неделя, неделя, карточка, неделя, неделя... Там все, что есть - обычные блоки на всю ширину. Впихивая карточку внутрь недели и размещая ее на одном уровне с числами, мы усложняем себе жизнь. Числа и карточка - это уже действительно разные вещи.

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

    неделя
        числа
            день1
            день2
            деньN
        бронирование
    неделя
        числа
            день1
            день2
            деньN
        бронирование

    При таком подходе на одном уровне будут только недели, на другом - только числа. А посередине - простое разделение компонентов недели на логические части. Это должно быть удобно и с позиции CSS, и из JS. И не нужно будет ничего изобретать.
    Ответ написан
    Комментировать
  • Как запустить VueJs в Docker на Ubuntu 14.04?

    sfi0zy
    @sfi0zy
    Creative frontend developer
    Step 0 : FROM node:12-alpine
    Pulling repository node
    INFO[0002] Error: Status 410 Gone

    что не так

    Если посмотреть, какие там теги и какие Dockerfile-файлы из этого репозитория сейчас актуальны, то мы увидим, что 12 ноды там больше нет. И 14 нет. И 16 нет. Были. А теперь нет. Поэтому они все 410 Gone. Ваш скрипт не может скачать Dockerfile, которого нет, а без него у нас нет инструкций, что делать, и процесс останавливается. Если вы не хотите пользоваться актуальными версиями, а хотите вернуться в прошлое, то вам нужно откатить историю этого репозитория в то время, когда 12 нода там еще была представлена (пару лет назад) и плясать от того Dockerfile, который будет найден там, на свалке истории.
    Ответ написан
  • На каком языке\и каком фреймворке языка лучше написать онлайн-доску? Что-то типа MIRO, или chattern, или sBoard?

    sfi0zy
    @sfi0zy
    Creative frontend developer
    Что-то типа MIRO или chattern

    Это два совершенно разных инструмента.

    Подскажите, по какому пути идти, с чего начать?

    Как и в любом проекте - нужно начать с составления конкретного подробного ТЗ. Произвести анализ конкурентов. Сформировать требования для MVP. Описать сценарии использования. Проанализировать перспективы развития. Оценить ресурсы. Спроектировать систему на самом верхнем уровне. Потом уже смотреть, какие там инструменты на местах подойдут. Причем вероятнее всего реальные сложности начнутся совсем не там, где вы их сейчас ожидаете. Например бесконечный холст для рисования приведет вас к тому, что нужно уметь работать с канвасом и разбираться в алгоритмах рендеринга и оптимизации всего. Это знания в каком-то смысле параллельные языкам и фреймворкам. А если углубляться в функционал того же MIRO, то, скажем, рисование UML-диаграмм потребует разобраться в самой предметной области, в базовой работе с графами. Или, собственно, онлайн. Нужно чтобы это в реальном времени транслировалось? Нужно совместное редактирование с возможностью сделать ctrl-Z? Тут может вырасти целая карусель из сокетов, системы контроля версий и механизмов синхронизации всего. Конкретные языки там - дело десятое. А вот архитектура проекта в целом может быть реально замороченной. Онлайн-доска - понятие очень растяжимое. Много нюансов, про которые лучше подумать заранее.
    Ответ написан
    2 комментария
  • Как перезапустить полностью pixijs?

    sfi0zy
    @sfi0zy Куратор тега JavaScript
    Creative frontend developer
    GL_INVALID_VALUE: Offset overflows texture dimensions.

    Ошибки такого рода в мире WebGL обычно связаны с тем фактом, что мы пытаемся использовать текстуру, но у нас левые ее размеры, и мы, например, пытаемся получать из нее пиксели за ее границами. Искать проблему нужно вокруг этого факта. На сайте PixiJS можно найти описание основ работы с текстурами, и там сказано, что они кешируются. Если мы делаем Texture.from с тем же источником, то получаем не новую текстуру, а ту, которая уже была. Но в вашем коде где-то по дороге меняются размеры. А сама текстура, сам буфер с пикселями, получается старый, закешированный. Это, вполне вероятно, и вызывает несоответствие. Решением должно быть использование метода destroy() у текстуры, чтобы ее уничтожить с концами при переинициализации. Альтернативно у конструктора Texture.from есть второй параметр skipCache, который по идее даст схожий результат.
    Ответ написан
    1 комментарий
  • Обновление света в three.js?

    sfi0zy
    @sfi0zy
    Creative frontend developer
    const light1 = new THREE.PointLight(0xffffff, 0.4); // было
    const light1 = new THREE.PointLight(0xffffff, 1, 0, 0); // стало

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

    Все ровно наоборот. Но чем гадать, лучше посмотреть документацию PointLight, чтобы понять смысл параметров.

    Последний параметр decay, затухание, непосредственно связан как раз с физикой распространения света. Обычно мы стараемся его никогда не трогать, потому что меняя физику мы себе усложняем дальнейшую разработку в 99% случаев. По умолчанию этот параметр равен 2. Не 0.

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

    В подавляющем большинстве случаев достаточно менять только второй параметр - интенсивность. Измеряется в канделах. Реалистичные значения для бытовых источников света - от 0 до нескольких сотен.

    Если у вас с реалистичными значениями получается что-то не то - стоит уточнить размеры объектов. Чтобы физика работала, у нас 1 условная единица пространства WebGL должна соответствовать 1 метру. Если вы случайно сделали себе размер коробки в 600 метров, а не 0.6, то физика могла дать не тот визуальный эффект, который вы ожидали. Позиция камеры на расстоянии в сотни километров от коробки тоже намекает на то, что нужно проверить размеры.
    Ответ написан
  • Как отображать элементы в зависимости от масштаба содержащего их блока?

    sfi0zy
    @sfi0zy
    Creative frontend developer
    Это называется "кластеризация". Типовая задача при работе с картами. Во многих библиотеках для отображения карт решение есть прямо из коробки. Тут не нужно ничего придумывать, можно воспользоваться готовыми алгоритмами.
    Ответ написан
    4 комментария
  • Как назвать классы заказа для паттерна "Состояние"?

    sfi0zy
    @sfi0zy
    Creative frontend developer
    Попробуйте вместо попыток натянуть сову на глобус, а задачу на паттерн, действовать от простого. Пусть заказ бывает бесплатным. У заказа есть флаг "является ли он бесплатным". Мы даже можем воспользоваться возможностями языка и прикрутить какой-то геттер для надежности, чтобы флаг менялся в зависимости от устанавливаемой цены (в примерах условно JS):
    class Order {
        get isFree() { return this.price === 0; }
    }

    Мы можем прям сюда присобачить и оплату, но допустим мы не хотим, чтобы заказ что-то знал об урлах для оплаты. Ему это не надо. Заказ - это список товаров, какой-то статус завершенности, адрес доставки и.т.д. Он про данные, не про процессы. Путь будет обработчик, который может провести заказ как кассир в пятерочке:
    class Order { /* --- */ }
    
    class Сashier {
        proceed(order) {
            const url = order.isFree ? "free url" : "paid url";
            // ...редиректим, проводим оплату, предлагаем пакетик и кофе по акции
        }
    }

    Допустим у нас есть много платежных систем, там все сложно. Инфраструктура - не кассира дело. Ок, дадим ему доступ к адаптеру, который скрывает все за собой и проводит непосредственно оплату.
    class Order { /* --- */ }
    
    class PaymentHandler {
        charge(price) {
            // ...редиректим куда надо, в зависимости от цены и привязанной карты
        }
    }
    
    class Cashier {
        proceed(order) {
            const isSuccess = PaymentHandler.charge(order.price);
            
            if (isSuccess) {
                // заказ прошел
            } else {
                throw new Error('ГААААААЛЯЯЯ ОТМЕЕЕЕНА!!!!');
            }
        }
    }

    Получается четкое разделение ролей. Заказ - про данные, кассир - про процесс, обработчик оплаты - про муть с платежными системами. Возможно, что даже флаг isFree не особо нужен у заказа. И, возможно, что к паттерну "состояние" мы не придем, потому что он в первую очередь решает проблему бесконечного количества комбинаций флагов, но если нет флагов, то нет и проблемы. И.т.д. Развивайте конструкции по мере их естественного появления. Тогда проблем с именованием будет на порядок меньше. Потому что каждое слово в коде отражает какую-то заранее сформированную сущность в алгоритмах в голове.
    Ответ написан
    2 комментария
  • Как заменить под-зависимость на локальную копию?

    sfi0zy
    @sfi0zy Куратор тега JavaScript
    Creative frontend developer
    В package.json есть раздел overrides как раз для таких модификаций зависимостей зависимостей. В примерах в документации там почему-то акцент сделан только на версии пакетов, но можно и полностью заменить пакет на свой, если указать не версию, а локальный путь к нему.
    Ответ написан
  • Реально ли сделать лепестковую диаграмму с градиентом?

    sfi0zy
    @sfi0zy Куратор тега CSS
    Creative frontend developer
    В CSS и SVG есть какие-то градиенты и фильтры, из которых можно что-то такое плюс-минус собрать. Ну и вариации clip-path или масок, чтобы обрезать. Но. Логика формирования градиентов там своя, и она не всегда хорошо подходит под идею, как оно должно выглядеть. Иногда все мешается очень грязно, или какие-то полосы появляются. Не идеально там все. Много костылей нужно подставлять. Если будет нужна какая-то совсем особая интерполяция - то от количества костылей и подпорок тошно станет. Один раз подогнать можно, но с автоматизацией могут возникнуть сложности. А задача построения диаграмм почти всегда требует автоматизации. Это может быть не совсем очевидно с самого начала, но усугубляется там все очень быстро. Так что может иметь смысл сразу брать canvas и делать свою логику под свои хотелки. Там мы нарисовать можем что угодно, мы уже не зависим от браузера и его представлений о градиентах. Это более сложное решение в своей основе, чем подбор градиентов в SVG, но более перспективное в плане его дальнейшего развития.

    Ответ написан
    1 комментарий
  • Почему функция-конструктор срабатывает без `new`, хотя, согласно документации, не должна?

    sfi0zy
    @sfi0zy Куратор тега JavaScript
    Creative frontend developer
    У вас примеры с new и без new не эквивалентны. Вы просто посмотрите, что там на самом деле находится в получаемых переменных:

    function Foo(arg) {
        this.bar = function() {
            return arg;
        };
    
        return this.bar();
    }
    
    const notfoo = Foo('not foo');
    console.log(notfoo); // "not foo", т.е. notfoo - это не новый Foo, это строка текста.
    console.log(notfoo.bar); // undefined, что логично, у стандартной строки никакого bar нет.
    
    const foo = new Foo('foo');
    console.log(foo); // [object Object], т.е. вот это - настоящий новый Foo.
    console.log(foo.bar); // function() { ... }, и метод bar в нем есть.
    console.log(foo.bar()); // "foo"
    Ответ написан
    5 комментариев
  • Тормоза браузера из-за стилей, решение?

    sfi0zy
    @sfi0zy Куратор тега CSS
    Creative frontend developer
    Для начала для нас важно осознать, что у разных фильтров разная вычислительная сложность. Они не все "плохие". Алгоритмы для brightness, grayscale, hue-rotate и других манипуляций с цветом выполняются за O(1) для каждого пикселя. Т.е. нагрузка на железо растет линейно в зависимости от площади элемента на экране. Это не так страшно. А вот фильтры размытия, blur или drop-shadow, имеют сложность где-то в районе O(R^2). Там есть разные варианты оптимизаций, но в среднем мы говорим именно о квадратичной зависимости от радиуса размытия. И это для каждого пикселя. Именно отсюда мы имеем сильные тормоза при попытке что-то большое размыть на пол экрана. Дохлые видеокарты телефонов и ноутбуков не вывозят. Браузеры не умеют такие вещи переиспользовать, так что это переразмытие происходит снова и снова, и мы имеем что имеем.

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

    В контексте верстки тут есть полтора варианта, что можно сделать. Можно рассчитывать такие вычислительно-сложные штуки еще при разработке и загружать в страницу сразу в виде картинок или видео. Это не идеальный вариант, пропорции получаются фиксированные, но иногда подходит. Есть вариант рассчитывать такие штуки в фоне на WebGL. Т.е. мы грузим интерфейс, смотрим какого там все размера получается, и один раз в фоновом режиме генерируем картинки нужного размера и потом плавно показываем. Такой вариант частенько встречается в рекламно-конкурсных проектах, когда за прелоадером в начале скрывается в том числе и такая генеративная история. Тут мы получаем гибкость в плане размеров и хорошую производительность сайта в целом, потому что все операции проходят только один раз, а дальше у нас все переиспользуется в виде обычных картинок. Каких-то принципиально других вариантов у нас пока нет. Только дизайн менять.
    Ответ написан
    3 комментария
  • Почему возникает Ошибка синтаксического анализа XML в браузере firefox?

    sfi0zy
    @sfi0zy
    Creative frontend developer
    Между фактами
    Как видно, на первой позиции в первой строке находится {

    и
    Ошибка синтаксического анализа XML

    есть противоречие. То ли речь идет про XML, то ли про JSON. Надо определиться. Вполне вероятно, что у вас сервер левые заголовки отдает и браузер думает, что там XML, а на самом деле там JSON. Отсюда и ошибка.
    Ответ написан
    Комментировать
  • Почему не добавляется класс следующему элементу после 2 клика?

    sfi0zy
    @sfi0zy Куратор тега JavaScript
    Creative frontend developer
    Метод querySelector возвращает первый элемент, который соответствует селектору. В вашем конкретном случае querySelector('.btn') - это всегда первая кнопка. Тут вопрос не в количестве кликов, а в том, что логика действий завязана на первую кнопку.
    Ответ написан
    Комментировать
  • Как использовать в clip-path: path() проценты (ну и calc)?

    sfi0zy
    @sfi0zy Куратор тега CSS
    Creative frontend developer
    Весь затык у нас тут в том, что CSS не позволяет в рамках path жонглировать единицами измерения. Почему? Люди задавались этим вопросом с самого момента появления path в CSS. Но этот функционал всегда был в SVG. Так что можно добавить маску в SVG (тут у нас размер элемента, условные 100% на 100%, считается за 1 на 1):

    <svg width='0' height='0'>
        <defs>
            <clipPath id='example' clipPathUnits='objectBoundingBox'>
                <path d="M 0 0 a 1 1 0 0 0 1 1 h -1 v -1z"/>
            </clipPath>
        </defs>
    </svg>

    И тогда в CSS уже будет все просто:

    .example {
        clip-path: url(#example);
    }

    Это не идеальный вариант, хотелось бы на чистом CSS, но имеем, что имеем.
    Ответ написан
  • Как реализована анимация SVG элементов (персонажей) в web app?

    sfi0zy
    @sfi0zy Куратор тега JavaScript
    Creative frontend developer
    Могу предположить что что-то на подобии gsap

    Если рассматривать эту задачу в целом, без привязки к конкретному сайту, то это задача по созданию мультиков, в больших количествах, на потоке, в рамках сформированной дизайнерской системы. Делать это за счет фронтендеров - такая себе идея. Сложно всех синхронизировать, очень много накладных расходов. Это будет реально дорогая разработка. И разработчики нужны очень прошаренные по части анимаций, чтобы они были со всей командой дизайнеров на одной волне. Таких днем с огнем не найдешь. Более простой и дешевый подход состоит в том, чтобы этим всем занимались моушен-дизайнеры в рамках экосистемы Lottie. А со стороны разработки мы только интегрировали готовые сценки в сайт или приложение. В последние годы обычно все так и делают. Наш стек здесь не имеет значения, равно как и умения разработчиков.
    Ответ написан
    5 комментариев
  • Можно ли вставить в сайт сделанный на Tilda игру сделанную на Unity Webgl?

    sfi0zy
    @sfi0zy
    Creative frontend developer
    я так понимаю, что встраивать нужно будет с помощью JS. Можно ли такое сделать?

    Официальный help в разделе "for developers" говорит, что вам нужен блок T123. Он позволяет интегрировать HTML, CSS и JS код в страницу.
    Ответ написан
  • Какие возможные варианты сделать такую кнопку, чтобы границы кнопок подстраивались под размер текста внутри?

    sfi0zy
    @sfi0zy Куратор тега CSS
    Creative frontend developer
    Где-то в светлом будущем у нас будет CSS Painting API, с помощью которого можно будет рисовать какие угодно бордеры. А пока можно его сымитировать обычным канвасом (правда придется отступы подгонять под особенности шрифта, но это уже детали, один раз можно сделать):



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

    sfi0zy
    @sfi0zy Куратор тега CSS
    Creative frontend developer
    порядок действий

    1. Сделать 12 элементов.
    2. Расположить элементы по кругу. Тут абсолютное позиционирование В текущих реалиях вечнозеленых браузеров мы можем использовать нативные функции sin() и cos(), чтобы рассчитать, где какие из них должны быть расположены на окружности не покидая мир CSS. Тут никакой магии, геометрия за 7 класс школы.
    3. Естественным образом в расчетах координат появится угол, который можно менять, тем самым поворачивая всю эту карусель. Его можно уже из скриптов менять по той логике, которая нужна для взаимодействия с пользователем.
    4. Обрезать все штатным clip-path.




    Это если говорить про HTML+CSS подход. Он легко делается, но он не идеальный внутри. Есть две проблемы, которые не решатся заменой свойств на другие. Первая - это дергающиеся элементы. В каких-то браузерах это будет проявляться меньше, в каких-то больше. Как ни крути положения элементов округляются до целого количества пикселей по неведомой для нас логике и в движении будут заметны сдвиги в 1px туда-сюда. И производительность - это вторая потенциальная проблема. Двигать много элементов одновременно, особенно если они большие - не всегда хорошо. Не факт, что это будет проблемой в вашем случае, но в теории может стать с учетом всего остального, что будет на странице. Более производительным в теории вариантом будет нарисовать все это на канвасе. Там же можно будет взять под контроль все округления. По крайней мере до какой-то степени. Это следующий шаг, куда можно все это развивать. Логика будет той же самой, но уже на других технологиях. Вероятно вам будет проще начать с варианта на CSS.
    Ответ написан
    5 комментариев
  • Как создать такую фигуру?

    sfi0zy
    @sfi0zy Куратор тега CSS
    Creative frontend developer
    Я думал через clip-path но там нет такой плавности... даже чат джипити не понимает...

    Если уж говорить про clip-path, то там есть clip-source, с помощью которого мы можем поиспользовать clipPath из мира SVG, а в рамках SVG уже можно нарисовать себе любую форму. В разделе синтаксиса и на MDN, и в стандарте, это буквально первый предлагаемый вариант использования clip-path. Не доверяйте вашей чатгопоте. Читайте документацию самостоятельно. Там много интересного.
    Ответ написан
    4 комментария