title in SVG: how to make it appear faster? - html

I have an html page with a JS script generating a SVG image made of many polygons (SVG is added inline inside the HTML).
I gave some of them a title, so that the user can hoover and get a caption.
Example:
<?xml version="1.0" standalone="no"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<polygon points="0,10 5,7 10,10 10,16 5,19 0,16" fill="rgb(114,132,56)" stroke="rgb(114,132,56)" stroke-width="1"><title>Washington</title></polygon>
</svg>
There is a delay for the browser to display this text.
I would like for it to appear faster.
Is this doable? Or do I have to change the structure to use something like map for image?
I found how to customize the appearance of this tooltip, but not how to change the speed for display.

There is no way to change this via CSS. However you can mimic the tooltip with Javascript. Here is an example improving on a solution from #Timmmm. The improvement consists in preserving the title elements for users using a screen reader.
function showTooltip(event) {
let element = event.target;
let tooltipElement = document.getElementById('tooltip');
let title;
if (!element.dataset.title) {
let titleElement = element.querySelector('title');
title = titleElement.innerHTML;
event.target.setAttribute('data-title', title);
titleElement.parentNode.removeChild(titleElement);
} else {
title = element.dataset.title;
}
tooltipElement.innerHTML = title;
tooltipElement.style.display = 'block';
tooltipElement.style.left = event.pageX + 10 + 'px';
tooltipElement.style.top = event.pageY + 10 + 'px';
}
function hideTooltip() {
var tooltip = document.getElementById('tooltip');
tooltip.style.display = 'none';
}
#tooltip {
background: cornsilk;
border: 1px solid black;
border-radius: 3px;
padding: 2px 4px;
}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<polygon
onmousemove="showTooltip(event);"
onmouseout="hideTooltip();"
points="0,10 5,7 10,10 10,16 5,19 0,16"
fill="rgb(114,132,56)"
stroke="rgb(114,132,56)"
stroke-width="1">
<title>Washington</title>
</polygon>
</svg>
<div id="tooltip" style="position: absolute; display: none;"></div>
To optimise for small file size when many shapes are present, both the styles and event binding can be moved out of the SVG and into Css / Javascript:
function showTooltip(event) {
let element = event.target;
let tooltipElement = document.getElementById('tooltip');
let title;
if (!element.dataset.title) {
let titleElement = element.querySelector('title');
title = titleElement.innerHTML;
event.target.setAttribute('data-title', title);
titleElement.parentNode.removeChild(titleElement);
} else {
title = element.dataset.title;
}
tooltipElement.innerHTML = title;
tooltipElement.style.display = 'block';
tooltipElement.style.left = event.pageX + 10 + 'px';
tooltipElement.style.top = event.pageY + 10 + 'px';
}
function hideTooltip() {
var tooltip = document.getElementById('tooltip');
tooltip.style.display = 'none';
}
document.addEventListener('DOMContentLoaded', function(event) {
const tooltipTriggers = document.querySelectorAll('polygon');
Array.from(tooltipTriggers).map(trigger => {
trigger.addEventListener('mousemove', showTooltip);
trigger.addEventListener('mouseout', hideTooltip);
})
});
.tooltip {
position: absolute;
background: cornsilk;
border: 1px solid black;
border-radius: 3px;
padding: 2px 4px;
}
svg .grey {
fill: rgb(114, 132, 56);
stroke: rgb(114, 132, 56);
stroke-width: 1;
}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<polygon
class="grey"
points="0,10 5,7 10,10 10,16 5,19 0,16">
<title>Washington</title>
</polygon>
</svg>
<div id="tooltip" class="tooltip" style="display: none;"></div>

Related

html css svg path align center on screen

I want to show dynamically svg but every time svg position is changing and sometimes overflowing from screen. I want to alignt this svg path center of screen.
function App() {
const [city, setCity] = useState("");
useEffect(() => {
setCity(cities[Math.floor(Math.random() * cities.length)]);
}, []);
return (
<div>
<div className="svg-div">
<svg height="100%" width="100%" className="svg" viewBox="0 0 600 600">
<g>
<path id="city" d={city?.d} />
</g>
</svg>
</div>
<Input cities={cities} />
</div>
);
}
export default App;
Most likely your dynamically retrieved paths are parts of a complete map svg.
So the surrounding space or overflow ist caused by the paths' coordinates which are relative to the original map viewBox.
Example 1: extracted map region
.svgAssetHidden {
visibility: hidden;
position: absolute;
width: 0;
height: 0;
overflow: hidden;
}
.map,
.svg-use
{
display: block;
width: 20em;
border: 1px solid #ccc;
fill:#ccc;
}
.map path{
stroke-width:2;
stroke:#fff;
}
<p>Complete map</p>
<svg id="svgMapComplete" class="map" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path id="region1" d="M36.4 21.3l-5.9-11.8l7.3-1l2.9 2.8l7.3-1.9l-2.6-3.9l-1.5-3.1l7.1-2.3l13.6 3.3l25.7-1.2l3.6 3.9l-12 6.4l-3.6 7.1l-29 7.4l-12.9-5.7z" />
<path id="region2" d="M100.1 30.2l-3.7 11.2l-9.5 15.1c0 0-26.1 1.3-27.4 1.3c-1.2 0-2.9 8.4-3.4 10.7l-19.1-2.2l-6.5-15.1l-3.3-12.9l-21.4-12.3l6.8-9.4l10.9-6.2l7-1l5.9 11.7l13 5.9l29-7.4l-1.4 2.7l9.6 3.7l10.8-5.4l2.7 9.6z" />
<path id="region3" d="M37 66.3l19.2 2.2c0 0.1 0 0.2-0.1 0.3c-0.4 1.8-10 6.8-10 6.8l-32.3 24.2l-13.8-6.7l4.1-26.8l6.3-11.4l-2.8-10.7l-6.3-11.9l4.5-6.3l21.4 12.2l3.3 12.9l6.5 15.2z" />
</svg>
<p>Map fragment – display region</p>
<svg id="svgMapCompletePart" class="map" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" >
<path id="region3" d="M37 66.3l19.2 2.2c0 0.1 0 0.2-0.1 0.3c-0.4 1.8-10 6.8-10 6.8l-32.3 24.2l-13.8-6.7l4.1-26.8l6.3-11.4l-2.8-10.7l-6.3-11.9l4.5-6.3l21.4 12.2l3.3 12.9l6.5 15.2z" />
</svg>
The southwestern region still has surrounding space since it's relative to the parent map's initial viewBox.
To circumvent this problem you could wrap all path elements in a <symbol>element containing its own viewbox – you will need to get each region's boundary box via getBBox().
Example 2: show regions wrapped in symbol elements
/**
* select
*/
let svg = document.querySelector("#svgMap");
let regions = svg.querySelectorAll("path");
/**
* query elements to be wrapped in symbols
**/
function wrapSymbols(parent, els) {
els.forEach(function(el, i) {
let symbol = wrapSymbol(el, i);
parent.appendChild(symbol);
});
}
/**
* wrap path in symbol element
**/
function wrapSymbol(el, i = 0) {
let symbol = document.createElementNS("http://www.w3.org/2000/svg", "symbol");
symbol.id = el.id ? "symbol-" + el.id : "symbol-" + i;
let symbolBB = el.getBBox();
let symbolVBox = [symbolBB.x, symbolBB.y, symbolBB.width, symbolBB.height];
symbolVBox.forEach(function(el, i) {
symbolVBox[i] = +symbolVBox[i].toFixed(2);
});
symbol.setAttribute("viewBox", symbolVBox.join(" "));
symbol.insertAdjacentElement("beforeend", el);
return symbol;
}
/**
* create example use html
**/
function getExampleUseHTML(el) {
let useHtml = "";
let symbols = document.querySelectorAll("symbol");
symbols.forEach(function(el, i) {
let vB = el.getAttribute("viewBox").split(" ");
useHtml +=
'<svg class="svg-use" viewBox="0 0 ' +
vB[2] +
" " +
vB[3] +
'">\n' +
'<use class="use-symbol" href="#' +
el.id +
'" />\n' +
"</svg>\n";
});
return useHtml;
}
/**
* render example use html
*/
wrapSymbols(svg, regions);
let useHTML = getExampleUseHTML(svg);
document.body.insertAdjacentHTML(
"beforeend",
'<div class="map-cell-flex">' + useHTML + "</div>"
);
.svgAssetHidden {
visibility: hidden;
position: absolute;
width: 0;
height: 0;
overflow: hidden;
}
.map-cell-flex {
display: flex;
flex: 1;
}
.map,
.svg-use {
border: 1px solid #ccc;
fill: #ccc;
}
<p>Map fragment – display region by use element</p>
<svg id="svgMap" class="svgAssetHidden" xmlns="http://www.w3.org/2000/svg">
<path d="M36.4 21.3l-5.9-11.8l7.3-1l2.9 2.8l7.3-1.9l-2.6-3.9l-1.5-3.1l7.1-2.3l13.6 3.3l25.7-1.2l3.6 3.9l-12 6.4l-3.6 7.1l-29 7.4l-12.9-5.7z" />
<path d="M100.1 30.2l-3.7 11.2l-9.5 15.1c0 0-26.1 1.3-27.4 1.3c-1.2 0-2.9 8.4-3.4 10.7l-19.1-2.2l-6.5-15.1l-3.3-12.9l-21.4-12.3l6.8-9.4l10.9-6.2l7-1l5.9 11.7l13 5.9l29-7.4l-1.4 2.7l9.6 3.7l10.8-5.4l2.7 9.6z" />
<path d="M37 66.3l19.2 2.2c0 0.1 0 0.2-0.1 0.3c-0.4 1.8-10 6.8-10 6.8l-32.3 24.2l-13.8-6.7l4.1-26.8l6.3-11.4l-2.8-10.7l-6.3-11.9l4.5-6.3l21.4 12.2l3.3 12.9l6.5 15.2z" />
</svg>
Once you've wrapped your path elements in a symbol you can place your regions via <use>
Symbol definition:
<symbol id="symbol-0" viewBox="30.5 0.1 63.4 26.9">
<path d="M36.4 21.3l-5.9-11.8l7.3-1l2.9 2.8l7.3-1.9l-2.6-3.9l-1.5-3.1l7.1-2.3l13.6 3.3l25.7-1.2l3.6 3.9l-12 6.4l-3.6 7.1l-29 7.4l-12.9-5.7z" />
</symbol>
Use instance:
<svg class="svg-use" viewBox="0 0 63.4 26.9">
<use class="use-symbol" href="#symbol-0" />
</svg>
Add this css
. svg-div{
display: flex:
justify-content: center;
align-items: center;
}

How to style the title tag inside a rect in a SVG? [duplicate]

This question already has answers here:
How to add a tooltip to an svg graphic?
(7 answers)
Closed 2 years ago.
I have a title tag inside a rect:
<rect width="37" height="38" rx="10" stroke="none">
<title>
ADM-04
Ana Fretta
Optiplex 3070
</title>
</rect>
Which looks like this when you hover over the rect:
Is there any way to style the tooltip?
with a reference to Timmmm's answer, here's a working demo of adding tooltip to sag element
const tooltips = document.querySelector('.tooltips');
function add_tooltip(ele) {
const el = document.querySelector(ele);
let tp = document.createElement('div');
tp.setAttribute('class', 'tooltip');
tooltips.appendChild(tp);
tp.innerHTML = el.querySelector('title').innerHTML;
el.addEventListener('mousemove', e => {
tp.style.left = e.clientX + 10 + "px";
tp.style.top = e.clientY + 10 + "px";
tp.style.display = 'flex';
});
el.addEventListener('mouseleave', () => {
tp.style.display = "none";
});
}
add_tooltip('rect');
.tooltips{
position: fixed;
width: 100vw;
height: 100vh;
top: 0;
left: 0;
z-index: -1000;
}
.tooltip {
background: cornsilk;
border: 1px solid black;
border-radius: 5px;
padding: 5px;
position: fixed;
display: none;
width: 100px;
height: 100px;
display: none;
justify-content: center;
align-items: center;
}
<div class="tooltips">
</div>
<svg>
<rect width="37" height="38" rx="10" stroke="black" fill="white">
<title>
ADM-04
Ana Fretta
Optiplex 3070
</title>
</rect>
</svg>

jQuery removeClass function does not work

I'm trying to remove an element's class on an event. I'm using jQuery library, and using the function removeClass to remove the element's class.
However, when inspecting the element's classes, the class I removed is not removed off the list.
In order to inspect the element's classes, there is the following code-block:
console.log($zoomToolOBJ.attr('class'));
$zoomToolOBJ.removeClass('onTool');
console.log($zoomToolOBJ.attr('class'));
As I view the console, I do see onTool class in both console.log (means the class onTool was not removed).
Here is my code:
<!DOCTYPE html>
<html>
<head>
<title>Ado designed</title>
<style>
.tools {
display: flex;
flex-direction: column;
overflow: hidden;
padding: 8px;
border-radius: 8px;
box-shadow: 3px 3px 3px #c5c5c5,
-3px 3px 3px #c5c5c5;
}
.toolIcon {
cursor: pointer;
transition: all .3s ease;
height: 60px;
width: 60px;
padding: 15px;
border-radius: 8px;
fill: #4d4d4d;
}
.toolIcon:not(:last-child) {
margin-bottom: 10px;
}
.toolIcon:hover {
background-color: #008cba;
fill: #FFF;
}
.onTool {
background-color: #008cba;
fill: #FFF;
}
</style>
</head>
<body>
<div class="tools">
<svg id="zoomTool" class="toolIcon onTool" viewBox="0 0 512 512">
<path
d="m289.8,200.2h-49.3v-49.3c0-11.3-9.1-20.4-20.4-20.4-11.3,0-20.4,9.1-20.4,20.4v49.3h-49.3c-11.3,0-20.4,9.1-20.4,20.4 0,11.3 9.1,20.4 20.4,20.4h49.3v49.3c0,11.3 9.1,20.4 20.4,20.4 11.3,0 20.4-9.1 20.4-20.4v-49.3h49.3c11.3,0 20.4-9.1 20.4-20.4 0-11.3-9.2-20.4-20.4-20.4z" />
<path
d="m220.2,388.7c-92.9,0-168.2-75.2-168.2-168.1s75.3-168.1 168.2-168.1 168.1,75.3 168.1,168.1-75.3,168.1-168.1,168.1zm274.8,78l-113.3-113.3c29.7-36.1 47.6-82.4 47.6-132.8 0-115.5-93.6-209.2-209.2-209.2s-209.1,93.7-209.1,209.2 93.6,209.2 209.2,209.2c50.4,0 96.6-17.8 132.7-47.5l113.3,113.3c5.2,5.3 21.1,7.9 28.9,0 7.9-8 7.9-20.9-0.1-28.9z" />
</svg>
<svg id="vectorTool" class="toolIcon" viewBox="0 0 492.426 492.426">
<polygon
points="261.232,434.981 261.232,57.445 305.607,101.82 326.82,80.606 246.213,0 165.607,80.606 186.82,101.82
231.232,57.408 231.232,435.019 186.82,390.606 165.607,411.82 246.213,492.426 326.82,411.82 305.607,390.606 " />
</svg>
<svg id="proportionsTool" class="toolIcon" viewBox="0 0 512 512">
<path d="M504.843,72.607L439.386,7.15c-9.534-9.534-25.048-9.533-34.582,0L281.561,130.392c-3.086,3.087-3.086,8.089,0,11.176
c3.086,3.085,8.089,3.085,11.175,0L415.978,18.326c1.634-1.634,3.806-2.533,6.116-2.533s4.482,0.899,6.116,2.533l65.458,65.457
c1.633,1.633,2.533,3.805,2.533,6.116c0,2.31-0.9,4.482-2.533,6.115l-16.064,16.064L435.515,69.99
c-3.086-3.085-8.089-3.085-11.175,0c-3.086,3.087-3.086,8.089,0,11.176l42.088,42.088l-18.353,18.353l-18.498-18.498
c-3.086-3.085-8.089-3.085-11.175,0c-3.086,3.087-3.086,8.089,0,11.176l18.498,18.497l-18.353,18.353l-18.498-18.498
c-3.086-3.085-8.089-3.085-11.175,0c-3.086,3.087-3.086,8.089,0,11.176l18.498,18.497l-18.353,18.353l-42.089-42.09
c-3.085-3.084-8.089-3.086-11.175,0c-3.086,3.087-3.086,8.089,0,11.176l42.089,42.089l-18.353,18.353l-18.498-18.498
c-3.086-3.085-8.089-3.085-11.175,0c-3.086,3.087-3.086,8.089,0,11.176l18.497,18.497l-15.526,15.526L255.1,179.203l14.45-14.451
c3.086-3.087,3.086-8.089,0-11.176c-3.086-3.085-8.089-3.085-11.175,0l-14.451,14.451L98.156,22.264
C88.018,12.126,74.539,6.543,60.202,6.543c-14.337,0.001-27.816,5.584-37.953,15.722C12.11,32.403,6.527,45.881,6.527,60.219
c0,14.337,5.583,27.816,15.721,37.954l145.765,145.765L7.157,404.797c-9.534,9.535-9.534,25.048,0,34.583l65.457,65.458
C77.232,509.456,83.373,512,89.905,512c6.532,0,12.673-2.544,17.291-7.162L268.054,343.98l11.457,11.457
c3.086,3.085,8.089,3.085,11.175,0c3.086-3.087,3.086-8.089,0-11.176l-15.814-15.814c-0.307-0.486-0.667-0.948-1.09-1.371
c-0.423-0.423-0.885-0.783-1.37-1.09L101.189,154.763l21.191-21.191l13.102,13.102c1.543,1.542,3.565,2.314,5.588,2.314
s4.045-0.772,5.588-2.314c3.086-3.087,3.086-8.089,0-11.176l-13.101-13.101l21.191-21.191l83.579,83.579
c0.003,0.004,0.006,0.007,0.01,0.011c0.004,0.004,0.007,0.006,0.011,0.01l88.081,88.081c0.218,0.288,0.45,0.57,0.713,0.833
s0.544,0.495,0.832,0.713l117.268,117.268l-21.191,21.191L305.735,294.576c-0.071-0.077-0.135-0.158-0.21-0.232l-47.182-47.183
c-0.078-0.078-0.163-0.146-0.243-0.22l-83.343-83.342c-3.086-3.085-8.089-3.085-11.175,0c-3.086,3.087-3.086,8.089,0,11.176
l249.291,249.291l-21.192,21.191l-75.096-75.097c-3.086-3.085-8.089-3.085-11.175,0c-3.086,3.087-3.086,8.089,0,11.176
l80.684,80.684c0.767,0.767,1.717,1.386,2.728,1.778l95.478,37.069c1.506,0.584,3.076,0.868,4.634,0.868
c3.342,0,6.624-1.308,9.073-3.759c3.591-3.593,4.721-8.973,2.88-13.707l-37.108-95.434c-0.392-1.008-1.011-1.96-1.777-2.725
L343.963,268.071l160.88-160.881C514.378,97.655,514.378,82.142,504.843,72.607z M256.882,332.805l-15.507,15.503l-18.498-18.498
c-3.086-3.085-8.089-3.085-11.175,0c-3.086,3.087-3.086,8.089,0,11.176l18.498,18.498l-18.353,18.353l-42.089-42.089
c-3.086-3.085-8.089-3.085-11.175,0c-3.086,3.087-3.086,8.089,0,11.176l42.089,42.089l-18.353,18.353l-18.498-18.498
c-3.086-3.085-8.089-3.085-11.175,0c-3.086,3.087-3.086,8.089,0,11.176l18.498,18.497l-18.353,18.353l-18.498-18.498
c-3.086-3.085-8.089-3.085-11.175,0c-3.086,3.087-3.086,8.089,0,11.176l18.498,18.498l-18.353,18.353l-42.089-42.089
c-3.086-3.085-8.089-3.085-11.175,0c-3.086,3.087-3.086,8.089,0,11.176l42.089,42.088l-16.064,16.064
c-1.634,1.634-3.806,2.534-6.116,2.534s-4.482-0.9-6.116-2.534l-65.457-65.458c-3.372-3.372-3.372-8.859,0-12.231l160.857-160.858
L256.882,332.805z M33.423,86.998c-14.766-14.766-14.766-38.792,0-53.558c14.766-14.767,38.792-14.767,53.558,0l24.976,24.976
l-53.558,53.558L33.423,86.998z M116.798,116.803c-0.002,0.002-0.004,0.003-0.005,0.005c-0.002,0.002-0.003,0.004-0.005,0.005
l-26.774,26.774l-20.439-20.439l53.558-53.558l20.439,20.439L116.798,116.803z M483.703,483.681l-77.864-30.229l47.601-47.601
L483.703,483.681z" />
</svg>
<svg id="colorsTool" class="toolIcon" viewBox="0 0 459 459">
<path
d="M229.5,0C102,0,0,102,0,229.5S102,459,229.5,459c20.4,0,38.25-17.85,38.25-38.25c0-10.2-2.55-17.85-10.2-25.5
c-5.1-7.65-10.2-15.3-10.2-25.5c0-20.4,17.851-38.25,38.25-38.25h45.9c71.4,0,127.5-56.1,127.5-127.5C459,91.8,357,0,229.5,0z
M89.25,229.5c-20.4,0-38.25-17.85-38.25-38.25S68.85,153,89.25,153s38.25,17.85,38.25,38.25S109.65,229.5,89.25,229.5z
M165.75,127.5c-20.4,0-38.25-17.85-38.25-38.25S145.35,51,165.75,51S204,68.85,204,89.25S186.15,127.5,165.75,127.5z
M293.25,127.5c-20.4,0-38.25-17.85-38.25-38.25S272.85,51,293.25,51s38.25,17.85,38.25,38.25S313.65,127.5,293.25,127.5z
M369.75,229.5c-20.4,0-38.25-17.85-38.25-38.25S349.35,153,369.75,153S408,170.85,408,191.25S390.15,229.5,369.75,229.5z" />
</svg>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript" src="lib/blowup.min.js"></script>
<script>
$(document).ready(() => {
// Tool icons objects
const $zoomToolOBJ = $('#zoomTool');
const $vectorToolOBJ = $('#vectorTool');
const $proportionsToolOBJ = $('#proportionsTool');
const $colorsToolOBJ = $('#colorsTool');
// Selected tool -- initiated with zoom tool
let mode = 1;
// Holder for the active tool element (if any)
let $activeToolOBJ = $zoomToolOBJ;
// Handlers for tool icon click event
const zoomToolOnClick = () => {
if (mode !== 1) {
if (!!$activeToolOBJ) {
$activeToolOBJ.removeClass('onTool');
}
$activeToolOBJ = $zoomToolOBJ;
mode = 1;
$zoomToolOBJ.addClass('onTool');
return;
}
mode = 0;
$zoomToolOBJ.removeClass('onTool');
$activeToolOBJ = null;
}
$zoomToolOBJ.on('click', zoomToolOnClick);
});
</script>
</body>
</html>
The problem appears to be with the version of jQuery that you are using. You are using a 2.x version, and this is a jQuery issue for SVG. It works with a 3.x version. Consider upgrading your jQuery version if it is possible. Also see this answer for additional information.
I think the class is being removed but you are adding it straight back on again:
const zoomToolOnClick = () => {
if (mode !== 1) {
if (!!$activeToolOBJ) {
$activeToolOBJ.removeClass('onTool'); // <----- removing class
}
$activeToolOBJ = $zoomToolOBJ;
mode = 1;
console.log($zoomToolOBJ.attr('class'));
$zoomToolOBJ.addClass('onTool'); // <----- adding it back on again
console.log($zoomToolOBJ.attr('class'));
return;
}
mode = 0;
console.log($zoomToolOBJ.attr('class'));
$zoomToolOBJ.removeClass('onTool');
console.log($zoomToolOBJ.attr('class'));
$activeToolOBJ = null;
}
Do you mean to be returning from the function after the class is removed?

Use inline svg as background of the other element

How can I use #bg as a background for section?
https://jsfiddle.net/42nn4b49/2/
div {
width: 4em;
}
section {
outline: 1px dotted red;
width: 8em;
height: 8em;
background: url(#bg); /* Desn't work */
}
<div>
<svg viewBox="-4 -4 8 8" id="bg">
<circle r="4" />
</svg>
</div>
<section></section>
PS: Same question in russian
Originally, I'd hoped to be able to combine the results of Drawing an SVG file on a HTML5 canvas and How to dynamically change a class css styling?
However, it seems not to work - I've not been able to work out how to replace a background-image attrib of a rule. The console.log message is shown, but nothing changes.
So instead, I've opted just to create a rule that just sets the bkg img, and then appended it to the first style element found inside the head.
// useful for HtmlCollection, NodeList, String types
function forEach(array, callback, scope){for (var i=0,n=array.length; i<n; i++)callback.call(scope, array[i], i, array);} // passes back stuff we need
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
document.getElementById('mBtn').addEventListener('click', onBtnClicked, false);
}
function onBtnClicked(evt)
{
var svgElem = document.querySelector('svg');
var b64SVG = getDataURL2(svgElem);
// doesn't work
//alterExistingCSSRuleAttrib('#panel', 'background-image', 'url('+b64SVG+');' );
// does work
addCssRule('#panel', 'background-image', 'url('+b64SVG+')' );
// does work
alterExistingCSSRuleAttrib('#panel', 'width', "200px" );
// doesn't work
alterExistingCSSRuleAttrib('#panel', 'border', "solid 3px green" );
// does work
alterExistingCSSRuleAttrib('#panel', 'border-top-color', "green" );
alterExistingCSSRuleAttrib('#panel', 'border-top-width', "5px" );
}
function addCssRule(selectorText, attribName, value)
{
var style = document.querySelector('style');
style.innerHTML += selectorText + "{" + attribName + ": " + value + "; }";
}
function getDataURL2(svgElem)
{
var xml = new XMLSerializer().serializeToString(svgElem);
var svg64 = btoa(xml);
var b64Start = 'data:image/svg+xml;base64,';
return b64Start + svg64;
}
function alterExistingCSSRuleAttrib(selectorText, tgtAttribName, newValue)
{
var styleSheets = document.styleSheets;
forEach(styleSheets, styleSheetFunc);
function styleSheetFunc(CSSStyleSheet)
{
forEach(CSSStyleSheet.cssRules, cssRuleFunc);
}
function cssRuleFunc(rule)
{
if (selectorText.indexOf(rule.selectorText) != -1)
forEach(rule.style, cssRuleAttributeFunc);
function cssRuleAttributeFunc(attribName)
{
if (attribName == tgtAttribName)
{
rule.style[attribName] = newValue;
console.log('attribute replaced: '+attribName);
}
}
}
}
#panel
{
background: url(bluebombSmall.svg);
display: inline-block;
width: 100px;
height: 100px;
border: solid 1px red;
border-radius: 8px;
}
#bomb2
{
display: none;
}
<button id='mBtn'>Click to update/add styles</button><br>
<div id='panel'></div>
<svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" >
<g transform="translate(0,-1020.3622)">
<path d="m23.23,15.84a10.55,10.55,0,1,1,-21.11,0,10.55,10.55,0,1,1,21.11,0z" transform="matrix(1.1875635,0,0,1.1875635,0.68612298,1020.367)" fill="#26201e"/>
<path d="m23.23,15.84a10.55,10.55,0,1,1,-21.11,0,10.55,10.55,0,1,1,21.11,0z" transform="matrix(0.86603158,0,0,0.86603158,2.4299747,1024.1874)" fill="#333"/>
<path d="m-13.04,19.32a1.964,1.964,0,1,1,-3.929,0,1.964,1.964,0,1,1,3.929,0z" transform="matrix(1.924285,1.1058108,-1.1908732,2.0723069,62.314757,1012.6494)" fill="#CCC"/>
<path d="m15.69,1026c0.02518-5.037,7.647-7.396,8.907-2.969,0.7936,2.761,1.349,5.666,4.877,6.786" stroke="#888" stroke-width="1.5px" fill="none"/>
<rect height="2.399" width="4.798" y="1026" x="13.31" stroke-width="0" fill="#26201e"/>
<path fill="#F00" transform="translate(2.0203051,1022.13)" d="M29.8,10.53,27.1,9.62,24.82,11.32,24.86,8.477,22.54,6.833,25.25,5.989,26.1,3.271,27.74,5.595,30.59,5.558,28.89,7.839z"/>
</g>
</svg>
quick jsfiddle I made for you: https://jsfiddle.net/42nn4b49/7/
HTML:
<div>
<svg viewBox="-4 -4 8 8" class="bg">
<circle r="4" />
</svg>
<section>Test</section>
</div>
CSS:
div {
width: 4em;
}
.bg {
position: absolute;
top: 0;
width: 8em;
height: 8em;
z-index: -100;
}
section {
outline: 1px dotted red;
width: 8em;
height: 8em;
background: url(#bg);
color: #fff;
text-align: center;
}
I assume that it's the result of absolute positioning your after. Essentially as #luuk mentioned, all you need is to wrap both elements in a single container, and set section { position : absolute;}. to understand this further read up here.
#wrap {
position: relative;
width: 30%;
background: #eee;
padding: .5em;
}
section {
position: absolute;
color: #f8f8ff;
top: 0;
left: 0;
z-index: 2;
outline: 1px dotted red;
width: 100%;
text-align: center;
}
#circle {
position: relative;
width: 100%;
z-index: 1;
}
p {
padding: 1.5em;
}
<div id="wrap">
<div id="circle">
<svg viewBox="-4 -4 8 8" id="bg">
<circle r="4" />
</svg>
</div>
<section id="box">
<p>This is my content.</p>
</section>
</div>
Feel free to ask any further questions.

How to make a div with arrowlike side without css border tricks?

I want to make menu navigation bar with several inline-block li elements, each of them must have arrow-like right side. Like this:
I googled for it and the most common answer is to use css tricks with transparent border. Like this one: http://jsfiddle.net/jx99z/5/
html:
<div class="text">Some Text<span class="arrow"></span></div>
css:
.text {
background-color:#ff0000;
color:#fff;
display:inline-block;
padding-left:4px;
}
.arrow {
border-style: dashed;
border-color: transparent;
border-width: 0.20em;
display: -moz-inline-box;
display: inline-block;
/* Use font-size to control the size of the arrow. */
font-size: 100px;
height: 0;
line-height: 0;
position: relative;
vertical-align: middle;
width: 0;
background-color:#fff; /* change background color acc to bg color */
border-left-width: 0.2em;
border-left-style: solid;
border-left-color: #ff0000;
left:0.25em;
}
It seems pretty good, but when I try to add other elements with :hover, they don't look and behave properly: http://jsfiddle.net/txayr2j6/
html:
<div class="text">Some Text<span class="arrow"></span></div>
<div class="text">Some Text<span class="arrow"></span></div>
css:
.text {
background-color:#ff0000;
color:#fff;
display:inline-block;
padding-left:4px;
}
.arrow {
border-style: dashed;
border-color: transparent;
border-width: 0.20em;
display: -moz-inline-box;
display: inline-block;
/* Use font-size to control the size of the arrow. */
font-size: 100px;
height: 0;
line-height: 0;
position: relative;
vertical-align: middle;
width: 0;
background-color:#fff; /* change background color acc to bg color */
border-left-width: 0.2em;
border-left-style: solid;
border-left-color: #ff0000;
left:0.25em;
}
.text:hover {
background-color:#ccc;
border-left-color: #ccc;
}
Another solution, which I found, is that I can draw any element using svg (whatever that means) like this: http://codepen.io/anon/pen/OXWoXd
html:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<polygon points="
0,0
0,200
270,200
300,100
270,0
150,0
" />
<div>Item 1</div>
</svg>
css:
svg polygon {
fill: transparent;
stroke: black;
stroke-width: 2px;
}
svg {
background-color: #ccc;
height: 50%;
}
body, html {
height: 100%;
margin: .2em;
}
But that solution is even worse: somehow I can't make element wider than 300 px and look at those ugly border and background. Also, I want that bar to be responsive. Thanks!
Svg are great for creating shapes in html
Used a polygon element for the shape.
Text element for the link description.
A element for creating a link.
#arrow-menu a polygon {
fill: #888;
stroke: #222;
}
#arrow-menu a:hover polygon {
stroke: #222;
fill: black;
}
#arrow-menu a:hover text {
fill: cornflowerblue;
}
#arrow-menu a {
font-size: 5px;
}
<svg id="arrow-menu" viewBox="-1 -1 112 22" xmlns:xlink="http://www.w3.org/1999/xlink">
<a xlink:href="#">
<polygon points="0,0 20,0 25,10 20,20 0,20 0,0"></polygon>
<text x="1.5" y="11.5">Menu link</text>
</a>
<a xlink:href="#">
<polygon transform="translate(22)" points="0,0 20,0 25,10 20,20 0,20 5,10 0,0"></polygon>
</a>
<a xlink:href="#">
<polygon transform="translate(44)" points="0,0 20,0 25,10 20,20 0,20 5,10 0,0"></polygon>
</a>
<a xlink:href="#">
<polygon transform="translate(66)" points="0,0 20,0 25,10 20,20 0,20 5,10 0,0"></polygon>
</a>
</svg>
Is it this what you are looking for? It is made with before and after Fiddle
It is better to make it with css than with images
Very interesting question. I believe it is better to use pictures, since you want your hover event to work and also, there is a problem with clicking at the borders. This is a full implementation of the design along with events:
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
.text {
background-color: rgb(237, 28, 36);
color:white;
padding-left:4px;
height: 30px;
padding-top: 10px;
}
</style>
<script type="text/javascript">
function mouseoverText(index) {
var images = document.querySelectorAll(".image");
var currentText = document.querySelectorAll(".text")[index];
currentText.style["background-color"] = "white";
currentText.style["color"] = "red";
images[index].src = ((images.length - 1 === index) ? "white-white" : "white-red") + "-arrow.png";
if (index > 0) {
images[index - 1].src = "red-white-arrow.png";
}
}
function mouseoutText(index) {
var currentText = document.querySelectorAll(".text")[index];
currentText.style["background-color"] = "rgb(237, 28, 36)";
currentText.style["color"] = "white";
var images = document.querySelectorAll(".image");
if (index >= 0) {
images[index].src = ((images.length - 1 === index) ? "red-white" : "red-red") + "-arrow.png";
if (index > 0) {
images[index - 1].src = "red-red-arrow.png";
}
}
}
var lastIndex = -1;
function mouseoverArrow(event, index) {
if (!!event) {
var x = event.offsetX;
var y = event.offsetY;
var height = 40;
if (((y < height / 2) && (x > y)) || ((y >= height / 2) && (x > (height - y)))) {
mouseoverArrow(null, index + 1);
return;
}
}
if (lastIndex !== -1) {
mouseoutArrow();
lastIndex = -1;
}
lastIndex = index;
var texts = document.querySelectorAll(".text");
if (index === texts.length) {
return;
}
texts[index].style["background-color"] = "white";
texts[index].style.color = "red";
mouseoverText(index);
}
function mouseoutArrow() {
if (lastIndex < 0) {
return;
}
var texts = document.querySelectorAll(".text");
if (lastIndex >= texts.length) {
return;
}
texts[lastIndex].style.color = "white";
texts[lastIndex].style["background-color"] = "rgb(237, 28, 36)";
mouseoutText(lastIndex);
lastIndex = -1;
}
function clk(index) {
console.log("Element " + (lastIndex === -1 ? index : lastIndex) + " was clicked");
}
</script>
</head>
<body>
<div style="display: inline-flex;">
<div class="text" onmousemove="mouseoverText(0);" onmouseout="mouseoutText(0);" onclick="clk(0);">Some Text</div>
<img class="image" src="red-red-arrow.png" onmousemove="mouseoverArrow(event, 0);" onmouseout="mouseoutArrow();" onclick="clk();" />
<div class="text" onmousemove="mouseoverText(1);" onmouseout="mouseoutText(1);" onclick="clk(1);">Some Text</div>
<img class="image" src="red-red-arrow.png" onmousemove="mouseoverArrow(event, 1);" onmouseout="mouseoutArrow();" onclick="clk();" />
<div class="text" onmousemove="mouseoverText(2);" onmouseout="mouseoutText(2);" onclick="clk(2);">Some Text</div>
<img class="image" src="red-white-arrow.png" onmousemove="mouseoverArrow(event, 2);" onmouseout="mouseoutArrow();" onclick="clk();" />
</div>
</body>
</html>
I attach the useful pictures as well: