Been bashing my head over this for a while. The project I'm working on requires that I display two randomly selected videos from a list of four possible, unique animations, and on the next page, display the correct corresponding textual description for the video selected. Right now, the approach I'm taking is creating a separate list.js file apart from my code, with each video grouped with its corresponding sentence, but as my code is right now, I cannot use the randomization function to randomize all objects at once.
the list.js file.
//two randomly selected animations are shown here as samples
var stims = jsPsych.randomization.factorial(list.js)
for (const i of stims) {
var video = "video/" + i[video] + ".mp4"
var description = {
type: "html-keyboard-response",
stimulus: [
i["sentence"] +
"<p> Press spacebar to proceed to the next sample animation </p>"
],
choices: [' ']
}
var experience = {
timeline:
[
{
type: 'video',
width: 600,
data: {
subject: code,
},
sources: [video]
}
]
}
timeline.push(fixation);
timeline.push(experience);
timeline.push(description);
}
above is the pertinent code in my experiment.
Related
I'm having a little issue using ngx-gallery Here is the github page and my stackblitz example.
Scenario - I want my user click a button to swap the images around to the first image in the gallery.
Ex. User clicks button and moves the image from position 3 to image position 1. Including the small thumbnail, the medium image (main viewer) and the big preview image.
Problem - Everything I've tried doesn't seem to work. I can't really find any methods that swap the indexes and when I swap them manually nothing happens.
FYI - I can add and delete images to the viewer with push and pop, I just can't set (swap) the first image programmatically with another.
stackblitz example
Here is some of the examples I've tried.
export class AppComponent implements OnInit {
#ViewChild('gallery') gallery: NgxGalleryComponent;
galleryOptions: NgxGalleryOptions[];
galleryImages: NgxGalleryImage[];
constructor() {}
ngOnInit() {
this.galleryOptions = [{
width: '600px',
height: '400px',
thumbnailsColumns: 4,
arrowPrevIcon: 'fa fa-chevron-left',
arrowNextIcon: 'fa fa-chevron-right',
imageAnimation: NgxGalleryAnimation.Slide
}
];
this.galleryImages = [{
small: 'https://preview.ibb.co/jrsA6R/img12.jpg',
medium: 'https://preview.ibb.co/jrsA6R/img12.jpg',
big: 'https://preview.ibb.co/jrsA6R/img12.jpg'
},
{
small: 'https://preview.ibb.co/kPE1D6/clouds.jpg',
medium: 'https://preview.ibb.co/kPE1D6/clouds.jpg',
big: 'https://preview.ibb.co/kPE1D6/clouds.jpg'
},
{
small: 'https://preview.ibb.co/mwsA6R/img7.jpg',
medium: 'https://preview.ibb.co/mwsA6R/img7.jpg',
big: 'https://preview.ibb.co/mwsA6R/img7.jpg'
}, {
small: 'https://preview.ibb.co/kZGsLm/img8.jpg',
medium: 'https://preview.ibb.co/kZGsLm/img8.jpg',
big: 'https://preview.ibb.co/kZGsLm/img8.jpg'
},
];
}
swap() {
console.log("button clicked!");
// doesn't do anything
[this.galleryImages[2], this.galleryImages[0]] = [this.galleryImages[0], this.galleryImages[2]];
// doesn't do anything
[this.gallery.thumbnails.images[2], this.gallery.thumbnails.images[0]] = [this.gallery.thumbnails.images[0], this.gallery.thumbnails.images[2]];
// doesn't do anything
[this.gallery.images[2], this.gallery.images[0]] = [this.gallery.images[0], this.gallery.images[2]];
}
}
<div class="gallery-wrapper">
<ngx-gallery #gallery [options]="galleryOptions" [images]="galleryImages" class="ngx-gallery"></ngx-gallery>
</div>
<button (click)="swap()">swap image 1 and 3</button>
This may be because you are mutating the array. Sometimes Angular change detection only kicks in when you do not mutate.
Mutating happens when you change the array (the items in the array or the order of items in the array) but do not change the array reference.
To avoid mutating try:
this.galleryImages = [this.galleryImages[2], this.galleryImages[1], this.galleryImages[0]]
Alternatively, even when you do mutate an Array you can solve the problem by running lodash cloneDeep afterwards, which will get you a new reference after mutating:
import { cloneDeep } from 'lodash-es'
// your existing code
this.galleryImages = cloneDeep(this.galleryImages)
Note that there are some decent npm packages for changing the position of items in an array such as array-move - this avoids mutation - note there are other good packages for this too, look for competitors on npm trends
I'd like to know whether it's possible to play three audio files one after the other and having a participant clicking on a button (perhaps a speech bubble) indicating the audio file he wants to select. Everything while an image is displayed constantly at the bottom (or top I really don't care about that).
IMPORTANT: I'd like each audio + speech bubble to appear together one at a time and stay on the monitor until the last sound has been played.
I have a drawing of what I mean:
A plus is to make it possible with some jsPsych plugin!
Please help me guys!
UPDATE, problem solved !
The main idea is to give up on the for loop, or providing a whole vector ideas and specify each audio as an independent trial, and concatenate the trials into a bigger "task".
The solution came from the main JsPsych group.
experiment: [];
var trial1 = {
type: 'audio-button-response',
stimulus: 'audio1.mp3',
choices: ['img/speech.png', 'img/speech.png', 'img/speech.png'],
trial_ends_after_audio: true,
prompt: "<img src='stimImage.jpg'>"
};
var trial2 = {
type: 'audio-button-response',
stimulus: 'audio2.mp3',
choices: ['img/speech.png', 'img/speech.png', 'img/speech.png'],
trial_ends_after_audio: true,
prompt: "<img src='stimImage.jpg'>"
};
var trial3 = {
type: 'audio-button-response',
stimulus: 'audio3.mp3',
choices: ['img/speech.png', 'img/speech.png', 'img/speech.png'],
response_ends_trial: true,
prompt: "<img src='stimImage.jpg'>",
on_finish: function(data) {
jsPsych.data.addDataToLastTrial({
key_press: data.choices
});
},
};
var fixation_trial = {
type: 'html-keyboard-response',
stimulus: '<div style="font-size:60px;">+</div>',
choices: [69],
trial_duration: 1000,
data: {
test_part: 'fixation cross'
},
on_finish: function(data) {
if (data.key_press == 69) { //press letter 'e' to skip this part
jsPsych.endCurrentTimeline();
}
}
};
var task = {
timeline: [fixation_trial, trial1, trial2, trial3]
};
experiment.push(task);
jsPsych.init({
timeline: experiment,
})
Although the examples of jsPsych about audio are not abundant, I did manage to find this example which loops images until a button is pushed and implemented the same logic to your audio files.
I'm not sure if the speech bubbles will appear at the correct moment, but altering the object in the audio_trials.push() method to include each image with each audio file, might solve it.
var audio = ['dep.mp3', 'dep.mp3', 'dep.mp3'];
var audio_trials = [];
for (let i = 0; i < audio.length; i++) {
audio_trials.push({
stimulus: audio[i]
});
}
var audio_trial = {
type: 'audio-button-response',
choices: ['img/speech.png', 'img/speech.png', 'img/speech.png'],
prompt: "<p>Click on the correct speech bubble</p>",
button_html: '<img src="%choice%" style="width: 300px"/>',
on_finish: function(data) {
jsPsych.data.addDataToLastTrial({
key_press: data.choices
});
},
timeline: audio_trials
};
var fixation_trial = {
type: 'html-keyboard-response',
stimulus: '<div style="font-size:60px;">+</div>',
choices: [69],
trial_duration: 1000, // here there is the random variation
data: {
test_part: 'fixation cross'
},
on_finish: function(data) {
if (data.key_press == 69) { //press letter 'e' to skip this part
jsPsych.endCurrentTimeline();
}
}
};
jsPsych.init({
timeline: [fixation_trial, audio_trial],
use_webaudio: true
});
I currently have a giant table of "auditpoints", some of those points are "automated". If they are automated they receive a gear icon in their row. The gear icon is not the only icon each row receives. Each row, no matter if it's automated or not receives two other icons, a pencil and a toggle button. When an automated point "runs" the gear icon rotates until it is finished "running". I've have implemented some code to ran all of these points at once but I have a small problem. When you click my button to run all these points all three of the icons I have mentioned rotate and this is not the result I am looking for. The line commented out in my code snippet (and it's matching bracket) will prevent the code from running all of the automated points. Commenting out the line is what causes all the icons to rotate. I know this line is required to get the automated points to run properly as it used in the single execution of automated points I just don't know what to change it to. It obviously shouldn't be click because you are no longer clicking the gear icon to get a point to run I just don't know what to change it to but the classes in that click function are related to the gear icon.
Hopefully this is a very easy question to solve and doesn't waste anyone's time. Thank you!
private updateAuto() {
var self = this;
$(".auditPointRow").each(function () {
//self.el.on("click", ".update, .edit", function () {
var row = $(this).closest(".auditPointRow");
var id = row.data("id");
var automated = (<string>row.data("automated")).toLowerCase() == "true";
var running = true;
if (automated && $(this).closest(".edit").length == 0) {
var gear = $(this).find(".fa");
var maxTurns = 120;
gear.css("transition", "transform linear " + maxTurns * 2 + "s");
gear.css("transform", "rotate(" + (maxTurns * 360) + "deg)");
var request = $.ajax(self.root + "api/sites/" + self.site.ID + "/auditpoints/" + id, {
"type": "PATCH", data: JSON.stringify([
{
Op: "Replace"
, Path: "/score"
, Value: "run"
}
])
});
request.done(function () {
gear.css("transition", "").css("transform", "rotate(0deg)");
row.prev().find("td").css("background-color", "");
if (row.prev().qtip("api")) {
row.prev().qtip("api").destroy(true);
}
});
}
//}
});
}
I think I found a solution to my problem. I used .each again to go through all of the "gears" and only rotate them.
private updateAuto() {
var self = this;
//$(".auditPointRow").each(function () {
$(".update, .edit").each(function () {
//Left out the rest of the code so this answer isn't too
//long, none of it changed if that matters.
});
//});
}
For some reason the result runs very slowly (but it runs!) and I'm not sure why so if anyone has any better suggestion/optimizations please feel free to leave those here.
Edit: I realized I didn't to go through .each twice, that's what was slowing to down so I removed that first each that went over auditPoints and just did the ones with gears instead.
Going back to the previous thumbnail overview results in flickering. Looking at it in slow motion the build up of the thumbnail page becomes visible. If the images are loaded fast, the problem disappears, but is very visible if the connection is slow. Is there a way keep the thumbnail page in cache or render the page after flexbox places all the elements? Or is there any other solution? Thanks!
Slow motion:
https://www.youtube.com/watch?v=x3vvCRIJdRo
All images are small sprites that are then drawn to canvases btw. I'm also using flexbox.
Website: http://eboydb.mod.bz/pool/all/1 (will remove this link – if fixed)
Edit:
Just tried to use waitOn with Iron Router – as suggested below. It doesn't seem to make a difference though.
Router.route('/pool/:slug/:page', {
name: 'pool',
template: 'pool',
after: function() {
document.title = siteName + ' /pool/' + this.params.slug + '/' + this.params.page;
},
waitOn: function() {
// set search slugs that will show everything
var allOptions = [
"all",
"everything",
"show all",
];
// when the slug is part of the array show everything
if (allOptions.indexOf(this.params.slug.toLowerCase()) > -1) {
var searchTerm = ".*";
// console.log('slug: all > ' + this.params.slug);
} else {
var searchTerm = this.params.slug;
}
Meteor.subscribe('PixQuery', searchTerm, this.params.page);
},
data: function() {
templateData = {
slug: this.params.slug,
}
return templateData;
}
});
I'm running a prototype script (lightbox) and I want to add an extra link below each image with the url to a page that changes with each image.
I have so far managed to add the a element to the right place, but later in the script I need to update the href of the link based on the image that is loaded.
There's a point in the script where the image is inserted into the lightbox after loading/navigating the lightbox:
showImage: function(){
this.loading.hide();
new Effect.Appear(this.lightboxImage, {
duration: this.resizeDuration,
queue: 'end',
afterFinish: (function(){ this.updateDetails(); }).bind(this)
});
this.preloadNeighborImages();
},
After it's finished it runs updateDetails, which includes the images' caption. This seemed to me the perfect place to also update the link:
updateDetails: function() {
// if caption is not null
if (this.imageArray[this.activeImage][1] != ""){
this.caption.update(this.imageArray[this.activeImage][1]).show();
}
// if image is part of set display 'Image x of x'
if (this.imageArray.length > 1){
this.numberDisplay.update( LightboxOptions.labelImage + ' ' + (this.activeImage + 1) + ' ' + LightboxOptions.labelOf + ' ' + this.imageArray.length).show();
}
/** slider effect cut from example code for the sake of brevity **/
}
I've tried many variations based on the codes used in these functions, but nothing seems to work. How do I update the href of a link with id=toFilePage?
I figured it'd be something like
this.toFilePage.href.update('http://example.com');
But that doesnt seem to work..
I believe the problem may lie within this section (starting at line 175 in lightbox.js)
(function() {
var ids = 'overlay lightbox outerImageContainer imageContainer lightboxImage hoverNav prevLink nextLink loading loadingLink ' + 'imageDataContainer imageData imageDetails caption numberDisplay bottomNav bottomNavClose';
$w(ids).each(function(id) {
th[id] = $(id);
});
}).defer();
This creates references to the objects created in the Builder section above it. Simply adding your id to that list should do the trick.
Otherwise you may also access it through $("myIdHere").