I am working on a project where a sound plays when you mouseover an image and stops playing on mouseout. I want it to start over each time and there has to be multiple images on each page. I am looking for the most efficient way to make this code work. Here is the sample page: http://inventivewebdesign.com/audio-img/sound.html
Code:
<body>
<script>
function PlaySound(soundobj) {
var thissound=document.getElementById(soundobj);
thissound.play();
}
function StopSound(soundobj) {
var thissound=document.getElementById(soundobj);
thissound.pause();
thissound.currentTime = 0;
}
</script>
<a onmouseover="PlaySound('violin')" onmouseout="StopSound('violin')"><img src="violin.png"></a>
<a onmouseover="PlaySound('xy')" onmouseout="StopSound('xy')"><img src="xy.png" width="300px" height="300px"></a>
<a onmouseover="PlaySound('piccolo')" onmouseout="StopSound('piccolo')"><img src="piccolo.png"></a>
<audio id='piccolo' src='piccolo.wav'/>
<audio id='violin' src='violin.mp3'/>
<audio id='xy' src='xy.mp3'/>
</body>
This all works. My only question is how to make the code more efficient.
I saw that I should be able to do something like this:
<audio>
<source id='piccolo' src='piccolo.wav'>
<source id='violin' src='violin.mp3'>
<source id='xy' src='xy.mp3'>
</audio>
But it doesn't work. Is the first set of code above the best way to do it?
Good question #MattM. I would simply add a function to create new instances of the audio hovers, making make it easier to implement more sounds without code repetition.
function newHover(e){
var audio = new Audio(); // creates audio element
audio.src = e.audio; // the audios location
var image = new Image(); //creates the image element
image.src = e.image; // the images location
image.className = e.title; // applies the name of the instrument to both elements
audio.className = e.title;
image.addEventListener("mouseover", PlaySound); // listens for mouse movement
image.addEventListener("mouseout", StopSound);
document.body.appendChild(audio); // appends the audio and image to the body of the document
document.body.appendChild(image);
}
That way, the below code block is unnecessary:
<a onmouseover="PlaySound('violin')" onmouseout="StopSound('violin')">
<img src="violin.png">
</a>
<a onmouseover="PlaySound('xy')" onmouseout="StopSound('xy')">
<img src="xy.png" width="300px" height="300px">
</a>
<a onmouseover="PlaySound('piccolo')" onmouseout="StopSound('piccolo')">
<img src="piccolo.png">
</a>
<audio id='piccolo' src='piccolo.wav'/>
<audio id='violin' src='violin.mp3'/>
<audio id='xy' src='xy.mp3'/>
Implement this in your code, none of the HTML above is needed in this solution.
(Note: getElementById was changed to querySelector in PlaySound and PauseSound functions)
function PlaySound(e) {
var thissound = document.querySelector("audio." + e.target.className);
thissound.play();
}
function StopSound(e) {
var thissound = document.querySelector("audio." + e.target.className);
thissound.pause();
thissound.currentTime = 0;
}
function newHover(e){
var audio = new Audio();
audio.src = e.audio;
var image = new Image();
image.src = e.image;
image.className = e.title;
audio.className = e.title;
image.addEventListener("mouseover", PlaySound);
image.addEventListener("mouseout", StopSound);
document.body.appendChild(audio);
document.body.appendChild(image);
}
window.onload = function(){
newHover({
audio: "http://inventivewebdesign.com/audio-img/piccolo.wav", // Path to the audio file (the src property of audio tag)
image: "http://inventivewebdesign.com/audio-img/piccolo.png", // Path to the image file (the src property of the image tag)
title: "piccolo" // The name of the instrument (applied as a className to both the image and the audio elements)
});
newHover({
audio: "http://inventivewebdesign.com/audio-img/xy.mp3",
image: "http://inventivewebdesign.com/audio-img/xy.png",
title: "xy"
});
newHover({
audio: "http://inventivewebdesign.com/audio-img/violin.mp3",
image: "http://inventivewebdesign.com/audio-img/violin.png",
title: "violin"
});
}
a{
position: absolute;
}
img{
width: 100px;
}
<body>
<a>Hover over the images!</a>
</body>
In conclusion, your solution works effectively, However it would make it much easier for you to have a function to create the audio hovers for you.
I took a look at inventivewebdesign.com, very nice website there!
EDIT>>>>>>>>>>>>
Note - I have tested the script in Firefox and Chrome. It should work fine.
For clarification on how to use the function:
To insert an image. Call the newHover function Like so:
newHover({
audio: /*audio src here eg. music.wav*/,
image: /*image src here eg. picture.png*/,
title: /*title here eg. violin / xylophone / piccolo*/
});
The images will be inserted into the document. You can then apply css styles or do what ever else you want to them.
Related
I'm testing on building a site locally on my machine using bootstrap.
I have a <video> sort of as the header of the site.
I would like this video to show the full width and height on mobile, and show a cropped/wide version of the video on desktop. I tried using inline media queries in the <source> tags, so that the src would change but nothing would work.
So I switched gears and used some javascript to change it that way.
So the crazy thing is, it seems my script works. When I look in chrome dev tools, the srcdoes in fact change when I resize my browser screen, however, it does not reflect on the site itself, it keeps whatever src I set it to in the html, as if it is ignoring my script.
I have tried everything I could think of, and I'm just stuck, not sure how to go about it any further. My code is below:
HTML
<video class="col-12" loop muted autoplay >
<source id="hvid" src="media/test.mp4" type="video/mp4">
</video>
JS
let homeVideo = document.getElementById('hvid')
console.log(homeVideo.src)
function myFunction(x) {
if (x.matches) { // If media query matches
homeVideo.src = "media/test.mp4";
} else {
homeVideo.src = "media/test-3.mp4";
}
}
var x = window.matchMedia("(max-width: 700px)")
myFunction(x) // Call listener function at run time
x.addListener(myFunction) // Attach listener function on state changes
;
console.log(homeVideo.src)
-Edits-
JS
var w = window.matchMedia("(max-width: 700px)");
var vid = document.getElementById("vid");
var source = document.getElementById("hvid");
window.addEventListener("resize", function screenres(){
if (w.matches) {
vid.pause();
source.src = "media/test.mp4";
vid.load();
vid.play();
} else {
vid.pause();
source.src = "media/test-3.mp4";
vid.load();
vid.play();
};
});
HTML
<div class="container">
<div class="row">
<video id="vid" class="col-12" loop muted autoplay>
<source id="hvid" src="media/test.mp4" type="video/mp4">
</video>
</div>
</div>
Just get the viewport size, and based on that value, pause the video, change the src link, load the new video and play the new video.
But do note that you will need to refresh the page after changing the browser size to see the video change.
If you want the video to change whenever the screen resizes as well as on page refresh, you will first need to move the above JavaScript to a function and run it when a resize event is fired. Then, for the page load, you need to remove the video element from your HTML and add it on page load using the createElement() method with the src attribute value also added depending on the viewport width.
Check this JSFiddle or run the following Code Snippet for a practical example of what I have described above:
/* JavaScript */
var w = window.matchMedia("(max-width: 700px)");
var vid = document.getElementById("vid");
var source = document.createElement("source");
source.id = "hvid";
source.setAttribute("type", "video/mp4");
vid.appendChild(source);
if (w.matches) {
vid.pause();
source.removeAttribute("src");
source.setAttribute("src", "https://storage.googleapis.com/coverr-main/mp4/Love-Boat.mp4");
vid.load();
vid.play();
} else {
vid.pause();
source.removeAttribute("src");
source.setAttribute("src", "https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4");
vid.load();
vid.play();
}
window.addEventListener("resize", function(){
var w = window.matchMedia("(max-width: 700px)");
var vid = document.getElementById("vid");
var source = document.getElementById("hvid");
if (w.matches) {
vid.pause();
source.src = "https://storage.googleapis.com/coverr-main/mp4/Love-Boat.mp4";
vid.load();
vid.play();
} else {
vid.pause();
source.src = "https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4";
vid.load();
vid.play();
}
});
/* CSS */
html, body {margin: 0; padding:0; width: 100%; height: 100%;}.row{display: block !important;}
<!-- CDN Links -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script><script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/><link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" rel="stylesheet"/>
<!-- HTML -->
<div class="container">
<div class="row">
<video id="vid" class="col-12" loop muted autoplay></video>
</div>
</div>
I have got a
<input type="file" id="howtovideo" name="howtovideo" accept="video/mp4"> </span>
When its changed , i am calling the below function to play video dynamically
$("#howtovideo").on('change', function() {
loadVideo();
});
function loadVideo(){
alert('loadVideo called');
var newsrc = 'http://clips.vorwaerts-gmbh.de/VfE_html5.mp4';
var video = document.getElementById('video');
var source = document.createElement('source');
source.setAttribute('src', newsrc);
video.appendChild(source);
video.play();
}
But nothing is happening and there are no errors in console demo.
Could you please let me know how to play vdeo dynamicaly ??
You don't need to add new source tag. Only set address of new video to src attribute of current source tag. Note that after changing src, you need to load video using .load() and then play video. Also if you have jQuery, use it to finding elements.
$("#howtovideo").on('change', function(){
loadVideo();
});
function loadVideo(){
var newsrc = 'http://clips.vorwaerts-gmbh.de/VfE_html5.mp4';
$('#video > source').attr('src', newsrc);
$("#video")[0].load();
$("#video")[0].play();
}
The question of how can JavaScript call the next video has been asked as I have thoroughly researched this topic before posting. However, in the situation that I will describe, a video is running after an onclick event calls the function: function(e) and I need to be able to call the next video by calling the function(e) again once the code detects an ended event by using the addEventListener method.
I have posted all my code below. In addition I have added comments to illustrate what I “think” is happening. I am brand new to JavaScript and have recently retired, so I have had time to research the Internet to try and piece together what is taking place. Please feel free to clarify my commented code as I would appreciate being set straight on what I have wriiten.
I have also made an attempt to put the code on jsfiddle
https://jsfiddle.net/dan2004/tuouh36d/
but it only seems to function in Chrome.
My main question to everyone is in regard to the statement:
document.getElementById('videoPlayer').addEventListener('ended',handler,false);
If I call a function outside of the function, I can issue a message via an alert, but if I call the function that I am in (handler(e)) I cannot get the next video to run. Somehow I need to be able to call the handler(e) function and send it the next onclick event.
Thanks for any help.
var video_playlist, links, i, videotarget, filename, video, source;
// Gets the video object from <div id="player"> in the HTML
video_playlist = document.getElementById("player");
// "links" is an array which contains all the <a href> tags in the <div id="playlist">.
// This div is located within <div id="player"> and contains a clickable playlist.
links = video_playlist.getElementsByTagName('a');
// This "for loop" scrolls through the links array of <a href> attributes and
// assigns an "onclick = handler" event to each one.
for (i=0; i<links.length; i++) {
links[i].onclick = handler;
};
// e is an [object MouseEvent]
function handler(e) {
// The handler function receives the full path to the mp4 file when it is clicked on in the playlist.
// The "preventDefault" method stops the function from following that path.
// This is so the data in the path may be parsed and manipulated below
e.preventDefault();
// videotarget grabs the href attribute of the item clicked on
// in the "playlist". This is the full path to the video file.
videotarget = this.getAttribute("href");
// Through the use of substr, filename grabs that part of the href which
// does not include the extension.
filename = videotarget.substr(0, videotarget.lastIndexOf('.')) || videotarget;
// The variable "video" contains the video object. This is obtained by using document.querySelector().
// This document method uses the css id class, #player, and grabs the [object HTML VideoElement].
// The [object HTML VideoElement] resides in <div id="player">
video = document.querySelector("#player video");
//Removes the poster attribute in the video tag
video.removeAttribute("poster");
// The source variable is used to hold an array of all the source tags in the
// [object HTML VideoElement] from <div id="player">.
source = document.querySelectorAll("#player video source");
// Using the substring extracted from the user's click choice in <div id="playlist">
// the three file types for browsers to choose from are concatenated to the string.
// These thre source files are then stored under the video object located in <div id="player">.
source[0].src = filename + ".mp4";
source[1].src = filename + ".webm";
source[2].src = filename + ".ogv";
// The video object will load the appropriate source[].src file then play it
video.load();
video.play();
// When the video ends the following statement will call the function test()
// which will then broadcast the alert message "Video Ended"
document.getElementById('videoPlayer').addEventListener('ended',test,false);
// This statement will not call the handler function in order to play the next video selection.
// document.getElementById('videoPlayer').addEventListener('ended',handler,false);
}; // function handler(e)
function test(){
alert("Video Ended");
};
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Video Playlist Tutorial</title>
<style>
body {font-family:Arial, Helvetica, sans-serif;background:#fff}
.center {text-align:center;width:640px;margin:0 auto;}
#player {background:#000; padding:10px;width:640px;margin:0 auto;border-radius:10px;}
#player video {width:640px;}
#playlist {background:#333;list-style:none;padding:0;margin:0; width:640px;}
#playlist h1 {font: 24px Arial, Helvetica, sans-serif; color:#FFF; font-weight:bold;padding:5px 2px;margin:0;}
#playlist a {color:#eeeedd;background:#333;padding:10px 5px;display:block;text-decoration:none;border-bottom:1px solid #222;}
#playlist a:hover {text-decoration:none; background:#999;color:#000}
</style>
</head>
<body>
<div id="player"> <!-- Assign id to video tag for ended event and to call handler to play next video -->
<video id="videoPlayer" controls="controls" width="640" height="360" preload="auto" autoplay >
<source src="1.mp4" type="video/mp4" />
<source src="1.webm" type="video/webm" />
<source src="1.ogv" type="video/ogg" />
</video>
<div id="playlist">
<h1>Videos</h1>
Bear <br>
Buck Bunny
</div>
</div>
<script>
</script>
</body>
</html>
Seeing as your handler() function relies on this being the clicked element, you can't just call that function, you'd have to also set the this-value to the next anchor etc. and trigger the event in a way that makes it look like it was triggered by the actual element.
An easier way to do this, would be to just decouple the playing logic, get the next element, and play the video
var video_playlist = document.getElementById("player");
var links = video_playlist.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
(function(j) {
links[j].addEventListener('click', function(e) {
handler.apply(this, [e, j])
});
})(i);
};
function handler(e, index) {
e.preventDefault();
var videotarget = this.getAttribute("href");
play(videotarget, index).addEventListener('ended', function() {
index = (++index) >= links.length ? 0 : index;
play(links[index].getAttribute("href"), index);
});
};
function play(videotarget) {
var filename = videotarget.substr(0, videotarget.lastIndexOf('.')) || videotarget;
var video = document.querySelector("#player video");
var source = document.querySelectorAll("#player video source");
video.removeAttribute("poster");
source[0].src = filename + ".mp4";
source[1].src = filename + ".webm";
source[2].src = filename + ".ogv";
video.load();
video.play();
return video;
};
<div id="player">
<!-- Assign id to video tag for ended event and to call handler to play next video -->
<video id="videoPlayer" controls="controls" width="640" height="360" preload="auto" autoplay>
<source src="1.mp4" type="video/mp4" />
<source src="1.webm" type="video/webm" />
<source src="1.ogv" type="video/ogg" />
</video>
<div id="playlist">
<h1>Videos</h1>
Bear
Buck Bunny
</div>
</div>
I have an image that plays and stops the track perfectly. I am trying to alternate the image source from play.png to pause.png depending on if the track is playing or not.
Here's the code I have that is working to start/stop the audio, only with a static play.png image. How can I change the src attribute using javascript between pause.png and play.png?
<img src='play.png' onclick="aud_play_pause()">
<audio id="audio1">
<source src="audio1.mp3" type="audio/mp3">
</audio>
<script>
var myAudio=document.getElementById("audio1");
function aud_play_pause(){
if (myAudio.paused){
myAudio.play();
} else {
myAudio.pause();
}
}
</script>
You'll want to use javascript's DOM manipulation functions to change this like so:
var myAudio = document.getElementById("audio1");
var image = document.getElementsByTagName("img")[0];
function aud_play_pause(){
if (myAudio.paused){
myAudio.play();
image.setAttribute("src", "pause.png");
} else {
myAudio.pause();
image.setAttribute("src", "play.png");
}
}
Although it is better to reference the img element by its ID, I used its tag name since it was the only one there.
I have the following code:
function playSound(source) {
document.getElementById("sound_span").innerHTML =
"<embed src='" + source + "' hidden=true autostart=true loop=false>";
}
<span id="sound_span"></span>
<button onclick="playSound('file.mp3');"></button>
Once you click play, the MP3 gets downloaded, than it starts to play. However, it can take a while if it has like 1 MB. What I need is a preloaded (just like you can do with the images). So when the page loads, the mp3 will be streamed and if, for instance, 10 seconds later, the user pressed the 'play' button, he won't have to wait until the mp3 gets downloaded first, as it is already streamed.
Any ideas? Thanks in advance for any tip!
You can preload using <audio /> for newer browsers. Set autoplay = false. For older browsers that don't support <audio />, you can use <bgsound />. To preload a sound, set the volume to -10000.
function preloadSound(src) {
var sound = document.createElement("audio");
if ("src" in sound) {
sound.autoPlay = false;
}
else {
sound = document.createElement("bgsound");
sound.volume = -10000;
}
sound.src = src;
document.body.appendChild(sound);
return sound;
}
That will get the sound in your browser's cache. Then to play it, you can keep doing what you are doing with <embed />. Or if you want to take advantage of HTML5 features, you can call .play() on the returned <audio /> element. You could even add a play method to the <bgsound />:
function loadSound (src) {
var sound = document.createElement("audio");
if ("src" in sound) {
sound.autoPlay = false;
}
else {
sound = document.createElement("bgsound");
sound.volume = -10000;
sound.play = function () {
this.src = src;
this.volume = 0;
}
}
sound.src = src;
document.body.appendChild(sound);
return sound;
}
Then use it like this:
var sound = loadSound("/mySound.ogg"); // preload
sound.play();
The only caveat is FireFox doesn't support mp3. You'll have to convert your files to ogg.
Working demo: http://jsfiddle.net/PMj89/1/
You can use the HTML5 <audio> element's preload attribute, and fall back on <embed>.