I am trying to trigger a ripple animation programatically at a given x,y coordinate, but I can't seem to get it right.
I have found a few helpful answers like these:
paper-ripple mouseDown event handler downAction Override
Polymer paper ripple
How to trigger Polymer paper ripple animation by API code?
I didn't find a way to apply the first two since at this stage I'm simply using a paper-ripple element without creating a custom element. The first answer is somewhat helpful, but I'd like to control the x,y coordinates of the ripple.
Here's how I tried to do this, using Jacek's snippet fro the 3rd answer:
<!DOCTYPE html>
<html>
<head>
<base href="https://polygit.org">
<script src="/components/webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="/components/polymer/polymer.html">
<link rel="import" href="/components/paper-ripple/paper-ripple.html">
<style>
.card {
position: relative;
display: inline-block;
width: 300px;
height: 240px;
vertical-align: top;
background-color: #fff;
box-shadow: 0 12px 15px 0 rgba(0, 0, 0, 0.24);
}
</style>
</head>
<body>
<template id="demo" is="dom-bind">
<div class="card">
<paper-ripple recenters></paper-ripple>
</div>
</template>
</body>
<script>
var demo = document.querySelector('#demo');
var mouseDown = new MouseEvent("mouseDown",{"clientX":30,"clientY":30,"screenX":30,"screenY":30});
var mouseUp = new MouseEvent("mouseUp",{"clientX":30,"clientY":30,"screenX":30,"screenY":30});
demo.addEventListener('dom-change', function() {
setInterval(triggerRippleDown, 1000);
setInterval(triggerRippleUp, 1200);
});
var triggerRippleDown = function() {
var paperRipple = document.querySelector('paper-ripple');
paperRipple.downAction(mouseDown);
}
var triggerRippleUp = function() {
var paperRipple = document.querySelector('paper-ripple');
paperRipple.upAction(mouseUp);
}
</script>
</html>
This passing x,y properties via mouse event doesn't seem to work, although this part of the documentation suggests so:
downAction: function(e) {
this.$.ripple.downAction({x: e.x, y: e.y});
}
Any hints on what's the recommended way to trigger a ripple programatically outside of a custom component ?
I dont know the recommended way but I have simple solution.
My solution is not to pass mouse event but object with x,y. look in this example:
<!DOCTYPE html>
<html>
<head>
<base href="https://polygit.org">
<script src="/components/webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="/components/polymer/polymer.html">
<link rel="import" href="/components/paper-ripple/paper-ripple.html">
<style>
.card {
position: relative;
display: inline-block;
width: 300px;
height: 240px;
vertical-align: top;
background-color: #fff;
box-shadow: 0 12px 15px 0 rgba(0, 0, 0, 0.24);
}
</style>
</head>
<body>
<template id="demo" is="dom-bind">
<div class="card">
<paper-ripple recenters></paper-ripple>
</div>
</template>
</body>
<script>
var demo = document.querySelector('#demo');
demo.addEventListener('dom-change', function() {
setInterval(triggerRippleDown, 1000);
setInterval(triggerRippleUp, 1200);
});
var triggerRippleDown = function() {
var paperRipple = document.querySelector('paper-ripple');
paperRipple.downAction({detail:{x:30,y:120}});
console.log(paperRipple.xStart);
}
var triggerRippleUp = function() {
var paperRipple = document.querySelector('paper-ripple');
paperRipple.upAction();
}
</script>
</html>
I use this and dont mouseEvent
paperRipple.downAction({detail:{x:30,y:120}});
paperRipple.upAction();
Related
I have a div that contains a header. In this header I will write characteristics of the object I am clicking on in the page. The initial on-click trigger works fine and processes the post request to a local flask server and displays the plot in the div using plotly.js. The problem comes in when the div is collapsed by clicking on the header and then trying to click on an object in the page. The desired outcome for this second on-click event is for the data inside the 'plot data' div to update, and causing the header to expand if it is minimized. However, the observed behavior is that if you click on an object, triggering an on-click event while the div is hidden, it results in the following error in the dev console.
Cannot read properties of null (reading 'innerText')
referencing this line:
console.log(document.getElementById("header symbol").innerText)
The relevant code here is below:
Jquery for expanding and closing the div
$(".header").click(function () {
const $header = $(this);
//getting the next element
var $content = $header.next();
//open up the content needed - toggle the slide- if visible, slide up, if not slidedown.
$content.slideToggle(200, function () {
//execute this after slideToggle is done
//change text of header based on visibility of content div
console.log(document.getElementById("header symbol").innerText);
$header.text(function () {
//change text based on condition
return $content.is(":visible")
? `▼ ${clickedBranchName} -- ${clickedBranchFromBus} ⟶ ${clickedBranchToBus}`
: `▲ ${clickedBranchName} -- ${clickedBranchFromBus} ⟶ ${clickedBranchToBus}`;
});
});
});
Plotting the data into the 'plot data' div:
function plotFlow(info) {
console.log(info.object.properties.name);
const dates = topoData.data.datetime;
const flows = topoData.data.flow;
var trace1 = { x: dates, y: flows, mode: "lines", type: "scatter" };
var data = [trace1];
var layout = {
plot_bgcolor: "rgba(128,128,128,1)",
paper_bgcolor: "rgba(128,128,128,1)",
height: 350,
xaxis: {
tickmode: "auto",
nticks: 36,
},
};
var plot_div = document.getElementById("plot_data");
// plot_div.replaceChildren();
console.log(document.getElementById("header symbol").innerText);
document.getElementById(
"header symbol"
).innerText = `▼ ${clickedBranchName} -- ${clickedBranchFromBus} ⟶ ${clickedBranchToBus}`;
console.log(document.getElementById("header symbol").innerText);
Plotly.newPlot(plot_div, data, layout);
}
And finally,. index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<meta charset="utf-8" />
<title> WHO!?!?</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
body {
margin: 0;
font-family: sans-serif;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.container {
position: absolute;
margin: 0;
bottom: 0px;
width: 100%;
border:1px solid #d3d3d3;
z-index: 999;
}
.container div {
width:100%;
}
.container .header {
background-color:#d3d3d3;
padding: 2px;
cursor: pointer;
font-weight: bold;
}
.container .content {
display: none;
padding : 5px;
}
</style>
</head>
<body>
<div id="app"></div>
<div id="plot_div" class="container">
<div class="header">
<span id="header symbol">▲</span>
</div>
<div id="plot_data"></div>
</div>
</div>
</body>
<script type="text/javascript" src="app.js"></script>
<script type="text/javascript">
App.renderToDOM(document.getElementById("app"));
</script>
</html>
So for anyone who may run into this rather niche error, I replace the ? : if statement in the jquery with an actual if else statement and it is behaving as expected.
I'm using a Jekyll website, doesn't really matter because this is a static page, I just write it as additional info.
Desired behavior:
I want to load my stylesheet via javascript, so it can depend of a local stored value, let's say dark and light.
I have done a little test of loading it by JS with the following code (which works).
GREEN
<head>
...
<link rel="stylesheet" href="/assets/css/{{'light'}}.css">
...
</head>
This loads the CSS file called "light" as expected.
But now I want to depend of the localStorage, with a variable theme that has light as value. I tried the following:
RED
<head>
...
<script>
var storedTheme = window.localStorage.getItem('theme'); //Tested and working in console
theme = storedTheme ? storedTheme : 'light'; //global variable (also readable in console)
</script>
<link rel="stylesheet" href="/assets/css/{{theme}}.css"> <!-- cant read global variable -->
...
</head>
Using global variables doesn't work, it gives me a 404 error as the stylesheet path is /assets/css/.css.
After that I thought that maybe creating an element would do the trick and I created one manually to test it:
RED
<head>
...
<p id="theme" style="display:none;">dark</p>
<link rel="stylesheet" href="/assets/css/{{document.getElementById('theme').innerHTML}}.css">
...
</head>
And nope, the path still appears as: /assets/css/.css
If you change styles on the <body> you get FOUC (Flash Of Unstyled Content). Try using a close equivalent like <main> and spread it 100% x 100% and <html> and <body> as well, but give them margin and padding of 0 in order to ensure <main> covers them completely.
The [disabled] attribute for the <link> is the best way of toggling them because they are still loaded but inert. Also, in the example there is a function called loadTheme(e) that is loaded on the 'DOMContentLoaded' event which insures that all of the DOM is loaded before hand. The example below will not work because localStorage is blocked on SO. There is a functioning example on Plunker. To test it:
Click the green Preview button.
Another frame should appear on the right. Within the frame is the webpage example click the ☀️ button.
It should be in dark mode now. Next, click the refresh ⟳ button located in the mini-toolbar within the frame or press ctrl+enter for Windows OS or ⌥+return for Mac OS.
The page should still be in dark mode. 👍
/* night.css
main {
background: #000;
color: #fff;
}
*/
/* default.css */
:root {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
font: 1ch/1.5 'Segoe UI';
}
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
font-size: 4ch;
}
main {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
color: #000;
}
form {
width: 80vw;
margin: 20px auto;
}
fieldset {
width: max-content;
min-height: 25px;
margin-left: auto;
padding: 0 1.5px 1.5px;
border-radius: 8px;
background: inherit;
color: inherit;
}
button {
display: block;
width: 100%;
height: 100%;
border: 0;
font-size: 4rem;
text-align: center;
background: transparent;
cursor: pointer;
}
#theme::before {
content: '☀️';
}
.night #theme::before {
content: '🌙';
}
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href='lib/default.css' rel='stylesheet'>
<link class='night' href='lib/night.css' rel='stylesheet' disabled>
<style></style>
</head>
<body>
<main>
<form id='UI'>
<fieldset name='box'>
<legend>Theme</legend>
<button id='theme' type='button'></button>
</fieldset>
<p>Click the "Theme" switch to toggle between `disabled` `true` and `false` on `night.css` and `light.css` `
<link>`s.</p>
</form>
</main>
<script>
const UI = document.forms.UI;
const M = document.querySelector('main');
const L = document.querySelector('.night')
const switchTheme = e => {
const clk = e.target;
if (clk.matches('button')) {
M.classList.toggle('night');
L.toggleAttribute('disabled');
}
let status = M.className === 'night' ? 'on' : 'off';
localStorage.setItem('theme', status);
};
const loadTheme = e => {
let cfg = localStorage.getItem('theme');
if (cfg === 'on') {
M.classList.add('night');
L.removeAttribute('disabled');
} else {
M.classList.remove('night');
L.setAttribute('disabled', true);
}
};
UI.addEventListener('click', switchTheme);
document.addEventListener('DOMContentLoaded', loadTheme);
</script>
</body>
</html>
I am a beginner. So I am making a drum pad with 6 interactive pads using javascript. I want to be able to change the color of each pad upon clicking/touching it. The way my code works now, only the first (top left) pad gets changed by the click. I would like to have this effect happen to all the pads. querySelectorAll() on the pad variable doesn't seem to do the trick. It actually stops the first pad from being activated at all. Any tips? Thanks!
const drumKit = document.querySelector('.drumkit');
let pad = document.querySelector('.pad');
function playDrum(event) {
if (event.target.classList.contains('pad')) {
event.preventDefault();
let soundToPlay = event.target.dataset.sound;
drums.play(soundToPlay);
pad.classList.add('playing');
}
}
function setViewportHeight() {
let vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
}
setViewportHeight();
window.addEventListener('resize', setViewportHeight);
drumKit.addEventListener('click', playDrum);
drumKit.addEventListener('touchstart', playDrum);
body {
background: #353535
}
.drumkit {
display: flex;
flex-wrap: wrap;
justify-content: center;
height: 100vh;
height: calc(var(--vh, 1vh) * 100);
}
.pad {
display: flex;
justify-content: center;
align-items: center;
margin: 10px;
box-shadow: 0 0 10px #000000;
flex: 1 0 calc(33.333% - 20px);
background: radial-gradient(#e3a864, #de9866, #d08367, #af6762);
}
.playing {
transform: scale(-1.-1);
border-color: #ffc600;
box-shadow: 0 0 1rem #ffc600;
}
.pad img {
width: 150px;
pointer-events: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="#">
<link rel="stylesheet" href="./styles.css">
<title>Lofi Beat Machine</title>
</head>
<body>
<div class="drumkit">
<div class="pad" data-sound="samp1"><img src="./icons/sample.png" alt="samp1"></div>
<div class="pad" data-sound="samp2"><img src="./icons/sample.png" alt="samp2"></div>
<div class="pad" data-sound="samp3"><img src="./icons/sample.png" alt="samp3"></div>
<div class="pad" data-sound="kick"><img src="./icons/kick.png" alt="kick"></div>
<div class="pad" data-sound="snare"><img src="./icons/snare.png" alt="snare"></div>
<div class="pad" data-sound="hat"><img src="./icons/closed-hihat.png" alt="hihat"></div>
</div>
<script src="howler.min.js"></script>
<script src="app.js"></script>
</body>
</html>
Nice job so far on the project! You were right in using querySelectorAll, but you'll need to loop through the elements to add the onClick to all the pads. First I'd change the pad variable to querySelectorAll like this:
let pad = document.querySelectorAll('.pad');
And since pad is now an array, we'll change the playDrum function by updating pad.classList.add() to event.target.classList.add() like this:
event.target.classList.add('playing');
event.target will target the specific pad you have clicked. Lastly, when attaching your onClick event, you can use a forEach function like this:
pad.forEach(elem => elem.addEventListener("click", playDrum));
And you can remove the drumKit.addEventListener('touchstart', playDrum);, it's not needed when the onClick function is attached to all the individual pads.
Here's the JS with all the changes:
const drumKit = document.querySelector('.drumkit');
let pad = document.querySelectorAll('.pad');
function playDrum(event) {
if (event.target.classList.contains('pad')) {
event.preventDefault();
let soundToPlay = event.target.dataset.sound;
drums.play(soundToPlay);
event.target.classList.add('playing');
}
}
function setViewportHeight() {
let vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
}
setViewportHeight();
window.addEventListener('resize' , setViewportHeight);
pad.forEach(elem => elem.addEventListener("click", playDrum));
Trying to use ScrollWatch.js to build a web page with infinite scroll but not getting any output. Nothing is being rendered when I run my code, here is a sample of my html
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>The Gradient Boost</title>
<link rel="stylesheet" href="{% static 'second/css/app/book.css' %}">
</head>
<body>
<h2><div data-scroll-watch>First Text</div></h2>
<h2><div data-scroll-watch>Second Text</div></h2>
<h3><div data-scroll-watch>Third Text</div></h3>
<script src="{% static 'second/js/app/book.js' %}"></script>
<script src="https://cdn.jsdelivr.net/npm/scroll-watcher#latest/dist/scroll-watcher.min.js"></script>
</body>
</html>
book.js
(function() {
var addElements = function() {
var txt = document.createTextNode('Testing');
var el;
el = document.createElement('div');
el.appendChild(txt);
document.body.appendChild(el);
// If we want newly injected elements to be watched, refresh ScrollWatch. It will re-query the dom and start watching new elements.
swInstance.refresh();
};
var swInstance = new ScrollWatch({
watch: 'div',
infiniteScroll: true,
infiniteOffset: 200,
onInfiniteYInView: addElements
});
})();
and book.css
.watch-container {
font-size: 2em;
width: 75%;
height: 150px;
padding: 20px;
margin: 50px auto;
background-color: #0681CD;
color: #fff;
overflow: auto;
text-align: center;
}
div {
text-align: center;
font-size: 1em;
margin: 200px 0;
opacity: 0;
transition: opacity 1s;
font-weight: normal
}
div.scroll-watch-in-view {
opacity: 1;
}
This is the documentation I am using as guidance
Running this code on codepen seems to give me the error message in my javascript
Uncaught ReferenceError: ScrollWatch is not defined
I think your cdn link is not correct, it's scroll-watcher not scrollwatch, you can try this https://cdn.jsdelivr.net/npm/scrollwatch#2.0.1/dist/ScrollWatch-2.0.1.min.js
It works on CodePen
I want to change the global variable x when the user clicks a button. However, it is not being changed. I have researched this on Google, and it seems like I'm doing everything right.
testing.html:
<!DOCTYPE html>
<html>
<head>
<title>Testing</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/javascript" src="testing.js"></script>
<style>
div {
border: solid 1px orange;
height: 50px;
width: 50px;
font-size: 45px;
text-align: center;
}
</style>
</head>
<body>
<button>Click here</button>
<div><div/>
</body>
</html>
tesing.js:
var x;
$(document).ready(function() {
x = 0;
$("div").text(x);
$("button").on("click", function() {
x = 1;
});
$("div").text(x); //the div stays at "0" even after I click the button
});
If I put $("div").text(x); inside the click function after x = 1, then it works, but I need it to change x in the global scope, not the local one, so I can use it in other JS functions in the html file.
EDIT:
The reason I'm trying to test x outside of the click function is because I'll need to use that updated x in a document ready function inside the html file, so I can't do everything inside the click function. Maybe what I'm trying to do isn't possible? But I thought that's why global variables exist?
You have to update the HTML inside the click handler. $("div").text(x); assigns the value of x as the text of $("div"), it does not bind the text to that variable, so the text must be updated when the value of the variable is updated.
var x = 0;
$("div").text(x);
$("button").on("click", function() {
$("div").text(++x);
});
div {
border: solid 1px orange;
padding: 10px 15px;
display: inline-block;
font-size: 45px;
text-align: center;
}
div::before {
content: "x = ";
}
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<button>Increment</button><br>
<div></div>