make an html svg object also a clickable link
Actually, the best way to solve this is... on the <object> tag, use:
pointer-events: none;
Note: Users which have the Ad Blocker plugin installed get a tab-like [Block] at the upper right corner upon hovering (the same as a flash banner gets). By settings this css, that'll go away as well.
http://jsfiddle.net/energee/UL9k9/
How to add JavaScript onClick handler to an embedded html object?
You have to implement onclick inside the svg and link it to the external JavaScript function using javascript inside the svg. See the SVG wiki for examples.
Update: Apparently the SVG wiki is no more. No surprise that the best references I can now (quickly) find are on StackOverflow itself.
This answer describes how to implement onclick inside the svg.
SVG image within an object tag overlys website content
After some experimenting and researching I found a solution. I needed to make the <ul>
element absolute in positioning and remove it from the fake <iframe>
. Now the navigation is visible and clickable. I needed to add some CSS and fiddle with height and width in javascript/jQuery due to variable heights, but that's irrelevant.
So it worked for me like this:
<div id="showNav">
<ul style='position: absolute'>
<li><a href=„LinkTarget“ onclick="location.href = this.href + fncTarget + '/index.htm';
return false;">Line 1</a></li>
<li><a href=„LinkTarget“ onclick="location.href = this.href + fncTarget + '/event.htm';
return false;">Line 2</a></li>
<li><a href=„LinkTarget“ onclick="location.href = this.href + fncTarget + '/error.htm';
return false;">Line 3</a></li>
<li><a href=„LinkTarget“ onclick="location.href = this.href + fncTarget + '/index.htm?reset=true';
return false;">Line 4</a></li>
</ul>
<iframe id="fake" src="about:blank" style="width: 102%; height: 103%; border: none;"></iframe>
</div>
You may need to vary height, width and border of the iFrame to match your case, since you need to adjust this to make all formatting of the parent <div>
visible.
I hope this will help someone who stumbles over the same issues.
Clickable positioning hyperlinks to A/V (locally stored on your website and “hidden” behind a poster image)
Demo
I'm sorry for the delay, and for it not being exactly the same as the Youtube one, the thing I lack most it's consistency, but here it is.
I've based this example in two songs from Hozier, one in audio and one in video format. (Hope nobody sues me)
As always you can modify the styles later on to fit your design, I just put something quick together to demonstrate.
Below, you will see a basic example of how the code works (for a more in-depth example, please refer to the demo).
HTML
Audio
<div class="mediaAudioFacade"
id="id"
data-sources="source1.mp3,source2.wav,source3.ogg"
data-start="seconds"(optional)
data-end="seconds"(optional)>
label
</div>
<div class="mediaJumper" data-id="id" data-time="seconds">label</div>
Video
<div class="mediaVideoFacade" (..)>(..)</div>
(..)
The only difference would be the class attribute, this being mediaVideoFacade
instead of mediaAudioFacade
.
JavaScript
window.addEventListener("load",function(){
setUpMediaObjects();
setUpMediaJumpers();
});
MediaObjects = [];
MediaJumpers = [];
function setUpMediaObjects() {
var allAudioFacades = document.querySelectorAll(".mediaAudioFacade");
if (allAudioFacades) {
for (var i = 0; i < allAudioFacades.length; i++) {
var facade = allAudioFacades[i];
var mo = new MediaObject(facade);
MediaObjects.push(mo);
}
}
var allVideoFacades = document.querySelectorAll(".mediaVideoFacade");
if (allVideoFacades) {
for (var i = 0; i < allVideoFacades.length; i++) {
var facade = allVideoFacades[i];
var mo = new MediaObject(facade);
MediaObjects.push(mo);
}
}
}
function setUpMediaJumpers(){
var allMediaJumpers = document.querySelectorAll(".mediaJumper");
for( var i = 0 ; i < allMediaJumpers.length ; i ++ ){
var mediaJumper = allMediaJumpers[i];
var mj = new MediaJumper(mediaJumper);
MediaJumpers.push(mj);
}
}
function MediaObject(facade) {
this.facade = facade;
this.id = this.facade.id;
this.sourcesURI = this.facade.dataset.sources.split(",");
this.sources = this.getSources();
var isAudio = this.facade.className.match(/mediaAudioFacade/);
this.type = (isAudio) ? "audio" : "video";
this.icon = new Image();
this.icon.src = (isAudio) ? "http://i.imgur.com/HKktAoE.png" : "http://findicons.com/icon/download/566082/video_play/33/png";
this.setUpFacade();
this.capType = this.type.substr(0,1).toUpperCase() + this.type.substr(1);
this.elem = document.createElement(this.type);
this.elem.controls = "true";
this.elem.className = "mediaType".replace(/type/i, this.capType);
this.hasStarted = false;
this.appendSources();
this.startTime = this.facade.dataset.start;
this.endTime = this.facade.dataset.end;
this.facade.addEventListener("click", this.startUp.bind(this) );
}
MediaObject.prototype.setUpFacade = function () {
var label = document.createElement("span");
label.innerHTML = this.facade.innerHTML || "Play audio.";
this.facade.innerHTML = "";
this.facade.appendChild(this.icon);
this.facade.appendChild(label);
}
MediaObject.prototype.getSources = function () {
var sources = [];
for (var i = 0; i < this.sourcesURI.length; i++) {
var sourceURI = this.sourcesURI[i];
var source = document.createElement("source");
source.src = sourceURI;
sources.push(source);
}
return sources;
}
MediaObject.prototype.appendSources = function () {
for (var i = 0; i < this.sources.length; i++) {
var source = this.sources[i];
this.elem.appendChild(source);
}
}
MediaObject.prototype.startUp = function () {
this.replaceNode(this.facade, this.elem);
this.hasStarted = true;
if( this.startTime )
this.elem.currentTime = this.startTime;
if( this.endTime )
this.elem.addEventListener("timeupdate",this.checkForVideoEnd.bind(this));
this.elem.play();
}
MediaObject.prototype.checkForVideoEnd = function(){
console.log(this.elem.currentTime);
if( Math.floor(this.elem.currentTime) == this.endTime )
this.elem.pause();
}
MediaObject.prototype.replaceNode = function(node1,node2){
var parent = node1.parentNode;
var next = node1.nextSibling;
if( next )
parent.insertBefore(node2,next);
else
parent.appendChild(node2);
parent.removeChild(node1);
}
function MediaJumper(jumper){
this.jumper = jumper;
this.id = this.jumper.dataset.id;
this.mediaObject = this.getMediaObject();
this.time = this.jumper.dataset.time;
this.jumper.addEventListener("click",this.jump.bind(this));
}
MediaJumper.prototype.getMediaObject = function(){
for( var i = 0 ; i < MediaObjects.length ; i ++ ){
var mediaObj = MediaObjects[i];
if( mediaObj.id == this.id )
return mediaObj;
}
return null;
}
MediaJumper.prototype.jump = function(){
if( this.mediaObject ){
if( !this.mediaObject.hasStarted )
this.mediaObject.startUp();
this.mediaObject.elem.currentTime = this.time;
this.mediaObject.elem.play();
}
}
Feel free to ask any question's about the code, or report anything that is not working, good luck and hope it helps! :)
Updates
Added a
data-start
anddata-end
, note thatdata-end
will only stop the video if the time specified matches the current time of the video floored. Technically:if( Math.Floor(MediaCurrentTime) == DataEndTime ) stop();
This means if a jumper is called it will continue to play normally until it hits that number again, and if the jumper calls for a time beyond the data-end, then the video will be played normally.
HTML object is blocking eventlistener
Your <object>
acts like an <iframe>
, just like we wouldn't want any website to be able to embed our bank website in an iframe and see where we clicked, the <object>
has the same "protection".
Even if the page are same-origin and can talk to each other, by default they won't receive any events from the other one.
But anyway what you probably want is to make the SVG document react to these events. For this, add the event listeners on that document directly.
// Wait for the <object> to be loaded
window.addEventListener("load", (evt) => {
const objEl = document.querySelector("object");
const svgDoc = objEl.getSVGDocument();
// Now you have access to the SVG document
// you can add event listeners to it as you wish
svgDoc.addEventListener("click", (evt) => {
console.log("clicked on", evt.target.outerHTML);
});
});
Unfortunately StackSnippets's null-origined iframes won't allow us to make live demos, so here is one on JSFiddle.
But beware the <object>
element isn't gathering much love from implementers and spec authors these days and it may get removed from the standards at some point in the future.
So instead, you may prefer to actually use an <iframe>
directly. Moreover since here we would access the loaded document, we can do the one thing that <object>
can do and <iframe>
can't: auto-resizing to the image content.
For this, when we get our SVG document, we grab its documentElement
's BBox and set our <iframe>
's width
and height
attributes to the BBox's ones.
// Wait for the <iframe> to be loaded
window.addEventListener("load", (evt) => {
const frameEl = document.querySelector("iframe");
const svgDoc = frameEl.getSVGDocument();
// Resize the iframe to its content's size
const bbox = svgDoc.documentElement.getBBox();
frameEl.width = bbox.width;
frameEl.height = bbox.height;
svgDoc.addEventListener("click", (evt) => {
console.log("clicked on", evt.target.outerHTML);
});
});
Once again as a JSFiddle.
Related Topics
How to Center Content in a Bootstrap Column
HTMLagilitypack Drops Option End Tags
How to Create a Wavy Shape CSS
How to Insert a Template into Another Template
How to Display HTML <Form> as Inline Element
Image Center Align Vertically and Horizontally
Html/Css: Empty Page + Only Header Page When Printing Table
How to Prevent Background Scrolling When Bootstrap 3 Modal Open on Mobile Browsers
Alternate Background Colors for List Items
How to Write Text on a HTML5 Canvas Element
Bootstrap 3 - Show Collapsed Navigation for All Screen Sizes
Equal Width Columns in CSS Grid
Alignment of Content Vertically in Adjacent Flexbox Containers