Ответы пользователя по тегу JavaScript
  • Какие есть способы по кадрам рисовать видео в canvas?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    А вот пример работы с видео в canvas – там налету меняют фон.

    Т.е. из AfterEffects выводите как обычное mp4 / h264 видео.
    Ответ написан
  • Зачем писать tooltipElem = null;?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    document.onmouseout = function(e) {
      if (tooltipElem) {
        tooltipElem.remove();
        tooltipElem = null;
      }
    };


    Чтобы при следующем событии mouseout условие if (tooltipElem) не проходило и не выполнялся лишний раз tooltipElem.remove()
    Ответ написан
    Комментировать
  • Как создать такую паутинку на канвасе?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Вот пример на D3js – интерактивный, реагирует на мышку. Реализация на SVG, но можно переписать и на canvas, если это так важно.

    index.html
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/ >
    		<title>Smoothed Radar Chart</title>
    
    		<!-- Google fonts -->
    		<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,300" rel='stylesheet' type='text/css'>
    		<link href='https://fonts.googleapis.com/css?family=Raleway' rel='stylesheet' type='text/css'>
    
    		<!-- D3.js -->
    		<script src="https://d3js.org/d3.v4.min.js" charset="utf-8"></script>
    		<script src="https://d3js.org/d3-path.v1.min.js" charset="utf-8"></script>
    		<script src="radarChart.js" charset="utf-8"></script>
    		<style>
    			body {
    				font-family: 'Open Sans', sans-serif;
    				font-size: 11px;
    				font-weight: 300;
    				fill: #242424;
    				text-align: center;
    				text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff, 0 -1px 0 #fff;
    				cursor: default;
    			}
    
    			.legend {
    				font-family: 'Raleway', sans-serif;
    				fill: #333333;
    			}
    		</style>
    	</head>
    	<body>
    		<div class="radarChart" style="display: inline-flex;"></div>
    		<div class="radarChart2" style="display: inline-flex;"></div>
    		<script>
    			//////////////////////////////////////////////////////////////
    			//////////////////////// Set-Up //////////////////////////////
    			//////////////////////////////////////////////////////////////
    
    			var margin = { top: 50, right: 80, bottom: 50, left: 80 },
    				width = Math.min(700, window.innerWidth / 4) - margin.left - margin.right,
    				height = Math.min(width, window.innerHeight - margin.top - margin.bottom);
    
    			//////////////////////////////////////////////////////////////
    			////////////////////////// Data //////////////////////////////
    			//////////////////////////////////////////////////////////////
    
    			var data = [
    				{ name: 'Allocated budget',
    					axes: [
    						{axis: 'Sales', value: 42},
    						{axis: 'Marketing', value: 20},
    						{axis: 'Development', value: 60},
    						{axis: 'Customer Support', value: 26},
    						{axis: 'Information Technology', value: 35},
    						{axis: 'Administration', value: 20}
    					]
    				},
    				{ name: 'Actual Spending',
    					axes: [
    						{axis: 'Sales', value: 50},
    						{axis: 'Marketing', value: 45},
    						{axis: 'Development', value: 20},
    						{axis: 'Customer Support', value: 20},
    						{axis: 'Information Technology', value: 25},
    						{axis: 'Administration', value: 23}
    					]
    				}
    			];
    
    			//////////////////////////////////////////////////////////////
    			////// First example /////////////////////////////////////////
          ///// (not so much options) //////////////////////////////////
    			//////////////////////////////////////////////////////////////
    			var radarChartOptions = {
    			  w: 290,
    			  h: 350,
    			  margin: margin,
    			  levels: 5,
    			  roundStrokes: true,
    				color: d3.scaleOrdinal().range(["#26AF32", "#762712"]),
    				format: '.0f'
    			};
    
    			// Draw the chart, get a reference the created svg element :
    			let svg_radar1 = RadarChart(".radarChart", data, radarChartOptions);
    
    			//////////////////////////////////////////////////////////////
    			///// Second example /////////////////////////////////////////
    			///// Chart legend, custom color, custom unit, etc. //////////
    			//////////////////////////////////////////////////////////////
    			var radarChartOptions2 = {
    			  w: 290,
    			  h: 350,
    			  margin: margin,
    			  maxValue: 60,
    			  levels: 6,
    			  roundStrokes: false,
    			  color: d3.scaleOrdinal().range(["#AFC52F", "#ff6600"]),
    				format: '.0f',
    				legend: { title: 'Organization XYZ', translateX: 100, translateY: 40 },
    				unit: '$'
    			};
    
    			// Draw the chart, get a reference the created svg element :
    			let svg_radar2 = RadarChart(".radarChart2", data, radarChartOptions2);
    		</script>
    	</body>
    </html>


    radarChart.js
    Ответ написан
  • Как делать регулярные выражения javascript?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    const re = /jsInterface.event\("user=(\d+);level/;
    let playerId;
    const scripts = document.querySelectorAll('script');
    for (let i = 0; i < scripts.length; i++) {
      const match = scripts[i].innerText.match(re);
      if (match) {
        playerId = +match[1];
        break;
      }
    }
    
    console.log(playerId)  // 4180878
    Ответ написан
    Комментировать
  • Задачка с нахождением анаграмм в массиве?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    как можно улучшить данный код

    Избежать лишних действий.

    Например, незачем на каждом шаге снова разбивать и сортировать исходное слово – достаточно сделать это один раз:
    function anagrams(word, words) {
        const sample = word.split('').sort().join('');
        return words.filter(function (e) {
            return e.split('').sort().join('') === sample;
        })
    }


    Нет смысла проверять неподходящие по длине слова.
    function anagrams(word, words) {
        const length = word.length;
        const sample = word.split('').sort().join('');
        return words.filter(w => w.length === length)
            .filter(function (e) {
                return e.split('').sort().join('') === sample;
            })
    }


    P.S. я вот такое решение отправил. Сравнить длину. Привести к lowercase. Запоминать позиции, в которых найден очередной символ и дальше искать после этой позиции (если будут повторы этого же символа). Как только какой-то символ не найден – всё, не совпали.
    Код
    // write the function isAnagram
    var isAnagram = function(test, original) {
      const length = original.length;
    
      if (length !== test.length) return false;
    
      const A = test.toLowerCase();
      const B = original.toLowerCase();
      const dict = {};
    
      for (let i=0, char, pos; i < length; i++) {
        char = A[i];
        pos = B.indexOf(char, +dict[char]);
        if (!~pos) return false;
        dict[char] = pos + 1;
      }
    
      return true;
    };
    Ответ написан
    Комментировать
  • Можно ли сделать сетеры для методов массива?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Может, переопределить метод на экземпляре?
    var a = [];
    a.push = function() {
      Array.prototype.push.apply(this, arguments);
      // todo
      console.log("QnA.habr");
    }
    
    a.push(5); // QnA.habr
    a.toString() // Array [ 5 ]
    Ответ написан
    Комментировать
  • Как проверить, что переданный параметр это функция?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    typeof будет равен "function" и для Object, String, Date, например — что не входит в ваши планы.

    С другой стороны, если весь код ваш, то достаточно проверять на не-пустоту
    callback && callback();

    Библиотека UnderscoreJS так определяет, функция ли аргумент:
    Object.prototype.toString.call(callback) === '[object Function]'
    и для вас можно так:
    callback  &&  Object.prototype.toString.call(callback) === '[object Function]'  &&  callback();
    Ответ написан
  • Кто может пояснить код?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Вызов inBetween(3, 6) возвращает не строку, не число, а функкцию.

    Можно длиннее записать:
    var daFunc = inBetween(3, 6); // daFunc это функция
    
    arr.filter(daFunc);

    Почти1 то же, что:
    var daFunc = function() {
      console.log(arguments);
    }
    
    arr.filter(daFunc);
    1«Почти» — потому, что контекст тут другой будет. Всякие a и b не будут определены.

    Или:
    function daFunc() { console.log(arguments); }
    
    arr.filter(daFunc);

    Или:
    arr.filter( function() { console.log(arguments); });


    В общем, arguments там никакой не внешний / родительский / фильтрованный, а свой собственный.
    С чем вызвали — то и получили. Вызвали в фильтре – аргументы фильтровские и получили.
    Ответ написан
    Комментировать
  • Самый лучший по точности бесплатный сервис предоставляющий API для определения местоположения?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Может, Google Geolocation API посмотреть?

    Сам не пробовал. Уточните, в каких масштабах можно бесплатно пользоваться.
    Ответ написан
    Комментировать
  • Как парсить элемент из другого сайта?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Незачем что-то парсить. ipinfo.io предоставляет API, есть бесплатный план (до 50 тыс. запросов в месяц)

    Например, с помощью jQuery, без авторизации можно получить IP, страну:
    $.get("https://ipinfo.io", function(response) {
      console.log(response.ip, response.country);
    }, "jsonp")


    Response содержит больше полей:
    {
      "ip": "134.209.xxx.xxx",
      "city": "Clifton",
      "region": "New Jersey",
      "country": "US",
      "loc": "40.8344,-74.1377",
      "org": "AS14061 DigitalOcean, LLC",
      "postal": "07014",
      "timezone": "America/New_York",
      "readme": "https://ipinfo.io/missingauth"
    }
    Ответ написан
    9 комментариев
  • Как в html вывести переменную из js?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    У вас же там просто строка текста собирается, ну..
    '<label class="component-input-checkbox-label" for="">' + html.data['name'] + '</label>\n' +
    Ответ написан
    1 комментарий
  • Как записать это циклом?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    В исходном варианте с var переменная i в любых вызовах навешанных функций имеет последнее своё значение из цикла, равное длине experimentElem.

    Замените var на let:
    for (let i = 0; i < experimentElem.length; i++) {

    старый ответ
    Попробуйте так:
    [...experimentElem].forEach((el, i) => {
      el.addEventListener('mouseenter', event => gifElem[i].play());
      el.addEventListener('mouseleave', event => gifElem[i].pause());
    })
    Ответ написан
  • Почему для JS не создают новых директив в роде "use strict"?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Вы можете использовать фичи ES6 без «лишних» полифиллов. Тем самым отсечёте всякие старые браузеры.
    Для личной сатисфакции добавить в начале кода якобы директиву:
    "Mr. Robot 2020";
    Ответ написан
    Комментировать
  • Как правильно реализовать передачу данных между окон?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    window.postMessage()

    У меня примерно так организована серверная OAuth2 авторизация в одном проекте. По клику «Войти через ХХХ» открывается новое окно, с URL авторизации в соц.сети с требуемыми параметрами. Там пользователь при необходимости логинится, даёт своё разрешение на доступ к данным. Его перекидывает на указанный URL на моём сервере с параметром &code=xxxxx, который уже мой сервер обменивает напрямую с соц.сетью на токен.

    При этом пользователю мой сервер в ответ на посадку с параметром code показывает какое-то минимальное содержание, главным образом, JS, который делает две вещи:
    • отправит postMessage() в родительское окно с основным приложением – сообщит о результате: получено разрешение или пользователь что-то накосячил или передумал;
    • закроет своё окно.


    Основное же окно после открытия дочернего с авторизацией, сидит, ждёт сообщение. Раз в секунду смотрит, существует ли ещё открытое дочернее окно, не закрыто ли оно (вдруг, пользователь психанул и просто закрыл то окно с авторизацией).
    Получив сообщение об успешной авторизации можно двигаться дальше.
    Получив сообщение об отказе авторизации или узнав, что дочернее окно просто пропало – вывести сообщение "так не пойдет, нужна авторизация. _Повторить?_"
    Ответ написан
    Комментировать
  • Как передать значение переменной в другую функцию, используя addEventListener?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Слушать события клика на всех элементах с классами .food-item-* (может, у них у всех есть какой-то общий класс?) или document.querySelectorAll('[class^=.food-item-]')

    При клике брать значение классов, похожих на .food-item-NNN-bin (регуляркой) и выдирать оттуда число.

    Но это, вестимо, костыль.

    Тут не хорошо, что значение класса используется не для отображения элемента, а для хранения каких-то его данных, этого самого числа. Класс обычно один-для-нескольких элементов. А для данных элемента есть data-атрибуты.
    Ответ написан
    4 комментария
  • В чем идея Mobile First подхода?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Сумев обходиться малым, позволить себе больше — проще, чем обладая многим, начать ограничивать себя.

    То же длиннее и на англ. в посте.
    абзац
    Progressive Advancement has won the game for now as far as I can see. If UI/UX designers start a product design with its desktop version, they will inevitably want to make use of most of the advantages of the advanced end. For example, the hover effect which is supported by a cursor mouse; HD images & complex charts which can display normally only when there is a recent bandwidth. In this way, the designers will make efforts to complete an amazing desktop version and only to find it can hardly be adopted on a mobile end unless they give up a lot of beautiful ideas. If so, the mobile end version will be more like an afterthought, an incomplete product which’s been watered down.
    Ответ написан
    Комментировать
  • Как задать фон и цвет всем объектам по которым не произведён клик?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Аккуратнее вынести стили в CSS. Скажем, стили по умолчанию у всех и некий класс active для единственного выбранного элемента:
    div.answer { background: #222; color: #aeaeae; }
    div.answer.active { background: #fff; color: #000; }


    Тогда скрипт примерно такой:
    const els = [...document.querySelectorAll('.answer')];
    
    const toggle = event => {
      els.forEach(el => el.classList[event.target === el ? 'add' : 'remove']('active'));
    }
    
    els.forEach(el => el.addEventListener('click', toggle));

    Fiddle
    spoiler

    Ответ написан
    Комментировать
  • Не понимаю оператора return в JS?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Смотрите, как вызывать/использовать эту функцию.

    var a = getRectArea( 3, 4 );
    Тут в переменной a окажется значение, которое функция вернула – то, что после "return" в ней оказалось. В вашем примере это 3 * 4, т.е. число 12. Ура, в переменной a теперь лежит число 12

    И как только выполнился return – всё, дальше функция уже не выполняется, это был выход.
    function test() {
      return;
      alert('Привет мир!'); // эта строка никогда не выполнится
    }
    Ответ написан
    1 комментарий
  • Как добавить event listener?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Сам gtag не предусматривает, чтобы слушали события на нём. Поэтому надо прошерстить весь свой код и найти все вызовы gtag() с искомым событием. И там же дописать ваш alert()
    Или сделать свою прослойку для аналитики. На странице вызывать вместо gtag() свою функцию, например, mytag() которая, в свою очередь, станет вызывать gtag() и может, другие скрипты аналитики.

    Upd. в комментариях выяснилось, что ТС не может поменять вызовы к gtag() В таком случае остаётся заменить функцию gtag() на свою:
    function gtag(){
      dataLayer.push(arguments); // это весь исходный её функционал
    
      if (arguments.length > 1
        && typeof arguments[0] === 'string'
        && arguments[0].toLowerString() === 'event'
        && typeof arguments[1] === 'string'
        && arguments[1] === 'name1'
      )
      {
        alert("Name 1!");
      }
    }
    Ответ написан
    4 комментария
  • Как работает этот алгоритм?

    sergiks
    @sergiks Куратор тега JavaScript
    ♬♬
    Тут как бы длинный поезд из смайликов и короткая видимая платформа остановки. В середине видны какие-то средние вагоны, а левый край поезда, определяемый переменной position – где-то далеко слева, его не видно, а значение position отрицательное. Ноль соответствует точно левому краю, началу видимой «платформы».

    Когда жмут prev – толпа смайликов едет вправо, её position увеличивается. Но при этом последний вагон не должен уехать правее левого края платформы. Поэтому position (обычно отрицательный) делается равным наибольшему из двух: 0 или вычисленному значению. Если «уехали», position получился положительным. И Math.min(0, position) станет равным 0.

    Та же механика с правым краем и движением «поезда» справа налево. Нельзя, чтобы правый вагон поезда уехал левее правого края платформы. Нельзя, чтобы показались пустые рельсы. Поэтому position не должен становиться левее == меньше, чем минус-длина поезда плюс длина платформы.
    Ответ написан
    3 комментария