How to randomize an element position in Qualtrics? - javascript

I would like to place the next button of a Qualtrics survey in three positions (horizontally aligned: left, middle, right). The position must be constant for the same participant (e.g. for participant 1 always on the left), but should be randomized between participants (e.g. participant 2 on the right, and so on).
I have used the following JS code for individual questions (since I can only add JS for each question but not for the entire survey), but if I apply this to all individual questions the next button will appear in different locations for the same participant:
var Button = document.getElementById("NextButton");
var ButtonContainer = Button.parentNode;
if(Math.random() < 0.333){
ButtonContainer.style.textAlign = "left"
}else {
if (Math.random() < 0.5) {
ButtonContainer.style.textAlign = "center"
} else {
ButtonContainer.style.textAlign = "right"
}
}
Apparently, the only way to add custom code for the entire survey is via CSS (in Look & Feel settings), I'm aware I cannot implement if/else functions in CSS, thus I don't know what to do.
Any hint would be really appreciated! Thanks in advance!

You can run JS on every page in the survey by placing it in the survey header or footer inside a script tag. However, using your script would result in the button being placed in different position on different pages (it would randomize for each page).
Instead, use the survey flow randomizer to set an embedded data variable to "left", "right", or "center". I haven't done it, but you can try piping the embedded variable into your custom CSS to position the button. It that doesn't work you can pipe the embedded data variable into the header/footer JS to position the button.

Related

How can I place a white image at the top and bottom (eg: 40px) of every image in an html file in js?

I am trying to add an image/blank rectangle on top of/overlaid on the top and bottom of every image on an html page. I plan to do this via a user-script, but I could not find any information on how to append an image on another at a specified PX x PX. I am slightly familiar with js. I have done two small hobby projects (an image parser and a poker game) this being the third, and assume I will have to achieve following:
Create a blank image to cover the top and bottom part of the image.
This can be done by creating a simple rectangle I think. I can play with the parameters of the size to make it fit.
get every image on the site
I can probably do this by parsing the DOM (I'm not sure if I need to do this if I am using a user-script) and doing a forEach(img), and within the forEach(img => I can add the rectangle to the top and bottom thereby adding it to every image on the page.
somehow append the blank image from above on top of the top and bottom of each image.
This is where I am lost. I have appended images to the DOM before, but I don't know how to do it through a user-script and I also don't know have to append an image on another image. I have thought of doing the following, but I am unsure how to continue:
I also have linked an example where I would use this user-script. What I am trying to do is remove a watermark. (I am only doing this locally on my computer as to not steal the translators work, which is why I am using JavaScript.) So to recap I am looking for how to solve number 3, and if possible/optionally an explanation of how to do this in grease-monkey or any other user-script manager. Let me know if anything was unclear and thanks to anybody who comments/answers this problem. edit:clarity
here is a link to an example use case
If you just need these two balnk space on each img on the page, just using this css:
img{
height: 945px;
object-fit:cover;
}
Or js:
var x = document.querySelectorAll("img");
var i;
for (i = 0; i < x.length; i++) {
x[i].style.height = "954px";
x[i].style.objectFit = "cover";
}

Move to center a selected object with scrollableWidth and scrollToHorizontalOffset

I am having a number (10) of objects which are clickable, but struggling with moving a selected one to the middle of the scroll view. You can see on the image below that number four is selected but not in the middle.
I tried to use:
myScrollView.scrollToHorizontalOffset(myScrollView.scrollableWidth / 2, true)
But it always bring the whole scroll view into the middle. Can anyone help with making it working? Thank you in advance.
Since You didn't put the Angular tag, I am assuming you are using the Typescript flavor of Nativescript.
In order to do this, you'd have to find a way keep track of your base (starting point) and your target (the one that the user just clicked) so that you can get there x offsets and animate the scroll from one to another.
Here's an example in your code behind:
export function() {
const base = page.getViewById('label1') as Label;
const target = page.getViewById('label2') as Label;
myScrollView.scrollToHorizontalOffset(target.getLocationRelativeTo(base).x, true);
}
Now, the code above will just do a minimum scroll to get to your target element (and you can use a different element other than the example label). But if you want to make it center, you can add an additional offset depending on how wide your scroll container is.
eg.
myScrollView.scrollToHorizontalOffset(target.getLocationRelativeTo(base).x + (myScrollView.width / 2), true);
Note that this is my hypothesis from something similar I've done before (just not needing to be center). So might need to play with the additional offset.
EDIT: (This is how to make it work specifically according to the OPs need)
myScrollView.scrollToHorizontalOffset(target.getLocationRelativeTo(base).x - (myScrollView.scrollableWidth / 2)), true);

Display dynamic html content like an epub/ebook, without converting html to epub format?

I want to create a responsive, mobile optimized reading experience similar to an epub/ebook reader, like the Kindle app, or iBooks, using dynamic html as the source.
Imagine a long article or blog post that requires a lot of vertical scrolling to read, especially on a small mobile device. What I would like to do is break the long page into multiple full-screen sections, allowing the user to use left/right navigation arrows and/or the swipe gesture to "page" through the article.
There are many JS libraries available that can create a "slide show" or "carrousel" of pre-defined slides (using divs or other container elements). But I want the text and html content to dynamically re-flow to fit any device viewport and still be readable... just like an epub/ebook user interface, like the Kindle app or iBooks. So, for the same article, there would be many more "pages" on a phone than there would be on a tablet or desktop viewport, and those "pages" would need to be dynamically created/adjusted if/when the viewport size changes (like switching from portrait to landscape on a mobile device).
Here is an example of a javascript .epub reader: epub.js
... notice the responsive behavior. When you resize your viewport, all the text re-flows to fit the available space, increasing or decreasing the total number of "pages". The problem is that epub.js requires an .epub file as its source.
What I want is the same user interface and functionality for an html page.
I have searched and searched for some kind of library that can do this out of the box, but haven't been able to find anything.
I realize that I could use a conversion script to convert my html page into an .epub file, and then use epub.js to render that file within the browser, but that seems very round-about and clunky. It would be so much better to mimic or simulate the .epub reader user experience with html as the direct source, rendering/mimicking a client side responsive ebook user experience.
Does anyone know if something like this already exists, or how I could go about building it myself?
The crucial functionality is the dynamic/responsive text-reflow. When the viewport dimensions are reduced, the text/content needs to reflow to the next "page" to avoid any need for vertical scrolling. I don't know how to do this efficiently. If I were to code it myself, I might use something like the jQuery Columnize plugin, setting all columns to width: 100vw; height: 100vh, so that each column is like a "page", and then figuring out how to create a swipe UI between those "pages".
Any help is much appreciated!
This becomes very difficult if the html page is complex, eg with precisely positioned elements or images. However if (as in the epub.js example) the content consists only of headings and paragraphs, it is achievable.
The basic idea is to progressively add content until just before the page overflows. By keeping track of where we start and stop adding content, clicking to the next page is a case of changing the page start to the previous page end (or vice versa if you're going back).
Process for reshaping content into pages
Let's assume you have all your content in one long string. Begin by splitting all the content into an array of words and tags. It's not as easy as splitting by whitespace as whitespace between < and > should be ignored (you want to keep classnames etc within each tag). Also tags should be separated as well, even if there is no whitespace between the tag and a word.
Next you need a function that checks if an element's contents overflow the element. This question has a copy-paste solution.
You need two variables, pageStart and pageEnd, to keep track of what indexes in the array are the beginning and end of the current page.
Beginning at the index in pageStart you add elements from the array as content to the page, checking after each add whether or not the contents overflow. When they do overflow you take the index you're up to, minus 1, as the index for pageEnd.
Keeping tags across page breaks
Now if all's ticketyboo then this should fill the page pretty well. When you want to go to the next page set your new pageStart as pageEnd + 1 and repeat the process. However there are some issues that you may want to fix.
Firstly, what happens if the page overflows in the middle of a paragraph? Strictly speaking the closing tag, </p>, is not required in HTML, so we don't need to worry about it. But what about the start of the next page? It will be missing an opening tag and that is a major problem. So we have make sure we check if the page's content begins with a tag, and if it doesn't then we get the closest opening tag prior to the current pageStart (just step back along the array from pageStart) and add it in before the rest of the content.
Secondly, as shown in the example, if a paragraph continues onto the next page, the last line of the current page is still justified. You need to check if pageEnd is in the middle of a paragraph and if so add syle="text-align-last:justify;" to the opening tag of that paragraph.
Example implementation
A pen showing all this in action is at https://codepen.io/anon/pen/ZMJMZZ
The HTML page contains all content in one long element. The content is taken directly from the container #page and reformed into pages, depending on the size of #page. I have't implemented justifying the last line if a page break occurs within a paragraph. Resize the #page element in the css and see how the content resizes itself - note that since the page size is fixed you'll have to use click forward and back to trigger a recalculation. Once you bind the page size to the window size, recalculating pages on the fly simply involves adding a resize event listener to the window that calls fillPage.
No doubt there are numerous bugs, indeed it will sometimes display things incorrectly (eg skipping or repeating words at the beginning or end of a page), but this should give you an idea of where to start.
Take a look at this repository on GitHub. Otherwise, you can create a one-page website with many sections, each one as high as the viewport, by using only CSS (demo):
.section { height: 100vh; }
or by using JavaScript, adding an anchor to each section to navigate between them, and applying a responsive unit (my demo) for the text of each section, to adapt it on resize... Something like this:
var curr_el_index = 0;
var els_length = $(".container").length;
$(".next_section").on("click", function(e) {
curr_el_index++;
if (curr_el_index >= els_length) {
curr_el_index = 0;
}
$("html, body").animate({
scrollTop: $(".container").eq(curr_el_index).offset().top
}, 300);
return false;
});
$(".previous_section").on("click", function(e) {
curr_el_index--;
if (curr_el_index < 0) {
curr_el_index = els_length - 1;
}
$("html, body").animate({
scrollTop: $(".container").eq(curr_el_index).offset().top
}, 300);
return false;
});
* {
border: 0;
margin: 0;
padding: 0;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
body {
background-color: #1a1a1a;
}
section {
height: 100vh;
background-color: #eee;
border: 2px solid red;
font-size: 6vw;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="container">Section 1 Previous Next</section>
<section class="container">Section 2 Previous Next</section>
<section class="container">Section 3 Previous Next</section>
<section class="container">Section 4 Previous Next</section>
<section class="container">Section 5 Previous Next</section>
EDIT #1
An idea of algorithm, that come from a my codepen, that uses the same jQuery plugin:
Create your reader layout, copying the whole text in it
Use this jQuery plugin to check the text inside the viewport (demo)
Count the number of characters/WORDS with "Onscreen" label in the
viewport (a references)
Split the whole text in a list containing as many characters/WORDS as
there are in the "Onscreen" label
Create a section for each element of the obtained list, filling each
section with the relative text; the number of elements of the list
gives you the number of pages (sections) of the whole text. You may
navigate between sections like above
On resize event, redo [2-5] algorithm steps
Cheers
The idea is to have a div that will contain the whole text (let's call this div #epub_container). Then, you will have a div with the same size of the page viewport (let's call it #displayer) and it will contain #epub_container.
#displayer will have css overflow:hidden. So when the site loads, it will only show the first page, because the rest of the #epub_container will be hidden.
Then you need a page navigator to increment/decrement the page number. When the page number changes, we will move the top offset of the #epub_container based on that.
This is the jQuery function:
function move_to_page() {
var height = window.innerHeight;
var width = window.innerWidth;
var $displayer = $('#displayer');
var offset = $displayer.offset();
$displayer.height(height - offset.top - 5);
var $epub = $('#epub_container');
var offset_top = offset.top - $displayer.height() * m_page;
$epub.offset({top: offset_top, left: offset.left});
}
JSFiddle
EDIT: call move_to_page() after the text reflow in order to recompute the pages.
I created a plugin that handles this perfectly. It has features like dark mode, font changing, line height adjustment, select chapter in a side nav menu, save and restore scrolling/reading position. You can find it for free on git hub at https://github.com/E-TechDev/Html-Book-Reader
Screenshots
Light Mode Dark Mode Side Nav Menu Change Font Adjust Paragraph
You can try CSS scroll snap points on text with columns
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scroll_Snap_Points
Somehow make the columns as wide as the viewport, and allow horizontal snapped scrolling.
Update
I mean to try to do the text flowing entirely using css. Pen:
https://codepen.io/ericc3141/pen/RYZEpr
body {
scroll-snap-type: mandatory;
scroll-snap-points-x: repeat(100%);
}
#columns-test {
height: 80vh;
columns: 90vw auto;
}
All you need is to insert a page break at the right places when you load the page. You can take the cue from here:
Dynamic Page-Break - Jquery
Here you can set the page height to your viewport height. You can handle the rest with javascript and css.

Basic "manga reader"-like carousel of images

I have several pages of a manga in .png format, around 300, and I would like to set up a section on my website so that users can read the manga, browsing through the pages using two arrows ("next page" and "previous page"). I don't care about animations between pages. The perfect example of what I want to achieve is MangaFox (not the whole website, just the window where you can read the manga).
The basic setting is: a 300px wide menu with the chapters list on the left, and manga pages appearing to the right. Either in the menu or below where the manga page img, two arrows let you go to the previous or next page.
I thought about using iframes: links to HTML pages containing each manga page would target the iframe and appear in it. However, this requires me to ceate an HTML page for each page, and set the links to the previous and next page manually. I would have 300 html pages, so this would be too heavy and time consuming.
I also tried linking the chapters list directly to the .png files, but the images are not styled as I would like (at least in Chrome, they don't appear in the center of the page, but rather in the upper left corner) and I would still have to set the previous and next arrows link manually.
Whai I dream of is:
- there's a list of the .png files, that sets a fixed order for the pages;
- a dropdown list in the left menu can point directly to a certain page in the list;
- the previous and next arrows recognize which image is being shown, and a click on the arrows skips to the next or previous item on the list. If there's no page before the current one, the "previous" arrow disappears; same for the "next" arrow in case the item is the last on the list.
Maybe there's a way simpler way to do it I didn't think of, but I can't find it.
Thank you in advance for your help!
(P.S.: I'm not using WordPress, just plain HTML, CSS and PHP)
Here's the simplest way I can think of doing this:
Left arrow
<a id="leftArrow" href="#{n-1}"></a>
Right arrow
<a id="rightArrow" href="#{n+1}"></a>
Set up onhashchange function that reads location.hash and sets the src attribute of the img element utilizing an array of pages you've defined somewhere:
window.onhashchange = function(){
var img = document.query('img');
var left = document.query('#leftArrow');
var right = document.query('#rightArrow');
var pageNumber = parseInt(location.hash);
//put some error handling here for edge cases, then...
img.src = imagesArray[pageNumber];
left.href = '#' + (pageNumber - 1);
right.href = '#' + (pageNumber + 1);
};
The page links in your side menu would have href="#{page number}" and would trigger the onhashchange function when clicked, updating the image and the arrows.
Hope this helps.

javascript to track and place multiple images on top of an image

I did a search here and couldn't find any questions with answers that were suitable to this.
I am writing a hockey scoring chance tracker and basically I want to show an image of the hockey ice and each time you click on the image it remembers where you clicked, puts a small red circle where you clicked with a number on top. That number is to be an auto incrementing number. Ultimately I want to track where all the mouse clicks are for storage into a database.
To the side of the image will be a form and each time the mouse is clicked it adds a new row to the table. This part is not too hard, I could easily do it with jquery.
The problem I am having is trying to find a quick easy way to keep laying the same image, multiple times, on top of another image, where the user clicks. I have been looking into HTML5/Canvas, as well as just plain javascript/jquery to do this.
I am here asking for suggestions on easy ways to do this.
Thanks
Here's a super simple jsfiddle with the beginnings of how I might go about doing it - let me know if you've any questions/concerns/need help making further improvements, and I'll be glad to update!
http://jsfiddle.net/jking/4dMJG/
(just prevent my divs are images, and the sidebar is a real form...)
Here is how I would do - simple, short way, I don't know how you want to extend it:
I would create an array, and bind event listener to the div you want your user to click on.
Every time the user clicks on this image, an event object is passed through, you can read out the X and Y coordinates of the mouse - .position() or .offset() depending on your layout.
Create a JSON object, which stores these values:
var hit = {
id: 1,
x: 250,
y: 365,
//add more attributes if you like/need
//for this particular 'hit'
}
And the you can store this object (-notation) in an array:
hitz.push(hit);
Now you should 'update' your UI based on this array.
Just loop through with a for...in loop and create your images:
var hockeyIceClone= $("div.hockey-ice").clone(true);
for (var i in hitz) {
var hit = hitz[i];
hockeyIceClone.append(
//assuming that your .hockey-ice div has position:relative at least
var image = $(new Image('image/path.png'));
//add more stuff for image if you like
$(image).css({
position: absolute,
left: hit.x,
top: hit.y
})
);
}
$("div.hockey-ice").replaceWith(hockeyIceClone);
The reason for cloning is because when you loop through an array and append elements to a 'container' placed out and visible on the UI, it might blink as it renders. So you better 'collect' it first, and place them out to the UI together.
Also you can use other methods than cloning, it's only an option.

Categories

Resources