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

    @garbagecollected
    Математика трансформаций очень простая.

    Отрендерить текст на изображение можно используя
    https://opentype.js.org/

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

    Либо использовать эту же библиотеку для того, чтобы получить path data для каждой буквы.

    Если ваша трансформация сводится к аффинным преобразованиям, то можно рассчитывать координаты не каждой точки изображения буквы, а только точки, которые участвуют в path data. Таким образом преобразуя все точки path data вы получите такую же path data, используя которую вы начертаете шрифты в любом месте на любом изображении. Это может дать очень выгодный прирост к производительности (потенциально до 1000х раз). Кроме того, линии path data "рисуется" с правильным расчетом межпиксельного пространства, и вам не надо будет делать ресамплинг, как при работе с изображениями.

    Но рисовать шрифты по безье - это не всегда можно свести к аффинным преобразованиям.

    На верхней иллюстрации у вас используется искажение по оси X: skewX()

    Получить координаты каждой точки можно умножив матрицу с исходными точками на матрицу CTM.
    https://www.w3.org/TR/SVG11/coords.html#TransformM...

    По ссылке выше вы найдёте матрицы с формулами аффинных преобразований в двухмерном пространстве. Матрицы имеют вид (3х3) из которых 6 чисел значимые, 3 числа - статичные (всегда [0, 0, 1]).

    Для 3D-преобразований используются матрицы 4х4 из которых 12 чисел значимые, 4 числа - статичные (всегда [0, 0, 0, 1]):
    https://drafts.csswg.org/css-transforms-2/#mathema...

    Для расчета 3d-трансформаций с учетом перспективы используются матрицы 8х8.

    Рассчитать координаты безье можно функциями (соответственно, квадратичная и кубическая безьё):

    // [p0x, p0x] - are coordinates of origin point
    // [p1x, p1y] - are coordinates of single control point
    // [p2x, p2y] - are coordinates of destination point
    // T - is number of points that needs to draw the curve
    const quadratic = ([p0x,p0y], [p1x,p1y], [p2x,p2y], T = 60) => {
      const x = t => (1 - t)**2 * p0x + 2 * (1 - t) * t * p1x + t**2 * p2x;
      const y = t => (1 - t)**2 * p0y + 2 * (1 - t) * t * p1y + t**2 * p2y;
      return Array.from({ length: T+1 }).map((_, t) => [x(t / T), y(t / T)]);
    };
    
    // [p0x, p0x] - are coordinates of origin point
    // [p1x, p1y] - are coordinates of first control point
    // [p2x, p2y] - are coordinates of second control point
    // [p3x, p3y] - are coordinates of destination point
    // T - is number of points that needs to draw the curve
    const cubic = ([p0x, p0y], [p1x, p1y], [p2x, p2y], [p3x, p3y], T = 60) => {
      const y = t => (1 - t)**3 * p0y + 3 * (1 - t)**2 * t * p1y + 3 * (1 - t) * t**2 * p2y + t**3 * p3y;
      const x = t => (1 - t)**3 * p0x + 3 * (1 - t)**2 * t * p1x + 3 * (1 - t) * t**2 * p2x + t**3 * p3x;
      return Array.from({ length: T+1 }).map((_, t) => [x(t / T), y(t / T)]);
    };


    На нижней иллюстрации вы используются трехмерные искажения.

    Про математику 3D искажении с перспективой можно прочитать тут
    https://www.cs.cmu.edu/~ph/texfund/texfund.pdf
    Там рассматриваются и формулы получения координат на плоскости и ресамплинг (чтобы, например, не было пикселизации шрифтов после трансформации).

    Для перемножений матриц можно использовать функцию

    const multiply = (a, b) => a.map((_, r) => b[0].map((_, c) => a[r].reduce((s,_,i) => s + a[r][i] * b[i][c], 0)));
    Ответ написан
    Комментировать
  • Как отключить swiper-bundle.min.css?

    @garbagecollected
    Используйте @layer для того, чтобы сделать ваши стили с бОльшей специфичностью, чем swiper-bundle
    Ответ написан
    Комментировать
  • Кто отвечает за безопасность VPS?

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

    И php безопасно настроить довольно сложно, если вообще возможно.
    Ответ написан
    Комментировать
  • Как сделать другого цвета выбранный диапазон в календаре?

    @garbagecollected
    675a26843d5ae677134831.png

    Вот, это работает:

    /* #000 - это черные выделеные дни */
    .cell_wrapper.cal_date.current.isSelected:not(:is(.isSelected ~ &)) {
      color: #fff;
      background: #000;
    }
    /* #888888 - это серые выделеные дни  */
    .cell_wrapper.cal_date.current.isSelected ~ .isSelected{
      color: #fff;
      background: #888888;
    }
    
    /* #000 - это черные выделеные дни  */
    .cell_wrapper.cal_date.current.isSelected:not(:has( ~ .isSelected)) {
      color: #fff;
      background: #000;
    }


    Но сам скрипт календаря - кривой!


    Должно быть очевидно хотя бы из-за того, что декабрь 2024 начинается с воскресения. =)
    Ответ написан
    Комментировать
  • Какими средствами сделать веб-интерфейс работы с БД?

    @garbagecollected
    То, что вы хотите, имеет научное название headless cms, например, strapi или ей подобные.
    Ответ написан
    Комментировать
  • Тут сказано поднять простой сервер на node.js. Можно ли такое поднять на Python?

    @garbagecollected
    Вы принимаете слишком близко сердцу. По заданию требуется поднять простой веб-сервер. Не важно на каком языке он написан. Но, если это, например node-static, то запустить его можно порстой командой static с текущей директорией как ROOT_PATH без параметров, либо указать путь к нужной директории ROOT_PATH последним параметром. По умолчанию сервер запустится на интерфейсе 0.0.0.0:8080, указать можно параметром -a <ip>:<port>, например, командой static -a 127.0.0.1:3000 вы запустите веб-сервер на порту 3000. Для этого не нужно знаний языков программирования. Ни python, ни javascript, ни node.js. Просто использовать.

    Что касательно самого python, то инструментов огромное количество. Среди самых старых django. Раньше был очень популярен, но сейчас из-за обилия конкурентов, он теряет актуальность. Я бы не стал начинать новый проект базируясь на django.
    Ответ написан
  • Как в node.js на windows 10 запускать mp3 на фоне?

    @garbagecollected
    require('child_process').execSync(`'C:\Program Files\VideoLAN\VLC\vlc.exe' --qt-start-minimized --play-and-exit --qt-notification=0 "D:\path\to\file.mp3"`);
    Ответ написан
    1 комментарий
  • Библиотека для работы с изображениями?

    @garbagecollected
    Все перечисленные задачи выполняет ImageMagick.
    Для анимации дополнительно будет полезен ffmpeg.
    Есть порт на Java: Jmagick, im4java, ffmpeg-java, xuggler (еще очень полезен код отсюда humble-video).
    Кстати говоря, im4java - это клиент imagemagick через CLI API. Он выглядит заброшенным, но полностью рабочий. В CLI у imagemagick всё стабильно, за многие годы так ничего не поменялось.
    Ответ написан
    6 комментариев
  • Как воспроизвести таблицу из БД Sqlite через JS в таблице HTML?

    @garbagecollected
    Попробуйте sqlime (demo) или duckdb (demo). Может и не понадобится цикл.
    Ответ написан
    Комментировать
  • Как написать регулярку для отделения последней части в роуте?

    @garbagecollected
    если речь идет про nodejs, то можно
    const path = require('path');
    console.log( path.basename( 'http://domain.ru/some/path/123456' ) ); 
      // => '123456'
    console.log( path.dirname( 'http://domain.ru/some/path/123456' ) ); 
      // => 'http://domain.ru/some/path'
    Ответ написан
    Комментировать
  • Как сделать единую точку входа в nginx через auth_basic?

    @garbagecollected
    Можно, но это относительно не безопасно.
    Вам надо заменить все ссылки на host2.ru вот на такой шаблон:
    https://имя:пароль@host2.ru/остальная/ссылка?включая=параметры#можно_с_хешем

    то есть, можно выполнить код:
    <script>
      // Поиск всех ссылок
      document.querySelectorAll('a[href]').forEach(a=>{
        // Если у ссылки определенный хост 
        if(a.hostname == 'host2.ru'){
          const credentials = `имя:пароль`;  // в этом месте заменить имя и пароль на текущие средствами PHP
          // меняем в ссылке https:// на https://имя:пароль@
          a.href = a.href.replace(/^(https?):\/\//,'$1://'+credentials+'@');
        }
      });
    </script>

    Теперь все ссылки не будут требовать логин-пароль
    Ответ написан
    Комментировать
  • Как вызвать метод?

    @garbagecollected
    перед определением метода вставь слово `static`, Например, так:
    class X {  // Класс X
      method1(){  // Обычный метод
        console.log('method1');
      }
      static method2(){  // Статичный метод
        console.log('method2');
      }
    }
    let x = new X(); // Создание объекта x класса X
    
    x.method1();  // Вызов обычного метода через имя объекта
    X.method2();  // Вызов статичного метода через имя класса
    X.prototype.method1(); // Вызов обычного метода через имя класса
    x.__proto__.constructor.method2(); // Вызов статичного метода через имя объекта
    Ответ написан
    Комментировать
  • Как высчитывать и округлять прошедшие месяцы имея дату?

    @garbagecollected
    Пример 1
    let date = new Date();
    date.setDate(date.getDate()-121); // установим дату в текущую минус 121 день
    console.log(date);

    Пример 2
    let ts = Date.now();  // Количество мс, прошедших с 1 января 1970г.
    ts-=121*24*3600*1000; // Вычтем 121 день помножим на 24 часа, помножим на 3600 сек/час, помножим на 1000 мс/сек
    let date = new Date(ts); // Создадим новую дату
    console.log(date);

    Пример 3
    let date = new Date('2022-04-13T14:43:00Z');
    let months  = (Date.now() - date.getTime()) / (30*24*3600*1000);
    console.log(`C момента 2022-04-13 прошло ${months.toFixed(1)} месяцев`);

    Пример 4
    let month;
    
    month = 6.7343423;
    month = Math.round(month * 2)/2;
    console.log(month); // => 6.5
    
    month = 6.8343423;
    month = Math.round(month * 2)/2;
    console.log(month); // => 7
    Ответ написан
  • Браузерная игра + расширение для неё - как добыть информацию для статистики?

    @garbagecollected
    Я бы не стал разбираться в чужих расширениях, я бы написал свой. Начать можно с изучения GreaseMonkey. Каждый скрипт имеет свое хранилище. Скрипт может сохранять нужные блоки информации или события, которые будут на определенных страницах с определенным URL. Далее вы можете прямо на сайте добавить кнопочку, по нажатию которой будет вываливаться вся сохраненная информация, например в формате JSON или каком вам удобнее.
    Ответ написан
    Комментировать
  • Как отключить уведомление об обновлении приложения на весь экран от Play Market?

    @garbagecollected
    Это можно сделать за 5-10 минут программой Lucky Patcher. В целом, программа интуитивно понятная и не требует инструкции по использованию.
    Ответ написан
  • Как повторить сетку с картинки?

    @garbagecollected
    Есть отличный сайт по теме https://labs.jensimmons.com/ (мотай страницу в самый низ)
    Примеры:
    https://labs.jensimmons.com/2016/examples/image-ga...
    https://labs.jensimmons.com/2016/examples/image-ga...
    Ответ написан
    Комментировать
  • Упростить js скрипт?

    @garbagecollected
    // Пусть, список будет в строке разделенной вертикальной чертой
    "contacts|goods|gallery|reviews|screen".split`|`
    // Находим каждый элемент
    .map(data=>document.querySelector(`.blocks__item[data-item="${data}"]`))
    // Вешаем на элементы событие mouseenter
    .forEach(el=>el.addEventListener('mouseenter',e=>{
      // Класс активного элемента надо удалить только у активного элемента
      document.querySelector`.blocks__item.blocks__item--active`.classList.remove`blocks__item--active`;
      // А элементу, вызвавшему это событие надо добавить класс активности
      e.target.classList.add`blocks__item--active`;
      // Еще где-то какому-то элементу присвоим класс, частично формирующийся из атрибута элемента события 
      document.querySelector`.blocks__phone-bg`.className = `blocks__phone-bg blocks__phone-bg--${e.target.getAttribute`data-item`}`;
    });
    // Вот и все!
    Ответ написан