GSAP + Vue using props to calculate a maxWidth - javascript

I am trying to animate buttons in my application using GSAP. User clicks button and animates the maxWidth of the button. I'd like to have this dynamic and add a percentage of the max width that is set using props. is it possible to pass the prop maxwidth to the gsap timeline? as of now it does not work for me.
props: {
maxWidth: {
type: String,
required: true,
},
},
methods: {
buttonTo(path) {
let tl = this.$gsap.timeline({
onComplete: function () {
pushToPath();
},
});
tl.to(this.$refs.primaryButton, {
duration: 0.6,
ease: 'power2.in',
maxWidth: `calc(${this.maxWidth} + 5%)`,
});
const pushToPath = () => {
this.$router.push({ path: path });
};
},
},

I've run into a similar issue before. The nice thing is that it has nothing to do with the Vue Lifecycle, so the value is available within methods.
There are a couple of things that could be causing this issue. I'd start by making sure your prop, "maxWidth," has "px" or some form of CSS measurement tied to it. CSS calc can't have a plain number within the CSS "calc" function.
Here is an example using your function:
props: {
maxWidth: {
type: String,
required: true,
},
},
methods: {
buttonTo(path) {
let tl = this.$gsap.timeline({
onComplete: function () {
pushToPath();
},
});
tl.to(this.$refs.primaryButton, {
duration: 0.6,
ease: 'power2.in',
maxWidth: `calc(${this.maxWidth}px + 5%)`,
});
const pushToPath = () => {
this.$router.push({ path: path });
};
},
},
You could also switch your prop to be of the type "Number" in case, for some reason, the string is causing issues within the timeline.
If this helps, please let me know!

Related

How to load visual into entire div using Power Bi embed report

I am embedding a Power BI report with a single page and single view in to my application using javascript.The visual is creating and loading fine but it is occupying in a particular portion of the parent div in which i am embedding my report.I need to stretch that visual into full width and height of the parent div.I tried this but it is not working for me.
Here is my current output
Here my visual is fit in to the centre of my parent div but i need to stretch that visual to cover all remaining red portion of my parent div
Here is my code
let visualConfig = {
type: 'report',
tokenType: models.TokenType.Aad,
accessToken: loggedInUser.accessToken,
embedUrl: globalData.embedUrl,
id: globalData.id,
viewMode: models.ViewMode.View,
permissions: models.Permissions.ReadWrite,
datasetBinding: {
datasetId: CurrentDataset
},
settings: {
//layoutType: models.LayoutType.Custom,
//customLayout: {
// pageSize: {
// type: models.PageSizeType.Custom,
// width: $("#idViewPreview").width(),
// height: 300
// },
// displayOption: models.DisplayOption.FitToPage
//},
panes: {
filters: {
visible: false
},
pageNavigation: {
visible: false
},
},
background: models.BackgroundType.Transparent,
visualSettings: {
visualHeaders: [
{
settings: {
visible: false
}
}
]
}
}
};
currentVisual.report = powerbi.embed($("#idViewPreview")[0], visualConfig);
//required for untag load event
currentVisual.report.off("loaded");
// Triggers when a report schema is successfully loaded
currentVisual.report.on("loaded", async function () {
try {
var newPage = await currentVisual.report.addPage("test_display");
currentVisual.page = newPage;
currentVisual.page.setActive();
let models = window['powerbi-client'].models;
const customLayout = {
x: 0,
y: 0,
width: 1000,
height: 800,
displayState: {
// Change the selected visuals display mode to visible
mode: models.VisualContainerDisplayMode.Visible
}
};
currentVisual.visuals = await currentVisual.page.createVisual("funnel", customLayout);
}
catch (ex) {
console.log(ex);
}
When we change the page size, the report will be fixed rather than contracted or expanded. If we make the page width smaller than the report width, the visual report will be contracted. However, when we change the div size, the iframe resizes the report automatically. If you want to customise the height and width of your visual, you can do so.
Set custom height and width of your visual.
defaultLayout: defaultLayout,
visualsLayout: {
"Required_Visual_Name": {
x: "Required_Width",
y: "Required_Height",
displayState: {
mode: models.VisualContainerDisplayMode.Visible
}
},
}
};
2.Now Update the settings
layoutType: models.LayoutType.Custom,
customLayout: {
displayOption: models.DisplayOption.FitToPage,
pagesLayout: {
"Your_Report_Id": pageLayout
}
},
}
3.Apply the settings
await report.updateSettings(settings);
References:
https://learn.microsoft.com/javascript/api/overview/powerbi/custom-layout
I just made some changes in the actual answer and i am posting it here. After embedding the report before creating a visual i am updating the page layout.
let divWidth = $("div").width() - 10;
let divHeight = $("div").height() - 10;
let settings = {
layoutType: models.LayoutType.Custom,
customLayout: {
pageSize: {
type: models.PageSizeType.Custom,
width: divWidth,
height: divHeight
},
displayOption: models.DisplayOption.FitToPage
}
};
await embedReport.report.updateSettings(settings);
const customLayout = {
x: 0,
y: 0,
width: divWidth,
height: divHeight,
displayState: {
// Change the selected visuals display mode to visible
mode: models.VisualContainerDisplayMode.Visible
}
};
await embedReport.page.createVisual("column", customLayout);

Scheduling ToneJS events while transport is playing

I have 4 notes playing in my Tone JS app and would like to change the 3rd note to be something else whilst the transport is currently playing. Here is my code:
JS:
import { Transport, start, Sampler } from "tone";
const notesToPlay = [
{
timing: 0.25,
sameAsLast: false,
duration: 0.1,
velocity: 1
},
{
timing: 0.5,
sameAsLast: true,
duration: 0.1,
velocity: 1
},
{
timing: 0.75,
sameAsLast: false,
duration: 0.1,
velocity: 1
},
{
timing: 1,
sameAsLast: false,
duration: 0.2,
velocity: 1
}
];
var eventIds = [];
(function () {
function playSynth() {
Transport.start();
start();
}
const sampler = new Sampler({
urls: {
A1: "A1.mp3",
A2: "A2.mp3"
},
baseUrl: "https://tonejs.github.io/audio/casio/",
onload: () => {
loadNotes();
}
}).toDestination();
function loadNotes() {
notesToPlay.forEach((n) => {
const eventId = Transport.scheduleRepeat((time) => {
sampler.triggerAttackRelease(
["A1"],
n.duration,
n.timing + time,
n.velocity
);
}, 4);
eventIds.push(eventId);
});
}
document.getElementById("play").addEventListener("click", function () {
playSynth();
});
document.getElementById("stop").addEventListener("click", function () {
Transport.stop();
});
document.getElementById("replace").addEventListener("click", function () {
const arrayIdxToReplace = 2;
Transport.clear(eventIds[arrayIdxToReplace]);
const note = notesToPlay[arrayIdxToReplace];
Transport.scheduleRepeat((time) => {
sampler.triggerAttackRelease(
["D1"],
note.duration,
note.timing + time,
note.velocity
);
}, 4);
});
})();
HTML:
<div id="app">
<button id="play">play me</button>
<button id="stop">stop</button>
<button id="replace">Replace 3rd note</button>
</div>
When I click the replace 3rd note button it removes the old event which is good but when it schedules the new event in it is out of sync with where the old 3rd note would be.
A way to get around this is by stopping the Transport then clicking to replace the 3rd note and then clicking play again however I want to be able to do this while the Transport is still playing. Where have I gone Wrong?
Here is a fiddle to demo the issue:
https://codesandbox.io/s/tonejs-forked-fxhzm?file=/src/index.js:0-1643
This is pretty awkward to fix the way it is structured now. The trouble is that every note you add is on its own loop, which begins whenever you call scheduleRepeat ... you would have to correct for the offset between the original loop and the new one, which seems kind of tricky.
I'd suggest that you have call scheduleRepeat only once, and have the callback read the list of notes you have stored. That way you can just replace or alter one of those notes and the next time around it'll be changed, and you won't have any timing problems. I think that would mean including the pitch in your note schema.

Rails vuejs get height of iframe element

I am using vuejs with rails webpacker and turbolinks. I want to calculate the correct height of the iframe element on the initial page load. Currently, I am getting the height of the element when I manually refresh the page, and when someone navigates from any other pages to the page where the iframe element is located, the height of the element is not calculated.
My index.js setup:
Vue.use(TurbolinksAdapter);
document.addEventListener('turbolinks:load', () => {
const app = new Vue({
el: '[data-behaviour="vue"]',
});
});
My preview.vue where the iframe element is located.
data() {
return {
frameHeight: '',
};
},
computed: {
computeHeight() {
this.frameHeight =
this.$refs.iframe.contentWindow.document.body.scrollHeight + 'px';
},
},
mounted() {
window.addEventListener('load', () => {
this.computeHeight;
});
},
I have tried replacing the mounted hook with the created hook as well, and instead of listening for the load event I have tried listening for the turbolinks:load event as well. But it doesn't work.
Any help would be appreciated. Thanks.
Try wrapping the compute height code in nextTick like so:
data() {
return {
frameHeight: '',
};
},
mounted() {
this.$nextTick(() => {
window.addEventListener('load', () => {
this.frameHeight =
this.$refs.iframe.contentWindow.document.body.scrollHeight + 'px';
});
})
},
This should allow the elements to load before executing the code to grab height.
You won't need the eventListener when using nextTick. You can just do it like:
data() {
return {
frameHeight: '',
};
},
mounted() {
this.$nextTick(() => {
this.frameHeight =
this.$refs.iframe.contentWindow.document.body.scrollHeight + 'px';
});
},

Is it possible to call the tippy (js) constructor only on the newest added popover?

after I created the popovers I am calling the tippy() constructor like:
tippy('.my-tippy-popover', { ... }); But this is creating all existing tippy popovers again. So if you have 80 popovers and you add a new one, then the tippy() constructor is creating 81 new popovers. And if you click one of the popovers you get 2x the event e.g. onShow. If you add now again a new popover and run tippy() constructor and click after that a popover, you get 3x onShow event. And so on. So it's adding more and more event listeners.
How can I avoid that?
Edit jsfiddle
jQuery(($) => {
runTippy()
})
function runTippy() {
tippy('.my-tippy-popover', {
content(reference) {
const id = reference.getAttribute('data-template');
const template = document.getElementById(id);
return template.innerHTML;
},
onHide(instance) {
console.log('+++ tippy onHide +++')
},
onCreate(instance) {
console.log('+++ tippy onCreate +++')
},
onShow(instance) {
console.log('+++ tippy onShow +++')
},
onShown(instance) {
console.log('+++ tippy onShown +++')
},
allowHTML: true,
trigger: 'click',
appendTo: document.getElementById('tippy-container'),
interactive: true,
interactiveBorder: 10,
interactiveDebounce: 35,
maxWidth: 'none',
});
}
function addPopover() {
const body = $('body');
body.append(`<span class="my-tippy-popover" data-template="tippyContent" >Popover</span><br>`);
runTippy()
}

How to get the current slide no in Glide.js

Hi how can I get the current slide no when I click next and previous button in GLide.js http://glide.jedrzejchalubek.com/docs.html#intro.
var carousel = $('#Carousel').glide({
type: 'carousel',
startAt: 1,
touchDistance: 2,
afterInit:function(){console.log("paintSlider")},
autoplay: 0
});
console.log(carousel.current());
For some reason, the function carousel.current() is not working.
You can use the code's callback and events instead.
Example:
var carousel = $('#Carousel').glide({
type: 'carousel',
...
afterTransition : function(event) {
console.log(event.index); // the current slide number
}
});
Also, carousel.index() works too!
const glide = new Glide('.glide');
glide.on(['mount.after', 'run'], () => {
const currentIndex = glide.index;
console.log(currentIndex)
});
glide.mount();
Not sure why, but documentation about accessing API is missing. I'll fix that.
You need to access api via .data('glide_api'), before making api calls.
var carousel = $('#Carousel').glide({
type: 'carousel',
startAt: 1,
touchDistance: 2,
afterInit:function(){console.log("paintSlider")},
autoplay: 0
}).data('glide_api');
console.log(carousel.current());
Thanks for using plugin!
It works for me:
jQuery(document).ready(function(){
var glide = jQuery('.slider').glide({
afterTransition : function() {
console.log(glide.current());
}
}).data('api_glide'); // data('api_glide') to get opportunity to use glide.current()
});
You can access the property index on your glide instance.
For example:
import Glide, { Controls } from '#glidejs/glide/dist/glide.modular.esm';
var glider = new Glide( el, options );
glider.mount( {
Controls,
} );
// You can get the current index using glider.index;
console.log( glider.index );
Glibert answer works
var stGlide = new Glide(`.heroglide-${article.id}`, {
type: 'carousel',
animationDuration: 500,
startAt: 1,
perView: 1,
peek: {
before: 50,
after: 50
},
// afterTransition : function(event) {
// console.log("========transition",event.index); // the current slide number
// }
});
try{
stGlide.on(['mount.after', 'run'], () => {
const currentIndex = stGlide.index;
console.log("====>index==>",currentIndex)
});
stGlide.mount();
}
const glide = new Glide('.glide');
glide.on("run", () => {
console.log(slider.index);
});

Categories