Bir SVG'nin kontur genişliğinin nasıl çizileceğini kontrol edebilir misiniz?


204

Şu anda tarayıcı tabanlı bir SVG uygulaması oluşturuluyor. Bu uygulama içinde, dikdörtgenler dahil olmak üzere çeşitli şekiller kullanıcı tarafından şekillendirilebilir ve konumlandırılabilir.

Diyelim ki stroke-widthbir SVG rectelemanına a uyguladığımda 1px, kontur rectofset ve inset'e farklı tarayıcılar tarafından farklı şekillerde uygulanır. Bu, özellikle bir dikdörtgenin dış genişliğini ve görsel konumunu hesaplamaya ve diğer öğelerin yanına yerleştirmeye çalıştığımda zahmetli olduğunu kanıtlıyor .

Örneğin:

  • Firefox 1 piksel ek (alt ve sol) ve 1 piksel ofset (üst ve sağ) ekler
  • Chrome 1 piksel ek (üst ve sol) ve 1 piksel ofset (alt ve sağ) ekler

Şimdiye kadar tek çözümüm gerçek sınırları kendim çizmek olacak (muhtemelen path araçla) ve sınırları konturlu öğenin arkasına yerleştirmek . Ancak bu çözüm hoş olmayan bir çözüm ve mümkünse bu yolda gitmemeyi tercih ederim.

Benim sorum şu, bir SVG'nin stroke-widthelemanlara nasıl çizildiğini kontrol edebiliyor musunuz ?


bunu başarmak için kullanabileceğiniz filtre kesmek var - ama bu harika bir çözüm değil
Michael Mullany

2
paint-orderDolgunun konturun üstünde işlenmesi gerektiğini belirtebileceğiniz bir parametre vardır, bu nedenle "dış hizalamayı" elde edersiniz, bkz. Jsfiddle.net/hne0kyLg/1
Ivan Kuckir

Bunu css 'anahat-' niteliklerini kullanarak yapmanın bir yolunu buldum: codepen.io/badcat/pen/YVzmYY . Tarayıcılarda bunun için desteğin ne olduğundan emin değilim, ancak yararlı olabilir.
bplmp

Yanıtlar:


376

Hayır, konturun bir öğenin içine mi yoksa dışına mı çizileceğini belirleyemezsiniz. SVG çalışma grubuna 2003 yılında bu işlevsellik için bir teklifte bulundum , ancak destek (veya tartışma) almadı.

SVG, phrogz.net/SVG/stroke-location.svg adresinden inme konumu örneği önerdi

Teklifte belirttiğim gibi,

  • kontur genişliğinizi iki katına çıkararak ve ardından nesneyi kendisine kırpmak için bir kırpma yolu kullanarak "iç" ile aynı görsel sonucu elde edebilirsiniz ve
  • kontur genişliğini iki katına çıkarıp nesnenin kontursuz bir kopyasını üst üste bindirerek 'dış' ile aynı görsel sonucu elde edebilirsiniz.

Düzenleme : Bu cevap gelecekte yanlış olabilir. Bu kullanarak bu sonucu elde etmek mümkün olmalıdır SVG vektör Effects birleştirerek, veStrokePathile veIntersect( 'iç' için) ya daveExclude ('dış için . Ancak, Vektör Efektleri hala bulabildiğim uygulamaları olmayan çalışan bir taslak modüldür.

Düzenleme 2 : SVG 2 taslak belirtimi bir stroke-alignmentözellik içerir (merkezi | içeride | olası değerlerin dışında). Bu özellik, sonunda ABD'ye dönüştürebilir.

Edit 3 : Eğlenceli ve dissapointingly, SVG çalışma grubu stroke-alignmentSVG 2'den kaldırıldı . Burada nesir sonra açıklanan bazı endişeleri görebilirsiniz .


2
Durum böyle olabileceğini düşündüm. Bunu çözmek için getStrokedBBox () adlı getBBox () için bir sarıcı işlevi yazdım. Bu sarıcı, tarayıcının bir şeklin iç kısmına ve ofsetine konturları uygulama şekline göre BBox'u döndürür. Mükemmel değil (en son tarayıcı sürümlerine karşı kontrol etmeye devam etmeliyiz), ancak şimdilik doğru bir genişlik şekli sağlıyor.
Steve

6
@Phrogz belki 10 yıl geçmeden göreceğiz. svgwg.org/svg2-draft/painting.html#SpecifyingStrokePaint ek açıklaması
frenchone

1
O sonunda burada! Ben, biri için, gerçekten bu özellik gelmesi için çağırıyorum.
mnsth

Herhangi bir SVGGeometryElement konturunu izlemek için bir kontur hizalama çözümü olarak kullanılabilecek bir svg-kontur komut dosyası oluşturdum , ilgilenen herkes için bir açıklama bulabilirsiniz
maioman

2
Teklif için vekalet edebileceğim bir sayfa var mı? Teşekkürler. Desteklenmediği saçma görünüyor.
mahish

57

GÜNCELLEME:stroke-alignment nitelik 1 Nisan SVG İnme adı verilen tamamen yeni spec taşındı 2015'te oldu .

SVG 2.0 Editörünün 26 Şubat 2015 Taslağı (ve muhtemelen 13 Şubat'tan beri) ), stroke-alignmentözelliği mevcut olduğudeğerlerle inner, center (varsayılan) veouter .

stroke-location@Phrogz tarafından önerilen mülk ve daha sonraki stroke-positionöneri ile aynı şekilde çalışıyor gibi görünüyor . Bu mülk en az 2011 yılından beri planlanmıştır, ancak

SVG 2 vuruş pozisyonunu belirtmek için bir yol içermelidir

, ertelendiği için spesifikasyonda hiçbir zaman ayrıntılı olmamıştır - şimdiye kadar görünüyor.

Hiçbir tarayıcı bu özelliği desteklemiyor veya bildiğim kadarıyla yeni SVG 2 özelliklerinden herhangi biri henüz yok, ancak umarım spesifikasyonlar olgunlaştıkça yakında olacak. Bu şahsen sahip olduğum bir özellik oldu ve nihayet spec orada gerçekten mutluyum.

Mülkün açık yollarda ve döngülerde nasıl davranması gerektiği konusunda bazı sorunlar var gibi görünüyor. Bu sorunlar büyük olasılıkla tarayıcılar arasındaki uygulamaları uzatacaktır. Ancak, tarayıcılar bu özelliği desteklemeye başladığında bu yanıtı yeni bilgilerle güncelleyeceğim.


1
stroke-alignmentWGC Çalışma Taslağı olan SVG Vuruşlarında belirtilir. Bu arada, SVG 2 W3C Editörün Taslağı, inme konumlandırma özelliğinin svgwg.org/svg2-draft/painting.html#SpecifyingStrokePaint adresindeki SVG spesifikasyonunda olacağını ve bu özelliğin zaten mevcut olmadığını ve böyle bir mülkün spesifikasyonda stroke-positionteklife bir bağlantı dışında, böyle görünmemesi de durum böyle olmayacak.
Patrick Dark

47

Birkaç kısıtlaması olan kolay bir yol buldum, ancak benim için çalıştı:

  • def'deki şekli tanımlar
  • şekle başvuran bir klip yolu tanımlayın
  • kullanın ve dış kırpılmış olarak konturu iki katına çıkarın

İşte çalışan bir örnek:

<svg width="240" height="240" viewBox="0 0 1024 1024">
<defs>
	<path id="ld" d="M256,0 L0,512 L384,512 L128,1024 L1024,384 L640,384 L896,0 L256,0 Z"/>
	<clipPath id="clip">
		<use xlink:href="#ld"/>
	</clipPath>
</defs>
<g>
	<use xlink:href="#ld" stroke="#0081C6" stroke-width="160" fill="#00D2B8" clip-path="url(#clip)"/>
</g>
</svg>


2
Bulduğum en iyi cevap
Ed Kolosovsky

1
Akıllı çözüm. Teşekkürler
Vince Yuan

Bu cevap olarak kabul edilmelidir. <defs> ve <use> kullanmak şu anda mevcut olan en şık çözümdür.
Nyerguds

Güzel çözüm. Dış strok yapmak için nasıl ters çevirirsiniz?
Lucent

Neden üst düzey <use>? Neden sadece yolu ve klip yolunu doğrudan koymuyorsunuz? Bu sadece para cezası çalışır: <svg width="240" height="240" viewBox="0 0 1024 1024"> <path id="ld" d="M256,0 L0,512 L384,512 L128,1024 L1024,384 L640,384 L896,0 L256,0 Z" clip-path="url(#clip)" stroke="#0081C6" stroke-width="160" fill="#00d2b8"/> <clipPath id="clip"> <use xlink:href="#ld"/> </clipPath> </svg>. (Evet, bu tamamen makul ve doğru SVG'dir ve her yerde doğru şekilde işleyecektir. Özyineleme korkmayın.)
Chris Morgan

31

Kontur ve dolguların sırasını belirlemek için CSS kullanabilirsiniz. Yani, önce inme sonra ikinciyi doldurun ve istediğiniz efekti elde edin.

MDN açık paint-order: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/paint-order

CSS kodu:

paint-order: stroke;

Bu harika!
Paylaştığınız

1
Bağlantılı belgeler konturun içeride, dışarıda mı yoksa ortalanmış mı olduğunu göstermiyor mu? Konturun nerede çizileceğini nasıl kontrol edeceğinizi açıklayabilir misiniz? Teşekkürler.
Crashalot

2
Kontur, her zamanki gibi ortalanır - ancak sağlam bir dolgunuz varsa, önce konturu boyamak için boya sırasını ayarlamanın etkisi, konturun iç yarısının üzerine çizilmesidir; dışında kalın kalın vuruş.
Chris Morgan

7

Aşağıda, tarayıcıya göre verilen konturu kullanarak üste, sağa, alta ve sola kaç piksel eklemeniz gerektiğini hesaplayan bir işlev vardır:

var getStrokeOffsets = function(stroke){

        var strokeFloor =       Math.floor(stroke / 2),                                                                 // max offset
            strokeCeil =        Math.ceil(stroke / 2);                                                                  // min offset

        if($.browser.mozilla){                                                                                          // Mozilla offsets

            return {
                bottom:     strokeFloor,
                left:       strokeFloor,
                top:        strokeCeil,
                right:      strokeCeil
            };

        }else if($.browser.webkit){                                                                                     // WebKit offsets

            return {
                bottom:     strokeCeil,
                left:       strokeFloor,
                top:        strokeFloor,
                right:      strokeCeil
            };

        }else{                                                                                                          // default offsets

            return {
                bottom:     strokeCeil,
                left:       strokeCeil,
                top:        strokeCeil,
                right:      strokeCeil
            };

        }

    };

6

Yukarıdaki kişilerin belirttiği gibi, konturun yol koordinatlarına bir ofseti yeniden hesaplamanız veya genişliğini iki katına çıkarmanız ve ardından bir tarafı veya diğerini maskelemeniz gerekir, çünkü SVG yalnızca Illustrator'ın kontur hizalamasını yerel olarak desteklemez, aynı zamanda PostScript de .

Adobe'nin PostScript Kılavuzu 2. baskı durumlarında vuruş için şartname: " 4.5.1 okşamaya: inme operatörü akım yolu boyunca bazı kalınlıkta bir çizgi çizer yolundaki her düz veya eğri parçanın için. Strok bir çizgi çizer merkezli üzerinde yanları segmente paralel olan segment. " (onların vurguları)

Spesifikasyonun geri kalanında, hattın konumunu dengelemek için hiçbir özellik yoktur. Illustrator içeriye veya dışarıya hizalanmanıza izin verdiğinde, gerçek yolun ofsetini yeniden hesaplar (çünkü hala üst baskıdan sonra maskelemeden hesaplama açısından daha ucuzdur). .Ai belgesindeki yol koordinatları, rasterleştirilen veya son biçime aktarılanlar değil referanstır.

Inkscape'in yerel biçimi spec SVG olduğundan, specte bulunmayan bir özellik sunamaz.


4

İşte için bir çalışma dönünce sınırlanmıştır iç rect kullanıyor symbolve use.

Örnek : https://jsbin.com/yopemiwame/edit?html,output

SVG :

<svg>
  <symbol id="inner-border-rect">
    <rect class="inner-border" width="100%" height="100%" style="fill:rgb(0,255,255);stroke-width:10;stroke:rgb(0,0,0)">
  </symbol>
  ...
  <use xlink:href="#inner-border-rect" x="?" y="?" width="?" height="?">
</svg>

Not: girişini değiştirdiğinizden emin olun ?.use gerçek değerlerle .

Arkaplan : sembolü değiştirerek yeni bir görünüm oluşturur, çünkü bu işleri nedeni budur symbolile svgve gölge DOM bir eleman yaratılmaktadır. Bu svg, gölge DOM'nin geçerli SVGöğenize bağlanır . svgS'nin yuvalanabileceğini ve her birinin svgçakışan kenarlık da dahil olmak üzere çakışan her şeyi kırpan yeni bir görünüm oluşturduğunu unutmayın . Neler olup bittiğine dair daha ayrıntılı bir genel bakış için Sara Soueidan'ın bu harika makalesini okuyun .


2

Bunun ne kadar yararlı olacağını bilmiyorum ama benim durumumda sadece kenarlığı olan başka bir daire oluşturdum ve onu diğer şekle “içine” yerleştirdim.


0

(Kirli) olası bir çözüm kalıpları kullanmaktır,

İşte içten içe üçgeni olan bir örnek:

https://jsfiddle.net/qr3p7php/5/

<style>
#triangle1{
  fill: #0F0;
  fill-opacity: 0.3;
  stroke: #000;
  stroke-opacity: 0.5;
  stroke-width: 20;
}
#triangle2{
  stroke: #f00;
  stroke-opacity: 1;
  stroke-width: 1;
}    
</style>

<svg height="210" width="400" >
    <pattern id="fagl" patternUnits="objectBoundingBox" width="2" height="1" x="-50%">
        <path id="triangle1" d="M150 0 L75 200 L225 200 Z">
    </pattern>    
    <path id="triangle2" d="M150 0 L75 200 L225 200 Z" fill="url(#fagl)"/>
</svg>

0

Xavier Ho'dan çözümKonturun genişliğini iki katına çıkarmak ve boya sırasını değiştirmek için parlaktır, ancak yalnızca dolgu şeffaf olmayan, düz bir renkse çalışır.

Başka bir yaklaşım geliştirdim, daha karmaşık ama her türlü dolgu için çalışıyor. Aynı zamanda elips veya yollarda da çalışır (daha sonra garip davranışlara sahip bazı köşe vakaları vardır, örneğin, kendilerini geçen, ancak çok fazla olmayan açık yollar).

İşin püf noktası şekli iki katman halinde göstermektir. Biri kontursuz (sadece dolgu) ve diğeri sadece çift genişlikte (şeffaf dolgu) konturlu ve tüm şekli gösteren bir maskeden geçirilir, ancak orijinal şekli kontursuz olarak gizler.

  <svg width="240" height="240" viewBox="0 0 1024 1024">
  <defs>
    <path id="ld" d="M256,0 L0,512 L384,512 L128,1024 L1024,384 L640,384 L896,0 L256,0 Z"/>
    <mask id="mask">
      <use xlink:href="#ld" stroke="#FFFFFF" stroke-width="160" fill="#FFFFFF"/>
      <use xlink:href="#ld" fill="#000000"/>
    </mask>
  </defs>
  <g>
    <use xlink:href="#ld" fill="#00D2B8"/>
    <use xlink:href="#ld" stroke="#0081C6" stroke-width="160" fill="red" mask="url(#mask)"/>
  </g>
  </svg>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.