I am trying to achieve something like the below using SVG:
I have tried many solutions from this platform and so far, I have accomplished this:
<svg xmlns="http://www.w3.org/2000/svg" width="327.846" height="318.144" viewBox="0 0 327.846 318.144">
<defs>
<style>
.a {
fill:#000;
stroke-width: 25px;
stroke: rgba(255, 255, 255, 0.5);
}
</style>
</defs>
<path class="a" d="M172.871,0a28.906,28.906,0,0,1,25.009,14.412L245.805,97.1a28.906,28.906,0,0,1,0,28.989L197.88,208.784A28.906,28.906,0,0,1,172.871,223.2H76.831a28.906,28.906,0,0,1-25.009-14.412L3.9,126.092A28.906,28.906,0,0,1,3.9,97.1L51.821,14.412A28.906,28.906,0,0,1,76.831,0Z" transform="translate(111.598) rotate(30)"/>
</svg>
With the above code, I am able to add stroke but not image. And for below code, I am able to add the image but stroke is not appearing:
<svg xmlns="http://www.w3.org/2000/svg" width="327.846" height="318.144" viewBox="0 0 327.846 318.144">
<defs>
<style>
.a {
fill: #000;
stroke-width: 25px;
stroke: rgba(255, 255, 255, 0.5);
}
</style>
<clipPath id="image">
<path class="a"
d="M172.871,0a28.906,28.906,0,0,1,25.009,14.412L245.805,97.1a28.906,28.906,0,0,1,0,28.989L197.88,208.784A28.906,28.906,0,0,1,172.871,223.2H76.831a28.906,28.906,0,0,1-25.009-14.412L3.9,126.092A28.906,28.906,0,0,1,3.9,97.1L51.821,14.412A28.906,28.906,0,0,1,76.831,0Z"
transform="translate(111.598) rotate(30)" />
</clipPath>
</defs>
<image clip-path="url(#image)" height="100%" width="100%" xlink:href="http://placekitten.com/800/800"
preserveAspectRatio="xMidYMin slice"></image>
</svg>
What am I missing to get both onboard?
PS: Rounded corners are a must for the outer core and transparent layer.
Any help/suggestions will be very helpful. Thanks.
Set fill: transparent / fill: none for the path and use it again, as a child of svg
<svg xmlns="http://www.w3.org/2000/svg" width="327.846" height="318.144" viewBox="0 0 327.846 318.144">
<defs>
<style>
.a {
fill: none;
stroke-width: 25px;
stroke: rgba(255, 255, 255, 0.5);
}
</style>
<clipPath id="image">
<path transform="translate(111.598) rotate(30)" d="M172.871,0a28.906,28.906,0,0,1,25.009,14.412L245.805,97.1a28.906,28.906,0,0,1,0,28.989L197.88,208.784A28.906,28.906,0,0,1,172.871,223.2H76.831a28.906,28.906,0,0,1-25.009-14.412L3.9,126.092A28.906,28.906,0,0,1,3.9,97.1L51.821,14.412A28.906,28.906,0,0,1,76.831,0Z"/>
</clipPath>
</defs>
<image clip-path="url(#image)" height="100%" width="100%" xlink:href="http://placekitten.com/800/800" preserveAspectRatio="xMidYMin slice"></image>
<path class="a" d="M172.871,0a28.906,28.906,0,0,1,25.009,14.412L245.805,97.1a28.906,28.906,0,0,1,0,28.989L197.88,208.784A28.906,28.906,0,0,1,172.871,223.2H76.831a28.906,28.906,0,0,1-25.009-14.412L3.9,126.092A28.906,28.906,0,0,1,3.9,97.1L51.821,14.412A28.906,28.906,0,0,1,76.831,0Z" transform="translate(111.598) rotate(30)"/>
</svg>
comments on #Vishal Bhatt
One more queue: when I increase stroke-width, the curve on the
transparent layer becomes a sharp corner. How can I keep that rounded
when increasing stroke-width?
will help solve the problem - stroke-linejoin:round;
Used a wide stroke of 65px while keeping the inner rounding of the stroke
For solution instead of clip-Path one can try mask:
<svg xmlns="http://www.w3.org/2000/svg" width="327.846" height="318.144" viewBox="0 0 327.846 318.144">
<defs>
<style>
.a {
fill:white;
stroke-width: 65px;
stroke: rgba(255, 255, 255, 0.5);
stroke-linejoin:round;
}
</style>
<mask id="msk">
<path class="a" transform="translate(111.598) rotate(30)" d="M172.871,0a28.906,28.906,0,0,1,25.009,14.412L245.805,97.1a28.906,28.906,0,0,1,0,28.989L197.88,208.784A28.906,28.906,0,0,1,172.871,223.2H76.831a28.906,28.906,0,0,1-25.009-14.412L3.9,126.092A28.906,28.906,0,0,1,3.9,97.1L51.821,14.412A28.906,28.906,0,0,1,76.831,0Z"/>
</mask>
</defs>
<image mask="url(#msk)" height="100%" width="100%" xlink:href="http://placekitten.com/800/800" preserveAspectRatio="xMidYMin slice"></image>
</svg>
Update
Hexagon rotation command
transform="rotate(15 124.5 111.5)", here
15 - angle of rotation
124.5 111.5 - Hexagon rotation center coordinates
<svg xmlns="http://www.w3.org/2000/svg" width="327.846" height="318.144" viewBox="0 0 327.846 318.144">
<defs>
<style>
.a {
fill:white;
stroke-width: 45px;
stroke: rgba(255, 255, 255, 0.5);
stroke-linejoin:round;
}
</style>
<mask id="msk">
<path class="a" transform="translate(50 50) rotate(15 124.5 111.5)" d="M172.871,0a28.906,28.906,0,0,1,25.009,14.412L245.805,97.1a28.906,28.906,0,0,1,0,28.989L197.88,208.784A28.906,28.906,0,0,1,172.871,223.2H76.831a28.906,28.906,0,0,1-25.009-14.412L3.9,126.092A28.906,28.906,0,0,1,3.9,97.1L51.821,14.412A28.906,28.906,0,0,1,76.831,0Z"/>
</mask>
</defs>
<image mask="url(#msk)" height="100%" width="100%" xlink:href="http://placekitten.com/800/800" preserveAspectRatio="xMidYMin slice"></image>
</svg>
Problem with clip-path or masks, is they need to have unique ids if you have multiple SVGs on the page.
One way around this is to create the SVG client-side; and generate a unique id for every clip-path
While we're at it might as well simplify that Hexagon path
Wrapped in a Custom Element (no shadowDOM required with that unique id) you get:
<style>
svg {
width: 148px;
background: teal;
}
</style>
<svg-hexed-image ></svg-hexed-image>
<svg-hexed-image src="http://placekitten.com/800/800"></svg-hexed-image>
<svg-hexed-image rotate="30" src="http://placekitten.com/801/801"></svg-hexed-image>
<svg-hexed-image rotate="45" stroke="red" opacity=".5" src="http://placekitten.com/300/300"></svg-hexed-image>
<script>
customElements.define('svg-hexed-image', class extends HTMLElement {
connectedCallback() {
let img = this.getAttribute("src") || "http://placekitten.com/120/120";
let strokewidth = this.getAttribute("stroke-width") || "3";
let opacity = this.getAttribute("opacity") || ".5";
let stroke = this.getAttribute("stroke") || "white";
let rotate = this.getAttribute("rotate") || 0;
let transform = `transform="rotate(${rotate} 23 23)"`;
// make very sure for a unique id:
let id = "id" + btoa(img) + (new Date() / 1);
let d = `M31 3.5a5 5 90 014 3l8 14a5 5 90 010 5l-8 14a5 5 90 01-4 3h-16a5 5 90 01-4-3l-8-14a5 5 90 010-5l8-14a5 5 90 014-3z`;
// now write HTML:
this.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 46 46">
<defs><clipPath id="${id}"><path fill="none" ${transform} d="${d}"></clipPath></defs>
<image clip-path="url(#${id})" height="100%" width="100%" href="${img}"></image>
<path fill="none" stroke="${stroke}" stroke-width="${strokewidth}"
${transform} opacity="${opacity}" d="${d}"/></svg>`;
}
});
</script>
I have a following html:
<div id="divVis2" class="divVis">
<svg width="1540" height="345">
<defs>
<marker id="normal" viewBox="0 -5 10 10" refX="15" refY="-1.5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M0,-5L10,0L0,5"></path>
</marker>
<marker id="anomaly" viewBox="0 -5 10 10" refX="15" refY="-1.5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M0,-5L10,0L0,5"></path>
</marker>
</defs>
<g>
<path class="anomaly" marker-end="url(#anomaly)" d="M908.3739002256449,176.0182689704716L661.9527686239043,249.64760217208658"></path>
<path class="normal" marker-end="url(#normal)" d="M660.4045373167714,246.37428873149702L879.5700343222044,98.59473202412175"></path>
<path class="normal" marker-end="url(#normal)" d="M878.0019325543491,95.25420149730667L631.216835426003,167.4248240636326"></path>
</g>
<g>
<g transform="translate(889.5195255254339,91.88595979689137)">
<circle class="normal" r="12"></circle>
<text x="0" y="4" class="normal">133</text>
</g>
<g transform="translate(619.6992424549181,170.7930657640479)">
<circle class="normal" r="12"></circle>
<text x="0" y="4" class="normal">134</text>
</g>
<g transform="translate(650.4550461135419,253.0830609587274)">
<circle class="anomaly" r="12"></circle>
<text x="0" y="4" class="normal">137</text>
</g>
<g transform="translate(919.8716227360072,172.5828101838308)">
<circle class="normal" r="12"></circle>
<text x="0" y="4" class="normal">136_1</text>
</g>
</g>
</svg>
</div>
Its corresponding css is:
#divVis2 path {
fill: none;
/* stroke: #666; */
stroke-width: 0.5px;
}
#divVis2 path.normal {
stroke: #808080;
}
#divVis2 path.anomaly {
stroke: red;
stroke-width: 1.5px;
}
/* for the marker */
#divVis2 #normal {
fill: black;
stroke-width: 0.5px;
}
#divVis2 #anomaly {
fill: red;
stroke-width: 1.5px;
}
#divVis2 circle.normal {
fill: #ccc;
stroke: #ffffff;
stroke-width: 0.5px;
}
#divVis2 circle.anomaly {
fill: #ff0000;
stroke: #ffffff;
stroke-width: 0.5px;
}
#divVis2 text.normal {
font: 7px sans-serif;
pointer-events: none;
fill: black;
text-anchor:middle;
}
#divVis2 text.label {
font: 9px sans-serif;
pointer-events: none;
fill: blue;
text-anchor:middle;
}
The corresponding output in browser is:
Why are the arrows not getting displayed at the end of each path? I am unable to find out the problem in css selectors.
Here is a jsfiddle: http://jsfiddle.net/onh7t53o/
#divVis2 path {
fill: none;
/* stroke: #666; */
stroke-width: 0.5px;
}
has a higher specificity for the markers than
#divVis2 #normal {
fill: black;
stroke-width: 0.5px;
}
so the marker paths are fill="none" and the stroke-width is so thin because the markers are small that you can't see it.
I had this problem in an angular app that was using a <base> tag. In the context of a rich web app like one built on Angular, where you need to set the <base> tag to make HTML5-style navigation work, it can get messy to try to fix that in a permanent way.
In my case, the app I was working on was showing a SVG-based interactive diagram builder that would change the app url as I selected elements therein.
What I did was to add a global event handler that would fix all url(#...) inline styles in any <path> element found in the page:
$rootScope.$on 'fixSVGReference', ->
$('path').each ->
$path = $ this
if (style = $path.attr 'style')?
$path.attr 'style', style.replace /url\([^)#]*#/g, "url(#{location.href}\#"
Then trigger this handler in key places, like when the app state changes (I'm using ui-router)
$rootScope.$on '$stateChangeSuccess', ->
$timeout (-> $rootScope.$emit 'fixSVGReference'), 5
As well as anywhere where I know there'd be new/updated paths like these. Here, the $timeout thing is to account for the fact that the DOM nodes really are changed asynchronously sometime after the $stateChangeSuccess event is triggered.