it-swarm.com.de

Können Sie steuern, wie eine SVG-Strichbreite gezeichnet wird?

Derzeit wird eine browserbasierte SVG-Anwendung erstellt. Innerhalb dieser App können verschiedene Formen vom Benutzer gestaltet und positioniert werden, einschließlich Rechtecken.

Wenn ich ein stroke-width auf ein SVG rect-Element von say 1px anwende, wird der Strich auf den Offset der rect angewendet und von verschiedenen Browsern auf unterschiedliche Weise eingefügt. Dies erweist sich als lästig, insbesondere, wenn ich versuche, die äußere Breite und die visuelle Position eines Rechtecks ​​zu berechnen und neben anderen Elementen zu positionieren. 

Zum Beispiel:

  • Firefox fügt 1px-Einfügung (unten und links) und 1px-Versatz (oben und rechts) hinzu.
  • Chrome fügt 1px-Einfügung (oben und links) und 1px-Versatz (unten und rechts) hinzu.

Meine einzige Lösung wäre bisher, die tatsächlichen Grenzen selbst zu zeichnen (wahrscheinlich mit dem Werkzeug path) und die Grenzen hinter dem strichenen Element zu positionieren. Diese Lösung ist jedoch eine unangenehme Problemumgehung, und ich ziehe es vor, diesen Weg möglichst nicht zu wählen.

Meine Frage ist also, können Sie steuern, wie ein stroke-width einer SVG auf Elemente gezeichnet wird.

169
Steve

Nein, Sie können nicht angeben, ob der Strich innerhalb oder außerhalb eines Elements gezeichnet wird. Ich habe der SVG-Arbeitsgruppe im Jahr 2003 einen Vorschlag für diese Funktionalität unterbreitet, aber sie erhielt keine Unterstützung (oder Diskussion).

SVG proposed stroke-location example, from phrogz.net/SVG/stroke-location.svg

Wie ich in dem Vorschlag festgestellt habe,

  • sie können das gleiche visuelle Ergebnis wie "innen" erzielen, indem Sie Ihre Strichbreite verdoppeln und dann einen Beschneidungspfad verwenden, um das Objekt an sich selbst zu schneiden, und
  • sie können dasselbe visuelle Ergebnis wie "außen" erzielen, indem Sie die Strichbreite verdoppeln und eine No-Stroke-Kopie des Objekts über sich selbst legen.

Edit: Diese Antwort kann in der Zukunft falsch sein. Diese Ergebnisse sollten mit SVG Vector Effects erreicht werden können, indem veStrokePath mit veIntersect (für 'inside') oder mit veExclude (für 'outside) kombiniert wird. Vektoreffekte sind jedoch immer noch ein funktionierendes Entwurfsmodul, für das ich noch keine Implementierungen finden kann.

Edit 2: Der SVG 2-Entwurf enthält eine stroke-alignment -Eigenschaft (mit center | inside | außerhalb möglicher Werte). Diese Eigenschaft kann es schließlich zu UAs machen.

Edit 3: Amüsant und enttäuschend hat die SVG-Arbeitsgruppe stroke-alignment aus SVG 2 entfernt. Sie können einige der Bedenken nach der Prosa hier sehen.

315
Phrogz

UPDATE: Das stroke-alignment-Attribut wurde am 1. April in eine komplett neue Spezifikation namens SVG Strokes verschoben.

Mit dem Entwurf des SVG 2.0-Editors vom 26. Februar 2015 (und möglicherweise seit 13. Februardie stroke-alignment-Eigenschaft ist vorhanden mit den Werten inner, center(Standardeinstellung) und outer

Es scheint auf dieselbe Weise zu funktionieren wie die stroke-location-Eigenschaft, die von @Phrogz vorgeschlagen wird, und der spätere stroke-position-Vorschlag . Diese Eigenschaft ist seit mindestens 2011 geplant, aber abgesehen von einer Anmerkung

SVG 2 muss eine Möglichkeit enthalten, die Hubposition anzugeben

, es wurde in der Spezifikation nie detailliert beschrieben, da es verzögert war - bis jetzt scheint es.

Kein Browser unterstützt diese Eigenschaft oder, soweit ich weiß, noch keine der neuen SVG 2-Funktionen, aber hoffentlich werden sie sobald die Spezifikation ausgereift ist. Dies ist eine Eigenschaft, auf die ich persönlich gedrängt habe, und ich bin wirklich glücklich, dass es endlich in der Spezifikation ist.

Es scheint einige Probleme zu geben, wie sich die Eigenschaft auf offenen Pfaden sowie in Schleifen verhalten sollte. Diese Probleme werden höchstwahrscheinlich Implementierungen über Browser hinweg verlängern. Allerdings werde ich diese Antwort mit neuen Informationen aktualisieren, wenn Browser beginnen Zur Unterstützung dieser Eigenschaft.

49
mnsth

Ich habe einen einfachen Weg gefunden, der einige Einschränkungen hat, aber für mich gearbeitet hat:

  • definiere die Form in defs
  • definieren Sie einen Clippfad, der auf die Form verweist
  • verwenden Sie es und verdoppeln Sie den Hub mit, da die Außenseite abgeschnitten ist

Hier ein Arbeitsbeispiel:

<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>

26
Jorg Janke

Hier ist eine Funktion, die berechnet, wie viele Pixel Sie mit dem angegebenen Strich oben, rechts, unten und links hinzufügen müssen, je nach Browser:

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
            };

        }

    };
7
Steve

Sie können CSS verwenden, um die Reihenfolge von Strichen und Füllungen zu gestalten. Streicheln Sie zuerst und füllen Sie dann Sekunde und erzielen Sie den gewünschten Effekt.

MDN bei Paint-order: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/Paint-order

CSS-Code:

Paint-order: stroke;
6
Xavier Ho

Wie bereits erwähnt, müssen Sie entweder einen Versatz der Wegkoordinaten des Strichs neu berechnen oder die Breite verdoppeln und dann die eine oder andere Seite maskieren, da SVG nicht nur die Strichausrichtung von Illustrator nicht unterstützt, PostScript auch nicht . 

Die Spezifikation für Striche in Adobes PostScript Manual 2. Ausgabe lautet: " 4.5.1 Strichen: Der Operator Stroke zeichnet eine Linie mit einer gewissen Stärke entlang des aktuellen Pfads. Für jede Gerade oder gekrümmtes Segment im Pfad, Strich zeichnet eine Linie, die zentriert auf dem Segment mit den Seiten parallel zum Segment ist. " (Hervorhebung ihrer)

Der Rest der Spezifikation hat keine Attribute zum Versetzen der Position der Linie. Wenn Sie Illustrator innen oder außen ausrichten können, wird der Offset des tatsächlichen Pfads neu berechnet (da er immer noch billiger ist als das Überdrucken und dann das Maskieren). Die Pfadkoordinaten im .ai-Dokument sind Verweise, nicht die, die gerastert oder in ein endgültiges Format exportiert werden. 

Da das native Format von Inkscape spezifiziertes SVG ist, kann es keine Funktion bieten, die den Spezifikationen fehlt. 

5
user1574945

Hier ist ein Workaround für innerer Randrect mit symbol und use.

Beispiel: 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>

Hinweis: Stellen Sie sicher, dass Sie ? in use durch reelle Werte ersetzen.

Background: Dies funktioniert, weil symbol ein neues Ansichtsfenster erstellt, indem symbol durch svg ersetzt und ein Element im Schatten-DOM erstellt wird. Diese svg des Schatten-DOMs wird dann mit Ihrem aktuellen SVG-Element verknüpft. Beachten Sie, dass svgs verschachtelt werden kann, und jede svg erstellt ein neues Ansichtsfenster, in dem alles, was sich überlappt, einschließlich des sich überlappenden Rahmens ausgeschnitten wird. Für einen viel detaillierteren Überblick über das, was los ist, lesen Sie diesen fantastischen Artikel von Sara Soueidan.

2
F Lekschas

Ich weiß nicht, wie hilfreich das sein wird, aber in meinem Fall habe ich nur einen anderen Kreis mit Rand erstellt und ihn in die andere Form „gelegt“.

0
Seb

Eine (schmutzige) mögliche Lösung ist die Verwendung von Mustern.

hier ist ein Beispiel mit einem inneren Dreieck:

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
max-lt