Fill SVG element with with a background-image with an offset - html

I want to do something similar to this Fill SVG path element with a background-image
However, I want to shift/offset the image. With CSS, it can easily done by setting background-image and background-position. How do I do it with SVG?

You can use patternTransform on the pattern element to transform the pattern; it works just like the transform attribute you may already be familiar with. See the documentation for details.

You can use a pattern and a SVG element with the fill attribute.
Here is an example: insert an image at position (10, 10) with a (40, 550) offset and a size (420, 340). Note that you must set the correct x/y and transform="translate(-x1 -y2)".
<p>
Original image
</p>
<svg version="1.1" width="500" height="400" style="background-color: #EEE;">
<defs>
<pattern id="europe" patternUnits="userSpaceOnUse"
width="1456px" height="1094px">
<image xlink:href="https://i.imgur.com/MQHYB.jpg"/>
</pattern>
</defs>
<rect fill="url(#europe)" transform="translate(-30 -540)"
x="40" y="550" width="420" height="340"/>
</svg>

Related

Polygon in HTML SVG is clipped

I create a star via an SVG polygon. It draws fine when the stroke width is 1, but with wider strokes, the bottom left (and only the bottom left) vertex gets cut off. Does anyone know why this happens (and how to fix it)?
The following snippets (which I displayed using https://www.w3schools.com 'try it') show the problem, both with the original star and with just the bottom 'arm' isolated as a simple triangle:
<svg height="200" width="200">
<polygon points="16,53 23,35 8,25 25,25 30,8 36,25 53,25 38,35 45,53 30,41" style="fill:none;stroke:purple;stroke-width:7" />
Sorry, your browser does not support inline SVG.
</svg>
<svg height="300" width="300">
<polygon points="120,164 64,212 92,140" style="fill:none;stroke:purple;stroke-width:9" />
Sorry, your browser does not support inline SVG.
</svg>
The default stroke-miterlimit is 4. You need a larger number than that because your star is quite pointy.
<svg height="200" width="200">
<polygon transform="translate(10, 10)" points="16,53 23,35 8,25 25,25 30,8 36,25 53,25 38,35 45,53 30,41" style="fill:none;stroke:purple;stroke-width:7; stroke-miterlimit:10" />
Sorry, your browser does not support inline SVG.
</svg>

SVG Pattern Doesn't Show on Page

I am completely clueless, what is going wrong with my svg pattern. I defined it in the def section of the svg and then tried to reference it. But it doesn't show up once I include the svg in an img-tag. If I open it on itself in the browser everything is good though.
See the following examples:
http://kijani.co/img/sketch/index.html
http://kijani.co/img/sketch/livingroom.svg
And my code:
<defs>
<pattern id="paper" patternUnits="userSpaceOnUse" width="200" height="200">
<image xlink:href="http://kijani.co/img/pattern/paper.jpg" width="200" height="200"/>
</pattern>
</defs>
<g id="background">
<path id="paper" fill="url(#paper)" d="..."/>
</g>
This might be a really stupid question, but I am fairly new to svg and couldn't find a solution anywhere so far.
This is svg's referencing mode probrem.
Using img element to display svg image is restrected for refering outer resources.
So you should use object element to display svg image, or embed pattern image into svg by data scheme format.

How do I tell if a DOM element is HTML or SVG?

I am writing a piece of infrastructure that needs to be applied differently to HTML elements versus SVG elements. Given a DOM node, how can I tell if it''s an SVG or HTML element?
You may try something like the following:
if(document.getElementById("el") instanceof SVGElement) {
console.log("It's an SVG element");
}
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="300" height="300">
<g id="firstGroup">
<rect id="el" width="100" height="50" x="40" y="20" fill="blue" />
<text x="40" y="100">This is a basic SVG document!</text>
</g>
</svg>
Note that the <svg> element itself is actually an HTML element containing SVG elements - which means that, perhaps surprisingly, the <svg> HTML element is not an SVG element, hence:
console.log(document.createElement("svg") instanceof SVGElement)) // => false
I'm not sure how cross browser compatible it is but I was poking through the DOM properties and saw a ownerSVGElement which seems promising?
Here goes what I was toying around with: http://jsbin.com/uMIronal/4/edit?html,js,output

Define a source rectangle for an SVG <image> like you can in HTML Canvas or CSS

In HTML5 Canvas you can draw an image as a whole, or draw only a piece of it, or draw only a piece of it to an arbitrary rectangle (which may scale it).
Here's an example of all three:
Here's the code used to draw those three examples:
ctx.drawImage(img, 0, 0);
ctx.drawImage(img,
// source rect
50, 50, 70, 70,
// destination rect
0, 200, 70, 70
);
ctx.drawImage(img,
// source rect
50, 50, 70, 70,
// destination rect
0, 270, 30, 30
);
This is also relatively easy to do in CSS.
My question is, for a given image, how can you achieve the same effects using SVG <image> elements?
How do I, for instance, make an Image that occupies 50x50 pixels, that shows a portion of the referenced href, as in the first crop?
One could use a clipping path to crop part of the image, but then you (seemingly) cannot use a clipping path of a larger image while defining the width and height of the <image> element to be small.
Here's a fiddle with the above code plus a sample SVG element:
http://jsfiddle.net/wcjVd/
You don't need a clipPath at all, you can use the viewBox to do what you want
<svg width="70px" height="70px" viewBox="50 50 70 70">
<image x="0" y="0" width="200" height="200"
xlink:href="http://placekitten.com/200/200" clip-path="url(#myClip)">
</image>
</svg>
The value of the viewBox attribute is a list of four numbers <min-x>, <min-y>, <width> and <height>, separated by whitespace and/or a comma, which specify a rectangle in user space which should be mapped to the bounds of the viewport established by the given element, taking into account attribute preserveAspectRatio.
Demo Here
Glad I can help you here because you helped me with a Canvas project a few months ago!
Edit
You said that you needed to transform them also, so after an hour I came up with these couple options:
If you can, transform the original image and do the same effect. Demo here If you are wanting the cropped image at the origin (0,0) then the code would look like
<defs>
<clipPath id="myClip">
<rect x="0" y="0" width="70" height="70"/>
</clipPath>
</defs>
<image x="-50" y="-50" width="200" height="200" clip-path="url(#myClip)"
xlink:href="http://placekitten.com/200/200"></image>
OR, more satisfactorily, you could do it using a use
<defs> <!-- Your original clip -->
<clipPath id="myClip">
<rect x="50" y="50" width="70" height="70"/>
</clipPath>
</defs>
<image id="myImage" x="0" y="0" width="200" height="200"
xlink:href="http://placekitten.com/200/200" clip-path="url(#myClip)" />
<!-- Hide the original (I made a layer of white) -->
<!-- This is the part that you could probably find a better way of doing -->
<rect x="0" y="0" width="200" height="200" style="fill:white" />
<!-- Create what you want how you want where you want it -->
<use x="-50" y="-50" width="200" height="200" xlink:href="#myImage" transform="scale(1.3)"/>
</svg>
Demo for that approach here

Is it possible to mix HTML form input tags with SVG, or to use SVG to lay out a form?

We like using jQuery templates with SVG for example to show a Product with a nicely styled price.
Say we have an SVG that represents a complicated layout. Is it possible to have the <input> tags nested in the SVG and still work within HTML 5? Are there alternatives within SVG to input data from the user, maybe extracting them with Knockout.js?
I know you could use the SVG in the sense of a background graphic and hack the positions so that the form fields line up. I am really interested in having the input statements flowed by the SVG if possible.
You can use foreignObject. A small example :
<?xml version="1.0" standalone="yes"?>
<svg xmlns = "http://www.w3.org/2000/svg" width="100%" height="100%">
<rect x="25" y="25" width="250" height="200" fill="#ff0000" stroke="#000000"/>
<foreignObject x="50" y="50" width="200" height="150">
<body xmlns="http://www.w3.org/1999/xhtml">
<form>
<input type="text"/>
<input type="text"/>
</form>
</body>
</foreignObject>
<circle cx="60" cy="80" r="30" fill="#00ff00" fill-opacity="0.5"/>
</svg>
This is a standard SVG, but I added HTML elements between the rect and the circle using the foreignObject tag. The stack order is respected, the circle being in front of the inputs.
Other solutions exists in "pure" SVG, but they heavily rely on JavaScript. Here an example : http://www.carto.net/papers/svg/gui/textbox/