Можно ли нарисовать SVG-путь на периферию круга [duplicate]

В следующем примере, который я написал, показано, как

  • обрабатывать асинхронные HTTP-вызовы;
  • Подождать ответа от каждого вызова API;
  • Использовать шаблон promise ;
  • Используйте шаблон Promise.All для объединения нескольких HTTP-вызовов;

Этот рабочий пример является автономным. Он будет определять простой объект запроса, который использует объект window XMLHttpRequest для совершения вызовов. Он будет определять простую функцию, чтобы дождаться завершения кучи обещаний.

Контекст. В этом примере запрашивается конечная точка Spotify Web API для поиска объектов playlist для заданного набора строк запроса:

[
 "search?type=playlist&q=%22doom%20metal%22",
 "search?type=playlist&q=Adele"
]

Для каждого элемента новый Promise запустит блок - ExecutionBlock, проанализирует результат, заплатит новый набор обещаний на основе массива результатов, который представляет собой список объектов Spotify user и выполняет новый HTTP-вызов в ExecutionProfileBlock асинхронно.

Затем вы можете увидеть вложенную структуру Promise, которая позволяет вам генерировать множественные и полностью асинхронные вложенные HTTP-вызовы и присоединять результаты к каждому подмножеству вызовов через Promise.all.

NOTE Recent Spotify search API-интерфейсам потребуется указать токен доступа в заголовках запроса:

-H "Authorization: Bearer {your access token}" 

Итак, вы должны запустить следующий пример, вам нужно поместить маркер доступа в заголовки запроса:

var spotifyAccessToken = "YourSpotifyAccessToken";
var console = {
    log: function(s) {
        document.getElementById("console").innerHTML += s + "
" } } // Simple XMLHttpRequest // based on https://davidwalsh.name/xmlhttprequest SimpleRequest = { call: function(what, response) { var request; if (window.XMLHttpRequest) { // Mozilla, Safari, ... request = new XMLHttpRequest(); } else if (window.ActiveXObject) { // Internet Explorer try { request = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { request = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {} } } // State changes request.onreadystatechange = function() { if (request.readyState === 4) { // Done if (request.status === 200) { // Complete response(request.responseText) } else response(); } } request.open('GET', what, true); request.setRequestHeader("Authorization", "Bearer " + spotifyAccessToken); request.send(null); } } //PromiseAll var promiseAll = function(items, block, done, fail) { var self = this; var promises = [], index = 0; items.forEach(function(item) { promises.push(function(item, i) { return new Promise(function(resolve, reject) { if (block) { block.apply(this, [item, index, resolve, reject]); } }); }(item, ++index)) }); Promise.all(promises).then(function AcceptHandler(results) { if (done) done(results); }, function ErrorHandler(error) { if (fail) fail(error); }); }; //promiseAll // LP: deferred execution block var ExecutionBlock = function(item, index, resolve, reject) { var url = "https://api.spotify.com/v1/" url += item; console.log( url ) SimpleRequest.call(url, function(result) { if (result) { var profileUrls = JSON.parse(result).playlists.items.map(function(item, index) { return item.owner.href; }) resolve(profileUrls); } else { reject(new Error("call error")); } }) } arr = [ "search?type=playlist&q=%22doom%20metal%22", "search?type=playlist&q=Adele" ] promiseAll(arr, function(item, index, resolve, reject) { console.log("Making request [" + index + "]") ExecutionBlock(item, index, resolve, reject); }, function(results) { // Aggregated results console.log("All profiles received " + results.length); //console.log(JSON.stringify(results[0], null, 2)); ///// promiseall again var ExecutionProfileBlock = function(item, index, resolve, reject) { SimpleRequest.call(item, function(result) { if (result) { var obj = JSON.parse(result); resolve({ name: obj.display_name, followers: obj.followers.total, url: obj.href }); } //result }) } //ExecutionProfileBlock promiseAll(results[0], function(item, index, resolve, reject) { //console.log("Making request [" + index + "] " + item) ExecutionProfileBlock(item, index, resolve, reject); }, function(results) { // aggregated results console.log("All response received " + results.length); console.log(JSON.stringify(results, null, 2)); } , function(error) { // Error console.log(error); }) ///// }, function(error) { // Error console.log(error); });

Я подробно рассмотрел это решение здесь .

119
задан 15 revs, 3 users 100% 23 March 2015 в 01:08
поделиться

12 ответов

То же самое для дуги XAML. Просто закройте дугу 99.99% с помощью Z, и у вас есть круг!

30
ответ дан Todd Main 27 August 2018 в 01:44
поделиться

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

function(cx, cy, r, deg){
    var theta = deg*Math.PI/180,
        dx = r*Math.cos(theta),
        dy = -r*Math.sin(theta);
    return "M "+cx+" "+cy+"m "+dx+","+dy+"a "+r+","+r+" 0 1,0 "+-2*dx+","+-2*dy+"a "+r+","+r+" 0 1,0 "+2*dx+","+2*dy;
}
2
ответ дан 2 revs 27 August 2018 в 01:44
поделиться

Я знаю, что это немного поздно в игре, но я вспомнил этот вопрос с того момента, когда он был новым, и у меня была подобная диллемма, и я случайно нашел «правильное» решение, если кто-то еще ищет его:

<path 
    d="
    M cx cy
    m -r, 0
    a r,r 0 1,0 (r * 2),0
    a r,r 0 1,0 -(r * 2),0
    "
/>

Другими словами, это:

<circle cx="100" cy="100" r="75" />

может быть достигнуто как путь с этим:

  <path 
        d="
        M 100, 100
        m -75, 0
        a 75,75 0 1,0 150,0
        a 75,75 0 1,0 -150,0
        "
  />

Трюк состоит в том, чтобы иметь две дуги , второй - вверх, где первый остановился и используя отрицательный диаметр, чтобы вернуться к исходной начальной точке дуги.

Причина, по которой это невозможно сделать как полный круг в одной дуге (и Я просто размышляю), потому что вы говорили бы, чтобы он рисовал дугу от себя (скажем 150 150) к себе (150,150), которую он отображает как «о, я уже там, нужная дуга!».

Преимуществами предлагаемого решения являются:

  1. его легко перевести из круга непосредственно в путь, а
  2. нет перекрываются в двух линиях дуги (что может вызвать проблемы, если вы используете маркеры или шаблоны и т. д.). Это чистая сплошная линия, хотя и нарисованная двумя частями.

Ничто из этого не имело бы значения, если бы они просто разрешали текстовым путям принимать фигуры. Но я думаю, что они избегают этого решения, поскольку элементы формы, такие как круг, технически не имеют точки начала.

jsfiddle demo: http://jsfiddle.net/crazytonyi/mNt2g/

Обновление:

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

<path 
    d="
    M cx cy
    m -r, 0
    a r,r 0 1,1 (r * 2),0
    a r,r 0 1,1 -(r * 2),0
    "
/>
345
ответ дан Anthony 27 August 2018 в 01:44
поделиться

См. решение Anthony's здесь, это функция для получения пути:

function circlePath(cx, cy, r){
    return 'M '+cx+' '+cy+' m -'+r+', 0 a '+r+','+r+' 0 1,0 '+(r*2)+',0 a '+r+','+r+' 0 1,0 -'+(r*2)+',0';
}
12
ответ дан Anton Matiashevich 27 August 2018 в 01:44
поделиться

Хорошо, что с помощью двух команд дуги рисовать полный круг.

обычно, я использую элемент эллипса или круга для рисования полного круга.

3
ответ дан cuixiping 27 August 2018 в 01:44
поделиться

Другой способ - использовать два кубических кривых Безье. Это для iOS-пользователей, использующих pocketSVG , который не распознает параметр svg arc.

C x1 y1, x2 y2, xy (или c dx1 dy1, dx2 dy2, dx dy)

Последний набор координат здесь (x, y) - это место, где вы хотите, чтобы линия заканчивалась. Остальные два являются контрольными точками. (x1, y1) - контрольная точка начала вашей кривой и (x2, y2) для конечной точки вашей кривой.

<path d="M25,0 C60,0, 60,50, 25,50 C-10,50, -10,0, 25,0" />
0
ответ дан ha100 27 August 2018 в 01:44
поделиться

Написанная как функция, она выглядит так:

function getPath(cx,cy,r){
  return "M" + cx + "," + cy + "m" + (-r) + ",0a" + r + "," + r + " 0 1,0 " + (r * 2) + ",0a" + r + "," + r + " 0 1,0 " + (-r * 2) + ",0";
}
2
ответ дан Harry Stevens 27 August 2018 в 01:44
поделиться

Эти примеры слишком сложны !!!

Просто сделайте это с помощью литералов шаблонов es6.

Простейший способ сделать это без создания двух дуг ..

Предполагается, что ваша область холста имеет ширину w и высоту h.

`M${w*0.5 + radius},${h*0.5}
 A${radius} ${radius} 0 1 0 ${w*0.5 + radius} ${h*0.5001}`

Просто используйте флаг «длинной дуги», поэтому полный флаг заполняется. Затем сделайте дуги 99.9999% полного круга. Визуально это одно и то же. Избегайте флага развертки, просто начиная круг в самой правой точке круга (один радиус прямо горизонтальный от центра).

0
ответ дан in code veritas 27 August 2018 в 01:44
поделиться

я сделал jsfiddle, чтобы сделать это здесь:

function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;

return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}

function describeArc(x, y, radius, startAngle, endAngle){

var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);

var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";

var d = [
    "M", start.x, start.y, 
    "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
].join(" ");

return d;       
}
console.log(describeArc(255,255,220,134,136))

link

все, что вам нужно сделать, это изменить ввод консоли .log и получить результат в консоли

1
ответ дан javad bat 27 August 2018 в 01:44
поделиться

Совершенно другой подход:

Вместо того, чтобы возиться с путями для указания дуги в svg, вы также можете взять элемент окружности и указать штрих-dasharray в псевдокоде:

with $score between 0..1, and pi = 3.141592653589793238

$length = $score * 2 * pi * $r
$max = 7 * $r  (i.e. well above 2*pi*r)

<circle r="$r" stroke-dasharray="$length $max" />

Его простота является основным преимуществом по сравнению с методом с несколькими дугами (например, при написании сценариев вы включаете только одно значение, и вы делаете для любой длины дуги)

Дуга начинается с самая правая точка и может быть сдвинута с использованием поворотного преобразования.

Примечание. В Firefox есть странная ошибка, при которой игнорируются вращения более 90 градусов и более. Чтобы начать дугу сверху, используйте:

<circle r="$r" transform="rotate(-89.9)" stroke-dasharray="$length $max" />
9
ответ дан mvds 27 August 2018 в 01:44
поделиться

Adobe Illustrator использует кривые безье, такие как SVG, а для кругов - четыре точки. Вы можете создать круг с двумя эллиптическими командами дуги ... но затем для круга в SVG я бы использовал <circle />:)

4
ответ дан Phrogz 27 August 2018 в 01:44
поделиться

Для таких, как я, которые искали атрибуты эллипса для преобразования пути:

const ellipseAttrsToPath = (rx,cx,ry,cy) =>
`M${cx-rx},${cy}a${rx},${ry} 0 1,0 ${rx*2},0a${rx},${ry} 0 1,0 -${rx*2},0`
1
ответ дан yogi 27 August 2018 в 01:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: