SVG dikdörtgenine metin yerleştirme ve ortalama


179

Aşağıdaki dikdörtgene sahibim ...

<rect x="0px" y="0px" width="60px" height="20px"/>

İçinde "Kurgu" kelimesini ortalamak istiyorum. Diğer dikdörtgenler için, svg word'ün içinde kalması gerekir mi? Hem yatay hem de dikey olarak ortalanmış şekiller ve sözcük kaydırma içine metin eklemek hakkında özel bir şey bulamıyorum. Ayrıca, metin dikdörtgen bırakamaz.

Http://www.w3.org/TR/SVG/text.html#TextElement örneğine bakmak , metin öğesinin x ve y dikdörtgeninin x ve y'den farklı olması nedeniyle yardımcı olmaz. Metin öğeleri için genişlik ve yükseklik yok gibi görünüyor. Burada matematikten emin değilim.

(Html ​​tablom işe yaramayacak.)


1
Lütfen metin bağlantısı ve baskın taban çizgisini kullanarak cevaba geçebilir misiniz? Teşekkürler!
neaumusic

1
neaumusic, bitti. 8)
Lady Aleena

Yanıtlar:


310

SVG'de metni yatay ve dikey olarak ortalamak için kolay bir çözüm:

  1. Metnin konumunu, içinde ortalamak istediğiniz öğenin mutlak merkezine ayarlayın :

    • Ebeveynse, sadece yapabilirsin x="50%" y ="50%".
    • Bu başka bir öğe xise x, o öğenin + genişliğinin yarısı (ve yyüksekliği ile benzerdir ) olacaktır.
  2. text-anchorMetni, değeriyle yatay olarak ortalamak için özelliği kullanın middle:

    orta

    Oluşturulan karakterler, sonuçta oluşturulan metnin geometrik ortası ilk geçerli metin konumunda olacak şekilde hizalanır.

  3. dominant-baselineMetni değere middlegöre dikey olarak ortalamak için özelliği kullanın (veya nasıl görünmesini istediğinize bağlı olarak, yapmak isteyebilirsiniz central)

İşte basit bir demo:

<svg width="200" height="100">
  <rect x="0" y="0" width="200" height="100" stroke="red" stroke-width="3px" fill="white"/>
  <text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle">TEXT</text>    
</svg>


1
Başka bir şey benim için çalışıyordu ben radyal ilerleme çubuğunun içinde bir sayı ortalamak için bu kullanılan - Bir çözüm bu basit için her yerde aradım
anthonytherockjohnson

7
Benim durumumda, işi yapan dominant-baselineözellik değil alignment-baseline.
pintoch

1
Düzenli olarak bunu yapmak için gidiyoruz, ayrıca aşağıdakileri ekleyebilirsiniz: <style type="text/css"><![CDATA[ text { alignment-baseline: middle; text-anchor:middle; } ]]></style>. Çözüm için teşekkürler.
Manngo

1
Kendi kod snippet'inizi çalıştırın. Çalışmıyor. Şuna göz atın: Stackoverflow'un sağladığı önizlemede bile çalışmaz. Daha önce belirtildiği gibi yorumda dominant-baselinegerçekten kullanılması gerekiyor. Üzgünüm, ama bu cevap bir şekilde yanıltıcı. Firefox veya Chromium'da çalışmıyor gibi görünüyor ve ek olarak doğru çözümü bulmak için yorumları incelemelisiniz, beklendiği gibi çalışan kodla başka bir cevap ekleme özgürlüğünü aldım. (Kayıtlar için: Ubuntu Linux'ta FF ve Chromium ile test edildi.)
Regis

2
@RegisMayrı işaret ettiğiniz için teşekkürler. Ben Mac Chrome değilim ve onunla para cezası çalıştı alignment-baseline, ancak gözlük gözden olması gerektiği, çünkü bu bir ilginç bir şey olabilir gibi görünüyor dominant-baselineiçin text, ve alignment-baselineiçin tspan, tref, altGlyph, ve textPath. Cevabı buna göre güncelledim.
Alvaro Montoro

38

SVG 1.2 Küçük metin sarma eklendi, ancak tarayıcıda bulabileceğiniz SVG uygulamalarının çoğu (Opera hariç) bu özelliği uygulamadı. Metni manuel olarak konumlandırmak genellikle geliştiriciye bağlıdır.

SVG 1.1 spesifikasyonu, bu sınırlamaya ve bunun üstesinden gelmek için olası çözümlere iyi bir genel bakış sağlar:

Her 'metin' öğesi tek bir metin dizisinin oluşturulmasına neden olur. SVG hiçbir otomatik satır kesme veya kelime kaydırma gerçekleştirmez. Birden çok metin satırının etkisini elde etmek için aşağıdaki yöntemlerden birini kullanın:

  • Yazarın veya yazma paketinin satır sonlarını önceden hesaplaması ve birden çok 'metin' öğesi (her metin satırı için bir tane) kullanması gerekir.
  • Yazarın veya yazma paketinin satır sonlarını önceden hesaplaması ve 'x', 'y', 'dx' ve 'dy' nitelikleri için uygun değerlere sahip bir veya daha fazla 'tspan' alt öğesiyle tek bir 'metin' öğesi kullanması gerekir yeni satırlar başlatan karakterler için yeni başlangıç ​​konumları ayarlamak için. (Bu yaklaşım, birden çok metin satırında kullanıcı metin seçimine izin verir - bkz. Metin seçimi ve pano işlemleri.)
  • Satır içi 'yabancıObject' öğesi içine gömülü XHTML [XHTML] gibi başka bir XML ad alanında oluşturulacak metni ifade edin. (Not: Bu yaklaşımın kesin semantiği şu anda tam olarak tanımlanmamıştır.)

http://www.w3.org/TR/SVG11/text.html#Introduction

İlkel olarak, metin kaydırma, dyöznitelik ve tspanöğeler kullanılarak simüle edilebilir ve spesifikasyonda belirtildiği gibi, bazı araçlar bunu otomatikleştirebilir. Örneğin, Inkscape'de istediğiniz şekli ve istediğiniz metni seçin ve Metin -> Çerçeveye Akış'ı kullanın. Bu, metninizi, şeklin sınırlarına göre sarılacak olan sarma ile yazmanıza olanak tanır. Ayrıca Inkscape'e SVG 1.1 ile uyumluluğunu sürdürmesini bildirmek için şu talimatları izlediğinizden emin olun: http://wiki.inkscape.org/wiki/index.php/FAQ#What_about_flowed_text.3F

Ayrıca, metin kaydırmayı dinamik olarak otomatikleştirmek için kullanılabilecek bazı JavaScript kitaplıkları vardır: http://www.carto.net/papers/svg/textFlow/

O bunların uygulanması olduğunu belirtmek önemlidir rağmen, (örneğin onların "düğmesi" örneğe bakın) bir metin öğesine bir şekle sarmaya CSVG en çözümünü nota ilginç değil bir tarayıcıda kullanılabilir: http://www.csse.monash.edu AU / ~ clm / csvg / about.html

Bundan bahsediyorum çünkü henüz yayınlamamış olsam da benzer şeyler yapmanıza izin veren ve web tarayıcılarında çalışan CSVG'den ilham alan bir kütüphane geliştirdim.


Cevabınız için teşekkürler ... ama ACK! Görünüşe göre o zaman svg dökmek zorunda kalacak. Geliştiricilerin düşünmesi gereken ilk şeylerden biri şekillere metin eklemek (kullanıcıların istediği gibi biçimlendirilmiş)! Bir daha yapmadan önce birlikte hareket etmelerini bekleyeceğim. Windows Paint'te yeniden çizmeye çalışacağım ve bunu yapıp yapmayacağını göreceğim. (Keşke tarayıcıları masayı doğru bir şekilde görüntüleyebilseydim.)
Lady Aleena

Svg'deki düzenlenebilir metin hakkında Opera, SVG 1.2 editable="true"Tiny'nin düzenlenebilir niteliğini destekler; bu , text veya textArea öğesine bir nitelik ekleyerek düzenlenebilir metin elde etmeyi mümkün kılar .
Erik Dahlström

2
@Erik, Opera bir kez daha eğrinin önünde.
jbeard4

@Lady Aleena, neden sadece bahsettiğim Inkscape çözümünü kullanmıyorsun? Bu yalnızca statik bir görüntü ise (örn. Dinamik davranış yoksa, metin içeriğini dinamik olarak güncellemiyorsa), bunun iyi çalışması gerekir. Ayrıca, Paint raster grafiklerini ürettiğinden, Paint'in ölçeklenemeyeceği ölçeklenebilir. Son olarak, Paint'in metin kaydırmayı herhangi bir düzeyde desteklediğine inanmıyorum.
jbeard4

@ echo-flow html oluşturmak için Microsoft Front Page kullandığımdan (ve sonradan döktüğüm) beri kod üretme programlarına olan güveni çok uzun zaman önce kaybettim. Her zaman yazdıklarıma kendi özel kodlarını ekleyerek programlara karşı temkinli davranıyorum. Ön Sayfa benim html gerçekten berbat. Eğer bir Inkscape kullanıcısıysanız, Inkscape'in kendi özel kodunu svg oluşturma işleminden sonra svg'ye girip çıkartmam gerektiğini söyleyebilir misiniz?
Lady Aleena

23

Önceki yanıtlar, yuvarlatılmış köşeler kullanıldığında kötü sonuçlar verdi veya stroke-widthbu> 1. Örneğin, aşağıdaki kodun yuvarlatılmış bir dikdörtgen üretmesini beklersiniz, ancak köşeler üst svgbileşen tarafından kırpılır :

<svg width="200" height="100">
  <!--this rect should have rounded corners-->
  <rect x="0" y="0" rx="5" ry="5" width="200" height="100" stroke="red" stroke-width="10px" fill="white"/>
  <text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">CLIPPED BORDER</text>    
</svg>

Bunun yerine, sarma tavsiye textbir yer svgve daha sonra bu yeni yuva svgve rectbir iç buluşmanızı gaşağıdaki örnekte olduğu gibi, eleman:

<!--the outer svg here-->
<svg width="400px" height="300px">

  <!--the rect/text group-->
  <g transform="translate(50,50)">
    <rect rx="5" ry="5" width="200" height="100" stroke="green" fill="none" stroke-width="10"/>
    <svg width="200px" height="100px">
      <text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">CORRECT BORDER</text>      
    </svg>
  </g>

  <!--rest of the image's code-->
</svg>

Bu, yukarıdaki yanıtlarda oluşan kırpma sorununu giderir. Ayrıca rect / text grubunu transform="translate(x,y)", rect / text'i ekran üzerinde konumlandırmak için daha sezgisel bir yaklaşım sağladığını göstermek için niteliğini kullanarak çevirdim.


16

SVG'yi programlı olarak oluşturuyorsanız, basitleştirebilir ve böyle bir şey yapabilirsiniz:

  <g>
      <rect x={x} y={y} width={width} height={height} />
      <text
          x={x + width / 2}
          y={y + height / 2}
          dominant-baseline="middle"
          text-anchor="middle"
      >
          {label}
      </text>
  </g>

3
Olması Shouldsn't dominant-baselineve text-anchordeğil dominantBaselineve textAnchor?
Nathaniel M. Beaver

1
@ NathanielM.Beaver Evet, olmalı. İyi yakalama. Yukarıdaki kod, ne yazık ki camelCase kullanılarak adların yeniden adlandırılmasını gerektiren React'ten alınmıştır.
Brennan Cheung

13

Doğrudan text-anchor = "middle"mülkü kullanabilirsiniz . Dikdörtgenin ve metninizin üzerinde bir sarıcı svg öğesi oluşturmanızı öneririm. Bu şekilde, tüm öğeyi bir css seçici kullanarak kullanabilirsiniz. Metnin 'x' ve 'y' özelliğini% 50 olarak yerleştirdiğinizden emin olun.

    <svg class="svg-rect" width="50" height="40">
        <rect x="0" y="0" rx="3" ry="3" width="50" height="40" fill="#e7e7e7"></rect>
        <text x="50%" y="50%" text-anchor="middle" stroke="black" stroke-width="1px" dy=".3em">N/A</text>
    </svg>


7

Tam Ayrıntı Blogu: http://blog.techhysahil.com/svg/how-to-center-text-in-svg-shapes/

<svg width="600" height="600">
  <!--   Circle -->
  <g transform="translate(50,40)">
    <circle cx="0" cy="0" r="35" stroke="#aaa" stroke-width="2" fill="#fff"></circle>
    <text x="0" y="0" alignment-baseline="middle" font-size="12" stroke-width="0" stroke="#000" text-anchor="middle">HueLink</text>
  </g>
  
  <!--   In Rectangle text position needs to be given half of width and height of rectangle respectively -->
  <!--   Rectangle -->
  <g transform="translate(150,20)">
    <rect width="150" height="40" stroke="#aaa" stroke-width="2" fill="#fff"></rect>
    <text x="75" y="20" alignment-baseline="middle" font-size="12" stroke-width="0" stroke="#000" text-anchor="middle">HueLink</text>
  </g>
  
  <!--   Rectangle -->
  <g transform="translate(120,140)">
    <ellipse cx="0" cy="0" rx="100" ry="50" stroke="#aaa" stroke-width="2" fill="#fff"></ellipse>
    <text x="0" y="0" alignment-baseline="middle" font-size="12" stroke-width="0" stroke="#000" text-anchor="middle">HueLink</text>
  </g>
  
  
</svg>


Diğer çözümler varken firefox'ta ortalanmadı. codepen.io/anon/pen/oEByYr
tgf

Firefox 58.0.1 (64 bit) üzerinde test ettim, işe yarıyor. Sizin için çalışmadığı sürümden bahsedebilir misiniz?
Sahil Gupta

Firefox 58.0.2 64 bit. Metin olması gerekenden biraz daha yüksek. İlk başta kolayca fark edilmeyebilir, ancak kutunuz çok yakından uyuyorsa daha açıktır; yüksekliği azaltmayı deneyin.
tgf

6

alignment-baselineburada kullanılacak doğru özellik değil. Doğru yanıt bir arada kullanmaktır dominant-baseline="central"ve text-anchor="middle":

<svg width="200" height="100">
    <g>
        <rect x="0" y="0" width="200" height="100" style="stroke:red; stroke-width:3px; fill:white;"/>
        <text x="50%" y="50%" style="dominant-baseline:central; text-anchor:middle; font-size:40px;">TEXT</text>
    </g>
</svg>


2

Bir dikdörtgenin içine metin eklemenin bir yolu, rekt nesnenin içine bir DIV olan yabancı bir nesne eklemektir.

Bu şekilde, metin DIV'nin sınırlarına uyacaktır.

var g = d3.select("svg");
					
g.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width","100%")
.attr("height","100%")
.attr("fill","#000");


var fo = g.append("foreignObject")
 .attr("width","100%");

fo.append("xhtml:div")
  .attr("style","width:80%;color:#FFF;margin-right: auto;margin-left: auto;margin-top:40px")
  .text("Mussum Ipsum, cacilds vidis litro abertis Mussum Ipsum, cacilds vidis litro abertis Mussum Ipsum, cacilds vidis litro abertis");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.js"></script>
<svg width="200" height="200"></svg>


1

SVG kullanarak ortalanmış bir şey elde etmek için bir zamanım vardı, bu yüzden kendi küçük fonksiyonumu yuvarladım. umarım sana yardımcı olur. Yalnızca SVG öğeleri için çalıştığını unutmayın.

function centerinparent(element) { //only works for SVG elements
    var bbox = element.getBBox();
    var parentwidth = element.parentNode.width.baseVal.value;
    var parentheight = element.parentNode.height.baseVal.value;
    var newwidth = ((parentwidth / 2) - (bbox.width / 2)) - 2; //i start everything off by 2 to account for line thickness
    var newheight = ((parentheight / 2) - (bbox.height / 2)) - 2;
    //need to adjust for line thickness??

    if (element.classList.contains("textclass")) { //text is origined from bottom left, whereas everything else origin is top left
        newheight += bbox.height; //move it down by its height
    }

    element.setAttributeNS(null, "transform", "translate(" + newwidth + "," + newheight + ")");
    // console.log("centering BOXES:  between width:"+element.parentNode.width.baseVal.value + "   height:"+parentheight);
    // console.log(bbox);
}

1

Grafikteki metnin yatay ve dikey hizalaması için aşağıdaki CSS stillerini kullanmak isteyebilirsiniz. Özellikle, bunun dominant-baseline:middleyanlış olduğunu unutmayın , çünkü bu, üst ve alt arasında yarım olmaktan ziyade (genellikle) üst ve taban çizgisi arasında yarımdır. Ayrıca, bazı kaynaklar (örneğin Mozilla ) dominant-baseline:hangingyerine kullanılır dominant-baseline:text-before-edge. hangingIndic komut dosyaları için tasarlandığından , bu muhtemelen yanlıştır . Tabii ki, Latince, Hintçe, ideografların veya herhangi bir şeyin karışımını kullanıyorsanız, muhtemelen belgeleri okumalısınız .

/* Horizontal alignment */
text.goesleft{text-anchor:end}
text.equalleftright{text-anchor:middle}
text.goesright{text-anchor:start}
/* Vertical alignment */
text.goesup{dominant-baseline:text-after-edge}
text.equalupdown{dominant-baseline:central}
text.goesdown{dominant-baseline:text-before-edge}
text.ruledpaper{dominant-baseline:alphabetic}

Edit: Ben sadece Mozilla da dominant-baseline:baselinekesinlikle yanlış kullanır fark ettim : bu bile tanınan bir değer değil! Varsayılan yazı tipi varsayılan olduğunu varsayıyorum alphabetic, yani, onlar şanslı.

Daha fazla düzenleme: Safari (11.1.2) anlıyor text-before-edgeama anlamıyor text-after-edge. Ayrıca başarısız oluyor ideographic. Harika şeyler, Apple. Sonuçta alphabeticalçaltıcıları kullanmak ve izin vermek zorunda kalabilirsiniz . Afedersiniz.

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.