2D Canvas: укажите единицы радиуса `arc ()`

Я пытался создать адаптивный веб-сайт, включающий холст.

При рисовании круглого индикатора выполнения я вызываю функцию arc(), но ее аргумент radius, похоже, что это должно быть в пикселях, но мне нужно, чтобы это было в процентах, vw, vh, em или любой другой единице, предлагаемой css.

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

Как мне это сделать?


person Magix    schedule 11.05.2017    source источник


Ответы (2)


После некоторого поиска я наткнулся на этот вопрос, который помог я решу проблему.

Вот как я это сделал:

var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);

var vw = w/100;
var vh = h/100;

var pxradius = 50;
var vwradius = pxradius*vw;

К сожалению, решения по процам и емс до сих пор нет

person Magix    schedule 11.05.2017
comment
Мне кажется, что ваш код в точности преобразует процентное значение pxradius в значение пикселя. Так что это решение на проц. Я что-нибудь упускаю? - person ; 15.11.2017
comment
Ну, не совсем так, поскольку проценты относятся к контейнеру, в котором размещен элемент (afaik), а здесь только относительно высоты / ширины окна - person Magix; 15.11.2017

Я сейчас над чем-то работаю, где мне пришлось решить ту же проблему (т.е. установить значения радиуса для _ 1_ в процентах или ems).


Вот код JavaScript моего решения:

function percentToPixelParentBased(percent, element, width_based=true) {
  return percentToPixelElementRelative(percent, element.parentElement, width_based);
}


function emToPixelParentBased(em_value, element) {
  return emToPixelElementRelative(em_value, element.parentElement);
}


function percentToPixelElementRelative(percent, element=false, width_based=true) { 
  if (element) {
    if (width_based) {
        var dimension = element.style.width || element.offsetWidth;
    } else {
        var dimension = element.style.height || element.offsetHeight; 
    }
  } else {
    if (width_based) {
        var dimension = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
    } else {
        var dimension = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
    }
  }

  var pixels_in_percent = dimension / 100;

  return pixels_in_percent * percent;
}


function emToPixelElementRelative(em_value, element=false) {
  var font_size = getFontSize(element);
  var ppi = getPPI();
  var px_in_pt = 72 / ppi; /* 1pt is 1/72 of an inch */
  var value_in_pt = em_value * font_size;

  return value_in_pt * px_in_pt;
}


function getFontSize(element=false) {

    if (element) {
    return parseFloat(getComputedStyle(element).fontSize);
  } else {
    /* getting font size from body */
    return parseFloat(getComputedStyle(document.body).fontSize);
  }
}


function getPPI() {
  var inch_div_html = "<div id='inch-div' style='height: 1in; left: -100%; position: absolute; top: -100%; width: 1in;'></div>";
  document.body.insertAdjacentHTML( 'afterbegin', inch_div_html);

  var device_pixel_ratio = window.devicePixelRatio || 1;
  var ppi_test_div = document.getElementById('inch-div');
  var ppi = ppi_test_div.offsetWidth * devicePixelRatio;

  document.body.removeChild(ppi_test_div);

  return ppi;  
}

Чтобы немного потрудиться, есть демонстрация на JSFiddle.


Теперь немного пояснений / замечаний: каждый из emToPixelElementRelative и percentToPixelElementRelative преобразует значение, переданное ему в качестве первого аргумента em=>px и %=>px соответственно. Второй аргумент обеих функций (element) - это элемент, на основе которого будут вычисляться значения в px (NB: имейте в виду, что вы передаете радиус, а не диаметр в arc(), что для процентов означает, что если вы передадим 50 (%) и будем основывать вычисления на элементе canvas - диаметр круга будет 100% и заполнит весь canvas (в случае квадратного холста)), если аргумент не передан - значения рассчитываются на основе размеров области просмотра. Третий аргумент (width_based) отражает, должны ли вычисляться значения относиться к ширине (если установлено true, что по умолчанию) или высоте (если установлено false).

percentToPixelParentBased и emToPixelParentBased - это просто оболочки для percentToPixelElementRelative и emToPixelElementRelative, которые основывают преобразование на родительском элементе переданного element.

getFontSize возвращает размер шрифта для переданного element или для элемента <body>, если вызывается без аргументов.

getPPI получает текущий PPI через своего рода упомянутый хак в этом ответе он принимает единственный аргумент (width_based), указывающий, следует ли основывать его вычисления на ширине (если true - по умолчанию) или высоте (если false).

Также обратите внимание, что я основывал em=>px расчеты на следующих предположениях:


Вопросы (и ответы на них, конечно) / ресурсы, которые помогли мне собрать это решение:

  1. Getting current PPI:
  2. Getting current font size:
  3. Percent to pixel conversion:
  4. Em to pixel conversion:
  5. Misc:
person Community    schedule 18.11.2017