vuejs: mounted issues with coordinates of elements and svg - vue.js

I have three columns, two with divs and the central one with an svg. I made a method that calculate the top() of each paragraph inside the divs to get the position and then draw an arrow in the svg. The problem is that when I use that method the first time I open my component, I get all zeroes, probably because the paragraph aren't really drawn (they have no coordinates) yet. I tried in mounted(), which should be the right place to do that. I use it also in updated() in case I reload my json with new data.
Am I missing something trivial?
The code I use to get the coordinates is like this:
drawLine(index1, index2) {
//var plist1 = this.$refs['p_list1'];
//var plist2 = this.$refs['p_list2'];
var plist1 = document.getElementsByClassName('p_list1');
var plist2 = document.getElementsByClassName('p_list2');
if (plist1.length == 0 && plist2.length == 0) return;
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'line');
//...
//const start = this.$refs['startpos'].getBoundingClientRect().top;
const start = document.getElementById('startpos').getBoundingClientRect().top;
const r1 = plist1[index1].getBoundingClientRect();
const r2 = plist2[index2].getBoundingClientRect();
index1 and index2 comes from a loop where I get which paragraph I have to connect with an arrow (also where the nextThick is)
Here is a simple example of the issue:
https://codesandbox.io/s/bootstrap-vue-test-bcozc
Note: it's badly shown, but if you press "DO" and then switch tab, you'll see that the arrow aren't correct. If you switch tab and then press DO, it will work.

Put your calculation methods in a $nextTick function to allow parents and children to fully render.
If that does not work, as a debug step, try using a setTimeout method to delay the calculation.

After understanding that the problem was linked to how tabs are built, I tried making that specific tab lazy and it worked.
<b-tab lazy ...
I don't know how tabs are normally built, but I suppose the dom is put together without having a real coordinate system and when it's made visible, I don't have any event to read to update the svg.

Related

Famo.us/Angular Sticky Background Position ScrollView Sync

I'm trying to create functionality very similar to most websites these days.
The concept is 3 sections the size of the browser, the background images are supposed to be fixed positioned and revealed by the div scrolling up and down.
We need this to function as beautifully on mobile as it does on desktop, and it looks like Famous/angular is the solution.
Here is a pen.
http://codepen.io/LAzzam2/pen/XJrwbo
I'm using famous' Scroll.sync, firing javascript that positions the background image on every start / update / end.
scrollObject.sync.on("update", function (event) {
console.log('update');
test(event);
});
here is the function positioning the backgrounds.
function test(data){
var scroller = document.getElementsByClassName('famous-group');
styles = window.getComputedStyle(scroller[0], null);
tr = styles.getPropertyValue("-webkit-transform").replace('matrix(1, 0, 0, 1, 0,','').replace(')','');
var distanceTop = -(parseInt(tr));
var sections = document.getElementsByClassName('section');
sections[3].style.backgroundPosition="50% "+distanceTop+"px";
sections[4].style.backgroundPosition="50% "+(-(window.innerHeight)+distanceTop)+"px";
sections[5].style.backgroundPosition="50% "+(-(window.innerHeight*2)+distanceTop)+"px";
};
Any input / suggestions / advice would be wonderful, really just looking for a proof of concept with these 3 background images scrolling nicely.
That jittery-ness is unfortunate, I can't tell what would be causing the issue, except maybe the order in which events are fired?
**There are known issues, only works in -webkit browsers as of now
I think your idea to use Famous is good, but probably what I would do, would be taking a different approach to the problem.
You are solving this by touching the DOM, that is exactly what both Angular and Famous are meant to avoid.
If I had to face the same goal, I would probably use a Famous surface for the background instead of changing the property of the main one and synchronize its position with the scrolling view.
So, in your code, it would be something like this:
function test(data){
var scrollViewPosition = scrollObject.getAbsolutePosition();
var newBackgroundPosition = // Calculate the new background position
var newForegroundPosition = // Calculate the new foreground position
var backgroundSurface = backgroundSurface.position.set(newBackgroundPosition);
var foregroundSurface = foregroundSurface.position.set(newForegroundPosition);
};

Is it possible to have a sticky header, scrolling to anchors all in a responsive layout?

I have a responsive layout and I am using sticky.js for my header. This seems to be working minus a few glitches that I can live with. But my anchors are always off (I am using smooth scrolling). I am not sure how to compensate for the sticky header when scrolling to an anchor when the responsive layout is constantly changing the width and height?
Unfortunately there is not a whole lot you can do with straight-CSS which won't distort your design. To tackle this issue in previous projects, I have used jQuery to handle these types of scrolling/anchor issues.
What You Have Now: <a> tags that look for id's on the page. The problem is this: when the site goes responsive, those anchor tags don't line up so nicely with your DOM layout.
My Solution: To give you the high level concept - I used jQuery to modify the ID positions on the fly. Say you click on a link when the site is full-size, and everything is fine. jQuery is not needed here. Now say that when you click that same link when the site was scaled to about the 768px-width range (iPad portrait): then my anchors might look as if they were about 100px off (for example). I wrote a bit of jQuery to handle this: "If the width is __, then offset the anchor ID's by ___px."
I would recommend using JS to account for the difference at time-of-scroll, rather than trying to artificially alter the height property of your anchor tags. Here's a function that might work for you, using pure JS:
adjustScroll = function () {
// Sticky nav selector (you'll have to provide your own selector)
const nav = document.querySelector('header>nav');
if (location.href.indexOf("#") >= 0) {
// Find the name of the anchor
let n = location.href.substr(location.href.indexOf("#")+1);
// Find the anchor by name, if it exists
let a = document.querySelector('a[name="'+n+'"]');
if (!a) {
return;
}
// Set y value as y-value of the anchor, offset by the header height
let y = a.offsetTop;
y -= nav.height + 10;
// Scroll to the y position
window.scrollTo(0, y);
}
}
// Call it wherever you need to call it
adjustScroll();
Examples of where to call it might be on a DOMContentLoaded event, or on an onclick event for anchor tags.

Need to scroll from clicked div to top of browser window. Not to top of document, using Isotope Jquery

Please take a look at my jsFiddle here
I am using jQuery Isotope plugin and I am having troubles using their itemPositionDataEnabled to be able to scroll from my clicked item to the top of whats currently visible in the browsers window.
With itemPositionDataEnabled I should be able to extract the x and y position of what ever item I'm requesting. However mine does nothing at all....
var $this = $(this),
scrollTop = $(window).scrollTop(),
itemPosition = $this.data('isotope-item-position'),
itemPositionY = $this.itemPosition.y,
distance = (itemPositionY - scrollTop);
$('html, body').stop().animate({
scrollTop: distance
}, 1000);
You have a plain and simple error in these two lines:
itemPosition = $this.data('isotope-item-position'),
itemPositionY = $this.itemPosition.y;
The second line should be:
itemPositionY = itemPosition.y;
Not sure if you're all the way there since it only seems to work on the way you want on the first click.
http://jsfiddle.net/EA8tM/90/

Reload carousel items

I need to reload the items from my carousel (I clicked on an item and a panel gets destroyed, then when I try to go back, I need to rebuild the carousel)
For this I am removing the items of the carousel by doing:
var len = cards.length;
for(var c = 0; c < len;c++)
this.myCarousel[0].items.remove(cards[0]);
then I set the cards again and set the carousel items again:
this.myCarousel[0].items.append(cards);
this.doLayout();
but after doing this, the cards dont get set right, they just get written on top of each other, no carousel effect gets done. Also the cards start being drawn under the carousel's toolbar, instead of starting below the toolbar.
The first time when I load the cards it works perfectly (when I build the carousel from scratch), but if I delete the previous cards and add them again, they don't get displayed properly, I hope someone can help me.
Thank you in advance
Do the adding and removing on the carousel itself as it has methods to do this:
this.myCarousel.removeAll();
var items = [];
for (...) {
items.push(<item def>);
}
this.myCarousel.add(items);
this.carousel.doLayout(); // Force the carousel to re-render
this.myCarousel.scrollToCard(0); // This will send the user back to the first card
If the user was at a different card when you run the above (say, if you put this into an orientation check) then you should return them to the correct card like so:
var curIndex = this.myCarousel.items.items.indexOf(this.myCarousel.layout.activeItem);
// Now do removing and adding
this.myCarousel.scrollToCard(this.myCarousel.items.items[curIndex]);
You have to use the index as the item will be removed.
id should only be used for debugging. There are better ways to resolve a component than use id that can get you into trouble.

How can I group functions together

I have created an image map with flash, I have separate button functions that display rollover and onpress functions for each region ie -
nw_btn.onRollOver = function() {
areaName_txt.text = "This Site (NWPHO)";
}
nw_btn.onPress = function() {
displayOverlay(areaName_txt.text);
}
This is repeated 15 times to cover each area button - I wondered whether there was a way to apply the same function call (displayOverlay) and apply area name text on rollover via one piece of code rather than repeating for each button?
I guess there must be a mistake with your tag, because what you describe look more like an AS2 structure.
But if you really are in AS3, here is what you can do : connect everything to a same function with addEventListener. In this function, test which button is at the source of the event, then put the code to be executed for each button.