mathjax with jquery fadein - javascript

In a html page with mathematical formulas using MathJax, I'm trying a smooth transition in the change from one formula to the another.
Here is the current code, that you can test here
<!DOCTYPE html>
<html>
<head>
<!-- https://jsfiddle.net/LnfL020r/2 -->
<title>math guided training</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
TeX: {
Macros: {
mgtMult: "",
mgtSelect: [ "\\bbox[10px,border:1px solid red]{#1}", 1],
}
}
});
</script>
<script type="text/javascript"
src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
<style>
.results {
display: flex;
height: 4cm;
position: relative;
}
#fadeBox,
#visibleBox {
width: 100%;
height: 100%;
position: absolute;
top: 0%;
left: 0;
}
</style>
</head>
<body>
<script>
var QUEUE = MathJax.Hub.queue; // shorthand for the queue
var math = null; // the jax element
var box = null; // the box math is in
var formula = "1+2x^3";
var SHOWBOX = function () {
var a = $('#box').html();
var dstDiv = $('#visibleBox');
dstDiv.html(a);
}
var SHOWBOX_FADE = function () {
var a = $('#box').html();
var dstDiv = $('#visibleBox');
var fadeDiv = $('#fadeBox');
fadeDiv.html(a);
fadeDiv.fadeIn(2000,function() {
dstDiv.html(a);
fadeDiv.hide();
});
}
var REFRESH = function () {
QUEUE.Push(
["Text",math,formula], // == math.Text(formula), [ method, object, args... ]
SHOWBOX
);
}
var REFRESH_FADE = function () {
QUEUE.Push(
["Text",math,formula], // [ method, object, args... ]
SHOWBOX_FADE
);
}
// Get the element jax when MathJax has produced it.
QUEUE.Push(
function () {
math = MathJax.Hub.getAllJax("box")[0]; // returns a MathJax.ElementJax
math.Text(formula);
SHOWBOX();
}
);
setTimeout(function(){
SHOWBOX();
}, 2000);
window.changeIt = function() {
formula = "1 + 2 { \\left( y + 4 \\right) } ^ 3 ";
REFRESH_FADE();
}
</script>
</head>
<body>
<div id="box" style="visibility:hidden; font-size: 500%; height:1px;">
\( \)
</div>
<div class="results">
<div id="visibleBox" style="font-size: 500%;">
Loading ...
</div>
<div id="fadeBox" style="font-size: 500%; display:none;">
</div>
</div>
<button onclick='changeIt()'/>click me</button>
</body>
</html>
The problem is:
The second formula has different height than the first one, due to the parenthesis. For this reason, the common part "1 + " of the second one is printed slightly down respect to its print in the first formula.
That produces an effect of borrow during the transition. I want that the "1 + " part, common to both formulas, doesn't moves when changing from first to second.
Any hint?

maybe this will work :
var SHOWBOX = function () {
var a = $('#box').html();
var dstDiv = $('#visibleBox');
// apply margin for the first equation
dstDiv.css({"margin-top":"2px"});
dstDiv.html(a);
}
var SHOWBOX_FADE = function () {
var a = $('#box').html();
var dstDiv = $('#visibleBox');
var fadeDiv = $('#fadeBox');
fadeDiv.html(a).fadeOut();
fadeDiv.fadeIn(500,function() {
dstDiv.html(a);
// remove the margin for the second equation
dstDiv.css({"margin-top":"0"});
fadeDiv.hide();
});
}
just applying a margin to counter the slight variance in top margin

Made little change in fadeIn and fadeOut
fadeDiv.html(a);
dstDiv.fadeOut(1000,function() {
dstDiv.html(a);
fadeDiv.fadeIn(1000);
});
}
Forked fiddle
Please comment if transition is not up to expection
EDIT
Updated With requirement
Fiddle link
window.onload=function(){
var QUEUE = MathJax.Hub.queue; // shorthand for the queue
var math = null; // the jax element
var mathdef = null; // the jax element
var box = null; // the box math is in
var defaultformula = "1+";
var formula = "2x^2";
var SHOWBOX = function () {
var a = $('#box').html();
var def = $('#defbox').html();
var fixedDiv = $('#fixed');
fixedDiv.html(def);
var dstDiv = $('#visibleBox');
dstDiv.html(a);
}
var SHOWBOX_FADE = function () {
var a = $('#box').html();
var dstDiv = $('#visibleBox');
var fadeDiv = $('#fadeBox');
fadeDiv.html(a);
dstDiv.fadeOut(1000,function() {
dstDiv.html(a);
fadeDiv.fadeIn(1000);
});
}
var REFRESH = function () {
QUEUE.Push(
["Text",math,formula], // == math.Text(formula), [ method, object, args... ]
SHOWBOX
);
QUEUE.Push(
["Text",mathdef,defaultformula], // == math.Text(formula), [ method, object, args... ]
SHOWBOX
);
}
var REFRESH_FADE = function () {
QUEUE.Push(
["Text",math,formula], // [ method, object, args... ]
SHOWBOX_FADE
);
}
// Get the element jax when MathJax has produced it.
QUEUE.Push(
function () {
math = MathJax.Hub.getAllJax("box")[0]; // returns a MathJax.ElementJax
mathdef = MathJax.Hub.getAllJax("defbox")[0]; // returns a MathJax.ElementJax
mathdef.Text(defaultformula);
math.Text(formula);
SHOWBOX();
}
);
setTimeout(function(){
SHOWBOX();
}, 2000);
window.changeIt = function() {
formula = "2 { \\left( y + 4 \\right) } ^ 2";
REFRESH_FADE();
}
}//]]>
.results {
display: flex;
height: 4cm;
position: relative;
}
#fadeBox,
#visibleBox {
width: 100%;
height: 100%;
position: absolute;
top: 0%;
left: 0;
}
<!DOCTYPE html>
<html>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
TeX: {
Macros: {
mgtMult: "",
mgtSelect: [ "\\bbox[10px,border:1px solid red]{#1}", 1],
},
Macros: {
mgtMult: "",
mgtSelect: [ "\\bdefbox[10px,border:1px solid red]{#1}", 1],
}
}
});
</script>
<script type="text/javascript"
src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
<div id="defbox" style="visibility:hidden; font-size: 500%; height:1px;padding-top:10px">
\( \)
</div>
<div id="box" style="visibility:hidden; font-size: 500%; height:1px;padding-left:200px">
\( \)
</div>
<div class="results">
<div id="fixed" style="font-size: 500%;margin-top:50x">
Loading ...
</div>
<div id="visibleBox" style="font-size: 500%;padding-left:100px">
</div>
<div id="fadeBox" style="font-size: 500%; display:none;padding-left:100px">
</div>
</div>
<button onclick='changeIt()'>click me</button>
</body>
</html>

Related

Annotate RoughViz chart using Rough-Notation library

I have a simple bar chart built with RoughViz.js. The key takeaway that I'd like to highlight in the chart is the difference in height between the first bar and the third bar. To do this I'd like to use the bracket annotation from Rough Notation and set the bracket to start at a y-coordiate equal to the height of the first bar and end at a y-coordinate equal to the height of the last bar. What is the best way to accomplish this?
EDIT...
this picture illustrates what I'm trying to accomplish. The large bracket is the one that the rough-notation library is drawing in my code. Note that it wraps the entire chart. I want it to instead draw the bracket like the small dark blue one that I've mocked up. The dashed lines are also just mock up so as to better convey the desired positioning.
The external libraries are:
https://github.com/jwilber/roughViz and
https://github.com/rough-stuff/rough-notation
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://unpkg.com/rough-viz#1.0.6"></script>
<script type="module" src="https://unpkg.com/rough-notation?module"></script>
<style>
body {}
;
.item1 {
grid-area: chart;
}
.item2 {
grid-area: annotation;
}
.grid-container {
margin-top: 3rem;
display: grid;
grid-template-areas:
'chart annotation';
grid-template-rows: 1fr;
grid-template-columns: 8fr, 3fr;
}
#typedtext {
font-family: 'Waiting for the Sunrise', cursive;
font-size: 25px;
margin: 10px 50px;
letter-spacing: 6px;
font-weight: bold;
color: blue;
padding-left: 3rem;
padding-top: 30%;
height: 100%;
}
</style>
</head>
<body>
<button id="annotate-button">Click me</button>
<div class="grid-container">
<div class="item1">
<div id="viz0"></div>
</div>
<div class="item2">
<div id="typedtext"></div>
</div>
</div>
</body>
</html>
<script>
// create Bar chart from csv file, using default options
new roughViz.Bar({
element: '#viz0', // container selection
data: {
labels: ['First thing', 'Second thing', 'Third thing'],
values: [100, 50, 25]
},
width: window.innerWidth * .7,
height: window.innerHeight * .7
});
</script>
<script type="module">
import { annotate } from 'https://unpkg.com/rough-notation?module';
const e = document.querySelector('#viz0');
const annotation = annotate(e, { type: 'bracket', color: 'blue', padding: [2, 10], strokeWidth: 3 });
document.getElementById("annotate-button").addEventListener('click', function(){
annotation.show();
})
</script>
<script>
//https://css-tricks.com/snippets/css/typewriter-effect/
// set up text to print, each item in array is new line
var aText = new Array(
"This is a comment"
);
var iSpeed = 10; // time delay of print out
var iIndex = 0; // start printing array at this posision
var iArrLength = aText[0].length; // the length of the text array
var iScrollAt = 20; // start scrolling up at this many lines
var iTextPos = 0; // initialise text position
var sContents = ''; // initialise contents variable
var iRow; // initialise current row
function typewriter() {
sContents = ' ';
iRow = Math.max(0, iIndex - iScrollAt);
var destination = document.getElementById("typedtext");
while (iRow < iIndex) {
sContents += aText[iRow++] + '<br />';
}
destination.innerHTML = sContents + aText[iIndex].substring(0, iTextPos) + "_";
if (iTextPos++ == iArrLength) {
iTextPos = 0;
iIndex++;
if (iIndex != aText.length) {
iArrLength = aText[iIndex].length;
setTimeout("typewriter()", 500);
}
} else {
setTimeout("typewriter()", iSpeed);
}
}
document.getElementById("annotate-button").addEventListener('click', function() {
typewriter();
})
</script>
You can also click here for a JsFiddle with the same code. The chart renders a little better on JsFiddle. https://jsfiddle.net/hughesdan/bmyda74e/1/
You can try this. You will find additional/changed code documented properly. It would be better to test the code here: https://jsfiddle.net/fo16n8tu/.
Rough annotation plugin needs HTML/SVG element to select and annotate. Therefore, I add a dummy <rect> element and use it for annotation. Let me know if this approach could work for you.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://unpkg.com/rough-viz#1.0.6"></script>
<script type="module" src="https://unpkg.com/rough-notation?module"></script>
<style>
body {}
.item1 {
grid-area: chart;
}
.item2 {
grid-area: annotation;
}
.grid-container {
margin-top: 3rem;
display: grid;
grid-template-areas:
'chart annotation';
grid-template-rows: 1fr;
grid-template-columns: 8fr, 3fr;
}
#typedtext {
font-family: 'Waiting for the Sunrise', cursive;
font-size: 25px;
margin: 10px 50px;
letter-spacing: 6px;
font-weight: bold;
color: blue;
padding-left: 3rem;
padding-top: 30%;
height: 100%;
}
</style>
</head>
<body>
<button id="annotate-button">Click me</button>
<div class="grid-container">
<div class="item1">
<div id="viz0"></div>
</div>
<div class="item2">
<div id="typedtext"></div>
</div>
</div>
</body>
</html>
<script>
// create Bar chart from csv file, using default options
const viz = new roughViz.Bar({
element: '#viz0', // container selection
data: {
labels: ['First thing', 'Second thing', 'Third thing'],
values: [100, 50, 25]
},
width: window.innerWidth * .7,
height: window.innerHeight * .7
});
</script>
<script type="module">
import { annotate } from 'https://unpkg.com/rough-notation?module';
const e = document.querySelector('#viz0');
/* START additional code */
// Select <g id="#viz0_svg"> element
const svgGroupWrapper = e.querySelector('[id="#viz0_svg"]');
// Get each bar <g> element
const bars = svgGroupWrapper.getElementsByClassName('viz0');
// Height difference between the first (bars[0]) and the third bar (bars[2])
const diffHeight = bars[0].getBoundingClientRect().height - bars[2].getBoundingClientRect().height;
// Get the position annotation element by horizontal x-axis
const offsetX = svgGroupWrapper.getElementsByClassName('rough-xAxisviz0')[0].getBoundingClientRect().width;
// Width of annotation element (also used in annotation options!!!)
const annotationPadding = [0, 6];
// Create dummy <rect> element to annotate on it. Annotation needs an HTML element to work
const elementToAnnotate = document.createElementNS('http://www.w3.org/2000/svg','rect');
// Set "x" attribute to offsetX - annotationPadding[1] - 1 to shift <rect> to very right, but with place for annotaion and width of rect (=1)
elementToAnnotate.setAttribute('x', offsetX - annotationPadding[1] - 1);
// Just positioning "y" to 0 so that the element start from top of the SVG
elementToAnnotate.setAttribute('y', '0');
// Set "width" to 1 to be identifable in SVG for annotation plugin
elementToAnnotate.setAttribute('width', '1');
// Set "height" to the height difference value between first and third bars
elementToAnnotate.setAttribute('height', diffHeight);
// Set "fill" to transparent so that the <rect> element is not visible for users
elementToAnnotate.setAttribute('fill', 'transparent');
// Add the element in wrapper <g> element
svgGroupWrapper.appendChild(elementToAnnotate);
/* END additional code */
// CHANGED CODE: Annotate dummy <rect> element for desired effects
const annotation = annotate(elementToAnnotate, { type: 'bracket', color: 'blue', padding: annotationPadding, strokeWidth: 3 });
document.getElementById("annotate-button").addEventListener('click', function(){
annotation.show();
})
</script>
<script>
//https://css-tricks.com/snippets/css/typewriter-effect/
// set up text to print, each item in array is new line
var aText = new Array(
"This is a comment"
);
var iSpeed = 10; // time delay of print out
var iIndex = 0; // start printing array at this posision
var iArrLength = aText[0].length; // the length of the text array
var iScrollAt = 20; // start scrolling up at this many lines
var iTextPos = 0; // initialise text position
var sContents = ''; // initialise contents variable
var iRow; // initialise current row
function typewriter() {
sContents = ' ';
iRow = Math.max(0, iIndex - iScrollAt);
var destination = document.getElementById("typedtext");
while (iRow < iIndex) {
sContents += aText[iRow++] + '<br />';
}
destination.innerHTML = sContents + aText[iIndex].substring(0, iTextPos) + "_";
if (iTextPos++ == iArrLength) {
iTextPos = 0;
iIndex++;
if (iIndex != aText.length) {
iArrLength = aText[iIndex].length;
setTimeout("typewriter()", 500);
}
} else {
setTimeout("typewriter()", iSpeed);
}
}
document.getElementById("annotate-button").addEventListener('click', function() {
typewriter();
})
</script>
You could try something like in the following example:
const lbls = ['First thing', 'Second thing', 'Third thing'];
const destination = document.getElementById("typedtext");
const empty = (data) => {
switch (true) {
case (data == null || data == 'undefined' || data == false || data == ''):
return true;
case (Array.isArray(data)):
return data.length == 0;
case (typeof data == 'object'):
return (Object.keys(data).length == 0 && data.constructor == Object);
case (typeof data == 'string'):
return data.length == 0;
case (typeof data == 'number' && !isNaN(data)):
return data == 0;
default:
return false;
}
}
const typewriter = () => {
settings.sContents = ' ';
settings.iRow = Math.max(0, settings.iIndex - settings.iScrollAt);
while (settings.iRow < settings.iIndex) {
settings.sContents += settings.aText[settings.iRow++] + '<br />';
}
if(!empty(settings.aText[settings.iIndex])) {
destination.textContent = settings.sContents + settings.aText[settings.iIndex].substring(0, settings.iTextPos) + "_";
}
if (settings.iTextPos++ == settings.iArrLength) {
settings.iTextPos = 0;
settings.iIndex++;
if (!empty(settings.aText[settings.iIndex]) && settings.iIndex != settings.aText.length) {
settings.iArrLength = settings.aText[settings.iIndex].length;
setTimeout(typewriter(), 500);
}
} else {
setTimeout(typewriter(), settings.iSpeed);
}
}
new roughViz.Bar({
element: '#viz0', // container selection
data: {
labels: lbls,
values: [100, 50, 25]
},
width: window.innerWidth * 0.7,
height: window.innerHeight * 0.7
});
var settings = {};
settings.diff = [];
lbls.forEach((label) => {
let g = document.querySelector('g[attrX=\"' + label + '\"]');
g.addEventListener('click', (e) => {
let b = parseInt(e.target.parentNode.getAttribute('attrY'));
if (e.target.getAttribute('fill') == '#ff0000') {
e.target.setAttribute('fill', 'transparent');
let index = settings.diff.indexOf(b);
settings.diff = settings.diff.filter((x, i) => i !== index);
} else {
e.target.setAttribute('fill', '#ff0000');
settings.diff.push(b);
}
});
});
document.getElementById("annotate-button").addEventListener('click', (e) => {
if (settings.diff.length == 2) {
settings.aText = [(settings.diff[0] - settings.diff[1]).toString()];
} else {
settings.aText = ['Select a pair first!'];
}
settings.iSpeed = 10; // time delay of print out
settings.iIndex = 0; // start printing array at this posision
settings.iScrollAt = 20; // start scrolling up at this many lines
settings.iTextPos = 0; // initialise text position
settings.sContents = ''; // initialise contents variable
settings.iRow = 0; // initialise current row
settings.iArrLength = settings.aText[0].length; // the length of the text array
typewriter();
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://unpkg.com/rough-viz#1.0.6"></script>
<script type="module" src="https://unpkg.com/rough-notation?module"></script>
<script type="module">
import { annotate } from 'https://unpkg.com/rough-notation?module';
const ee = document.querySelector('#viz0');
const annotation = annotate(ee, { type: 'bracket', color: 'blue', padding: [2, 10], strokeWidth: 3 });
document.getElementById("annotate-button").addEventListener('click', function(){
annotation.show();
})
</script>
<style>
body {}
;
.item1 {
grid-area: chart;
}
.item2 {
grid-area: annotation;
}
.grid-container {
margin-top: 3rem;
display: grid;
grid-template-areas:
'chart annotation';
grid-template-rows: 1fr;
grid-template-columns: 8fr, 3fr;
}
#typedtext {
font-family: 'Waiting for the Sunrise', cursive;
font-size: 25px;
margin: 10px 50px;
letter-spacing: 6px;
font-weight: bold;
color: blue;
padding-left: 3rem;
padding-top: 30%;
height: 100%;
}
</style>
</head>
<body>
<button id="annotate-button">Click me</button>
<div class="grid-container">
<div class="item1">
<div id="viz0"></div>
</div>
<div class="item2">
<div id="typedtext"></div>
</div>
</div>
</body>
</html>
OR use this JSFiddle

Call different events when a variable change in JS

I build a small application to switch between random images in an iframe, I would like that after 10 or 20 images the user will get an image or source I want him to get and not a random one, and then return to the loop.
I have a problem with the count and if function, will appreciate any help. Thanks
<body>
<iframe id="img_main" src="https://www.example.com/img_4.jpg" width="600" height="800" frameborder="1" scrolling="no"></iframe>
<br>
<button id="H" type="button" onclick=(newImg(),clickCounter(),changeImg())>images</button>
<div id="result"></div>
<script>
function newImg(){
var myArray = [
"img_1.jpg",
"img_2.jpg",
"img_3.jpg",
"img_4.jpg"
];
var imgNew = "https://example.com/"
var randomItem = myArray[Math.floor(Math.random()*myArray.length)];
document.getElementById("img_main").src = "https://example.com/" + randomItem ;
}
function clickCounter() {
if (typeof(Storage) !== "undefined") {
if (localStorage.clickcount) {
localStorage.clickcount = Number(localStorage.clickcount)+1;
} else {
localStorage.clickcount = 1;
}
function changeImg(){
if (localStorage.clickcount = 10,20) {
document.getElementById("ins_main").src = "https://example.com/pre_defined_img.jpg";
}
}
</script>
</body>
the way I see that...
by simply use of the modulo (finds the remainder after division)
you don't need to use an iframe, img element is enough.
use an IIFE. as closure method
file : "myScript.js"
const imgBox = (function()
{
const refURL = 'https://i.picsum.photos/id/'
, imgName = [ '251/300/500.jpg', '252/300/500.jpg', '253/300/500.jpg', '254/300/500.jpg'
, '255/300/500.jpg', '256/300/500.jpg', '257/300/500.jpg', '258/300/500.jpg'
, '259/300/500.jpg', '260/300/500.jpg', '261/300/500.jpg', '146/300/500.jpg'
, '263/300/500.jpg', '264/300/500.jpg', '265/300/500.jpg', '266/300/500.jpg'
, '267/300/500.jpg', '268/300/500.jpg', '269/300/500.jpg', '270/300/500.jpg'
, '271/300/500.jpg', '272/300/500.jpg', '273/300/500.jpg', '274/300/500.jpg'
]
, imgZero = '250/300/500.jpg'
, imgSiz = imgName.length
, imgMain = document.getElementById('img-main')
;
var imgNum = 0, randomI = 0;
const obj =
{ setNext()
{
if (!(++imgNum % 10)) // each 10 times
{
imgMain.src = refURL + imgZero
}
else
{
randomI = Math.floor(Math.random() * imgSiz)
imgMain.src = refURL + imgName[randomI]
}
return imgNum
}
}
return obj
})()
const btImg = document.getElementById('bt-img')
, imgCount = document.getElementById('img-count')
, banner = document.getElementById('my-banner')
;
btImg.onclick =evt=>
{
let counter = imgBox.setNext()
imgCount.textContent = counter
if (!(counter %50)) // each 50 times..
{
changeBanner()
}
}
// changing banner function...
function changeBanner()
{
//.....
// do what ever you want to change your banner
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
<style>
img#img-main {
width: 300px;
height: 500px;
border: 1px solid grey;
padding: 2px;
}
</style>
</head>
<body>
<img id="img-main" src="https://i.picsum.photos/id/250/300/500.jpg" alt="" >
<p id="img-count">0</p>
<button id="bt-img">Image change</button>
<div id="my-banner">the banner</div>
<script src="myScript.js"></script>
</body>
</html>

How do I programatically change a picture inside a div?

Here there is full code as you guys can see.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Collage</title>
</head>
<style>
div
{
background: url("Image/191203174105-edward-whitaker-1-large-169.jpg")
;
height: 300px;
width: 300px;
}
</style>
<body>
<div id="div"></div>
<button id="button">Next</button>
<script>
As here I took variable im where I feed 3 images.
var im=[
{'img':'Image/191203174105-edward-whitaker-1-large-169.jpg',}
,{'img':'Image/5718897981_10faa45ac3_b-640x624.jpg',},
{'img':'Image/gettyimages-836272842-612x612.jpg',},
];
var a=document.getElementById('button');
var b=document.getElementById('div')
a.addEventListener('click',next);
so here according to my knowledge it should provide the link of the each pic as loop starts but in program. I dont get the desired result. Can you please help me understand why this is happening?
function next()
{
for(var i=1;i<im.length;i++)
{
b.style.background=`url(${im[i].img})`;
}
}
</script>
</body>
</html>
var i = 0;
var im = [{
'img': 'https://picsum.photos/536/354'
},
{
'img': 'https://picsum.photos/id/237/536/354'
},
{
'img': 'https://picsum.photos/seed/picsum/536/354'
}
];
var a = document.getElementById('button');
var b = document.getElementById('div')
a.addEventListener('click', next);
function next() {
console.log(i);
b.style.background = `url(${im[i].img})`;
i++;
if (i == im.length) {
i = 0;
}
}
div {
background: url("https://picsum.photos/id/1084/536/354?grayscale");
height: 300px;
width: 300px;
}
<div id="div"></div>
<button id="button">Next</button>
If you're looking to cycle through pictures on a button click, then you can't really use a loop. In the code that you posted, on the click of the button, it rapidly looped through all of the pictures. You need to create a counter, and increment it on each button click.
The snippet below I've added in a previous button as well and you can cycle through the pictures both forward and backward.
const im = {
'img1': 'https://placehold.it/300x150/ff0000/ffffff?text=image_1',
'img2': 'https://placehold.it/300x150/00ff00/ffffff?text=image_2',
'img3': 'https://placehold.it/300x150/0000ff/ffffff?text=image_3',
};
const imgDiv = document.getElementById('imgDiv')
const btnNext = document.getElementById('btnNext');
const btnPrev = document.getElementById('btnPrev');
const totImages = Object.keys(im).length;
let imgNumber = 1;
btnNext.addEventListener('click', next);
btnPrev.addEventListener('click', prev);
function next() {
imgNumber++
let img = imgNumber <= totImages ? `img${imgNumber}` : null;
if (img) imgDiv.style.background = `url(${im[img]})`;
if (imgNumber === totImages) btnNext.disabled = true;
if (imgNumber > 1) btnPrev.disabled = false;
}
function prev() {
imgNumber--
let img = imgNumber >= 0 ? `img${imgNumber}` : null;
if (img) imgDiv.style.background = `url(${im[img]})`;
if (imgNumber < totImages) btnNext.disabled = false;
if (imgNumber === 1) btnPrev.disabled = true;
}
#imgDiv {
background: url("https://placehold.it/300x150/ff0000/ffffff?text=image_1");
height: 150px;
width: 300px;
}
#btnDiv {
width: 300px;
height: auto;
position: relative;
}
#btnPrev {
position: absolute;
left: 0;
top: 0;
}
#btnNext {
position: absolute;
right: 0;
top: 0;
}
<div id="imgDiv"></div>
<div id='btnDiv'>
<button id="btnPrev" disabled>&loarr; Prev</button>
<button id="btnNext">Next &roarr;</button>
</div>

How to save drag/drop coordinates back to angular model?

My code allows for dragging and dropping of form fields overlaying an page image. I'm using Kendo-ui for the drag/drop but that's not critical to the answer, I don't think, and the demo is overly simplified and doesn't contain the image. I need to be able to change the angular model's coordinates to reflect the dropped location so I can save it. The meat of my question is HOW to update the model. What's the most efficient way of doing this since I can possibly have hundreds of fields? Is it possible to bind to the left/bottom CSS coordinates? Should I update the CSS manually using jQuery and then update the model?
Here's the plunker with my code
INDEX.HTML
<!DOCTYPE html>
<html ng-app="app">
<head>
<title></title>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2016.2.714/styles/kendo.common-bootstrap.min.css" />
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2016.2.714/styles/kendo.bootstrap.min.css" />
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2016.2.714/styles/kendo.bootstrap.mobile.min.css" />
<script src="https://kendo.cdn.telerik.com/2016.2.714/js/jquery.min.js"></script>
<script src="https://code.angularjs.org/1.5.8/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-animate.js"></script>
<script src="https://kendo.cdn.telerik.com/2016.2.714/js/kendo.all.min.js"></script>
<script id="page-template" type="text/ng-template">
<div class="page" kendo-droptarget style="{{ 'width:' + (p.width + 2) + 'px; height:' + (p.height + 2) + 'px;' }}" ng-repeat="p in model.transaction.selectedDocument.pages">
<div class="field" data-fieldname="f.fieldName" kendo-draggable k-hint="model.draggableHint" k-dragstart="model.onDragStart" k-dragend="model.onDragEnd" ng-repeat="f in p.fields" style="{{ 'left:' + f.left + 'px;bottom:' + f.bottom + 'px;width:' + f.width + 'px;height:' + f.height + 'px;' }}">
<div></div>
</div>
</div>
<pre>{{ model | json }}</pre>
</script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<page-image-component></page-image-component>
</body>
</html>
SCRIPT.JS
// Code goes here
console.clear();
function pageImageController(TransactionFactory) {
var model = this;
model.transaction = TransactionFactory;
model.draggableHint = function (e) {
return e.clone();
}
model.onDragStart = function (e) {
console.log(e);
e.currentTarget.hide();
}
model.onDragEnd = function (e) {
console.log(e);
//e.currentTarget.css("left", "0px").css("top", "0px");
var field = e.currentTarget[0];
console.log(e.currentTarget)
e.currentTarget.show();
}
}
var app = angular.module("app", ["kendo.directives"]);
app.factory('TransactionFactory', function () {
var transaction = {
selectedDocument: {
fileName: "my.pdf",
pages: [{
pageNumber: 1,
width: 400,
height: 500,
fields: [
{
fieldName: "my field 1",
width: 75,
height: 13,
left: 50,
bottom: 300,
instance: 1
},
{
fieldName: "another field 1",
width: 65,
height: 13,
left: 200,
bottom: 440,
instance: 1
},
]
}]
}
};
return transaction;
});
app.component("pageImageComponent", {
template: $("#page-template").html(),
controllerAs: "model",
controller: ["TransactionFactory", pageImageController]
});
STYLE.CSS
/* Styles go here */
.page
{
border: 1px solid black;
position: relative;
}
.field
{
background-color: #ddd;
position: absolute;
}
I think I figured it out and I think it's efficient enough for rock and roll.
Here's the Plunker
function pageImageController(TransactionFactory) {
var model = this;
model.transaction = TransactionFactory;
var tempLeft = 0;
var tempTop = 0;
model.draggableHint = function (e) {
return e.clone();
}
model.onDragStart = function (e) {
//console.log(e);
e.currentTarget.hide();
}
model.onDrop = function (e) {
tempLeft = e.draggable.hint.offset().left -9;
tempTop = e.draggable.hint.offset().top +2;
console.log(e.draggable);
}
model.onDragEnd = function (e) {
//console.log(e);
var field = e.currentTarget[0];
//console.log(field)
var fieldIndex = field.attributes['data-fieldindex'].value;
var pageIndex = field.attributes['data-pageindex'].value;
//console.log(fieldIndex);
//console.log(pageIndex);
var tempBottom = model.transaction.selectedDocument.pages[pageIndex].height - tempTop;
model.transaction.selectedDocument.pages[pageIndex].fields[fieldIndex].left = tempLeft;
model.transaction.selectedDocument.pages[pageIndex].fields[fieldIndex].bottom = tempBottom;
e.currentTarget.css("left", tempLeft + "px").css("bottom", tempBottom + "px");
e.currentTarget.show();
}
}

Problem with putting in the right parameters

I have problem with putting in the right parameters from an eventListener into a function.
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript">
window.onload = function() {
var galleryContainer = document.getElementById('galleryContainer');
var image = galleryContainer.getElementsByTagName('div');
//console.log(image);
var images = new Array();
images.push(image);
for(var i = 0; i < images[0].length; i++) {
images[0][i].addEventListener('click', function() {showImage(this)
}, false);
};
}
// I dont know with parameter to put into showImage() from the listener.
function showImage( here is the problem ) {
var preview = document.getElementById('preview');
preview.innerhtml = image.innerhtml;
// I want to put the image into the preview element.
}
</script>
</head>
<body>
<div id="galleryContainer">
<div>trams</div>
<div>trams</div>
<div>trams</div>
<div>trams</div>
</div>
<div id="preview" style="width: 200px; height: 200px; border: 1px solid red"></div>
</body>
Try this code:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript">
window.onload = function() {
var galleryContainer = document.getElementById('galleryContainer');
var images = galleryContainer.getElementsByTagName('div');
//console.log(images);
for(var i = 0; i < images.length; i++) {
images[i].addEventListener('click', showImage, false);
};
}
// I dont know with parameter to put into showImage() from the listener.
function showImage(ev) {
ev=ev||event; // ev now point to click event object
var preview = document.getElementById('preview');
preview.innerHTML = this.innerHTML; // this point to DIV(trams)
}
</script>
</head>
<body>
<div id="galleryContainer">
<div>trams1</div>
<div>trams2</div>
<div>trams3</div>
<div>trams4</div>
</div>
<div id="preview" style="width: 200px; height: 200px; border: 1px solid red"></div>
</body>
Working example http://jsfiddle.net/Cp6HJ/
window.onload = function() {
var galleryContainer = document.getElementById('galleryContainer');
var image = galleryContainer.getElementsByTagName('div');
//console.log(image);
var images = new Array();
images.push(image);
for(var i = 0; i < images[0].length; i++) {
var callback = function(item){ return function(){ showImage(item); }; }(images[0][i]);
images[0][i].addEventListener('click', callback, false);
};
};
function showImage( item ) {
var preview = document.getElementById('preview');
preview.innerHTML = item.innerHTML;
}
Use this for the function definition statement :
function showImage(image) {
...
}
And correction in the inner html statement:
(note the capitalized 'H')
preview.innerHTML = image.innerHTML;

Categories