I have a website for CVOID-19 that displays cases on a MapBox map. One of the buttons on the website hides the case info so you get the the full map. The width transition of the case info box works nicely, but it leaves the map un-resized. Thankfully there is a method conveniently named map.resize() that resizes the map into it's appropriate size after the width of the case info box goes down to zero using a transitionend event. However the resizing isn't transitioned at all and it ends up looking incredibly janky with the sudden resizing of the map out of no where.
This is the solution I came up with, on the start of the transition you call the map.resize() function every 10 ms, and then you stop the interval once the transition has ended, it ends up looking quite a bit smoother.
let mapResizer;
countryPanel.addEventListener("transitionstart", (e) => {
if (e.target == countryPanel) {
mapResizer = setInterval(map.resize, 10);
}
})
countryPanel.addEventListener("transitionend", (e) => {
if (e.target == countryPanel) {
if (e.target.classList.contains("hide")) {
showBtn.hidden = false;
}
clearInterval(mapResizer);
}
})
Here is the website displaying the effect when you click the hide UI button (the little arrow pointing to the left): https://people.rit.edu/ajr6974/330/Project%203/
Related
I have explored few approaches to this, but none really seems to work exactly like I would like:
I would like that when scrolling down, navbar is moving up at the speed the user is scrolling down, like that is static at that point.
When it disappears, I would like that the bottom of it is still visible, because this is where I have a progress bar (but maybe progress bar should detach at that point and be on top of the viewport).
When you scroll up, I would like that navbar appears again, again at the speed of scrolling, like it is static, until you see the whole navbar, when it should stick to the top of the viewport.
Here is an example of behavior I would like, but not performance/experience (because behavior is implemented using scroll event, it is not smooth).
I have also attempted to use CSS transform, which would on scroll down add a class to hide the navbar, and scroll up remove the class, animating the navbar hiding/showing, but the issue with that is that animation speed is disconnected with scrolling speed.
I tried CSS sticky position as well, but it looks like I need the opposite of what it provides.
Is there some other way to make this work well?
I've looked at your problem and I think i found a simple approach.
with this simple function you can get the amount of pixels user has scrolled.
window.onscroll = function (e) {
console.log(window.scrollY); // Value of scroll Y in px
};
after user scrolls the desired amount of pixels, make the progress bar fixed top ( or position:fixed;top:0)
Checking the link you provided, it seems to work as expected (you want it to be linked to the scroll event since you want it to move as "static"). If, though, it staggers on some system due to inconsistent scroll events, you could try adding a transition property with a small enough duration. Keep in mind the this should only be enabled while the position property remains the same, otherwise when changing from "absolute" to "fixed" it would mess things up, since the coordinate origin changes.
So you can add another variable let changedPosition = false; and whenever you change the position property you can do
if (position !== "absolute") {
changedPosition = true;
} else {
changedPosition = false;
}
position = "absolute";
or
if (position !== "fixed") {
changedPosition = true;
} else {
changedPosition = false;
}
position = "fixed";
and when you apply the style do
navbar.style = `position: ${position}; top: ${navbarTop}px; transitiona: ${
changedPosition ? "none" : "100ms linear"
}`;
like https://codepen.io/gpetrioli/pen/XWVKxNG?editors=0010
You should play around a bit with the transition properties you provide, i just put some sample values there.
Some answers of our chatbot are very long. The webchat scrolls automatically to the bottom so users have to scroll up to get to the top of the bubble and start reading.
I've implemented a custom renderer (react) to wrap the answers into a custom component which simply wraps the answer into a div-tag. I also implemented a simple piece of code to scroll to the top of the bubble.
const MyCustomActivityContainer = ({ children }) => {
const triggerScrollTo = () => {
if (scrollRef && scrollRef.current) {
(scrollRef.current as any).scrollIntoView({
behavior: 'smooth',
block: 'start',
})
}
}
const scrollRef: React.RefObject<HTMLDivElement> = React.createRef()
return (
<div ref={ scrollRef } onClick={ triggerScrollTo }>
{ children }
</div>
)
}
export const activityMiddleware = () => next => card => {
if (/* some conditions */) {
return (
<MyCustomActivityContainer>
{ next(card) }
</MyCustomActivityContainer>
);
} else {
return (
{ next(card) }
)
}
};
But this only works if the scrollbar slider is not at its lowest position (there is at least 1 pixel left to scroll down, see here). The problem is the useScrollToBottom hook which always scrolls to bottom automatically if the scrollbar is completely scrolled down.
Is there any way to overwrite the scroll behavior or to temporarily disable the scrollToBottom feature?
As there is no reproducible example I can only guess.
And I'll have to make some guesses on the question too.
Because it's not clear what exactly in not working:
Do you mean that click on the <div> of MyCustomActivityContainer and subsequent call to triggerScrollTo doesn't result into a scroll?
That would be strange, but who knows. In this case I doubt anyone will help you without reproducible example.
Or do you mean that you can scroll the message into view, but if it is already in the view then new messages can result into a scroll while user is still reading a message.
That's so, but it contradicts with you statement that your messages are very long, because that would be the problem with short messages, not with the long ones.
But anyway, you should be able to fix that.
If it works fine with 1 pixel off the lowest position, then just scroll that 1 pixel. You'll need to find the scrollable element. And do scrollable_element.scrollTop -= 1. I tested this approach here. And it worked (there the scrollable element is the grandparent of <p>'s)
Or do you try to scroll automatically at the moment the message arrives? Аnd that is the real issue, but you forgot to mention it, and didn't posted the code that tries to auto-scroll?
In that case you can try to use setTimeout() and defer the scroll by, let's say, 200ms.
This number in based on what I gathered from the source:
BotFramework-WebChat uses react-scroll-to-bottom
In react-scroll-to-bottom there are some timeouts 100ms and 34ms
BotFramework-WebChat doesn't redefine them
There are some heuristics in react-scroll-to-bottom that probably coursing the trouble
https://github.com/compulim/react-scroll-to-bottom/blob/3eb21bc469ee5f5095a431ac584be29a0d2da950/packages/component/src/ScrollToBottom/Composer.js
Currently, there are no reliable way to check if the "scroll" event is trigger due to user gesture, programmatic scrolling, or Chrome-synthesized "scroll" event to compensate size change. Thus, we use our best-effort to guess if it is triggered by user gesture, and disable sticky if it is heading towards the start direction.
And
https://github.com/compulim/react-scroll-to-bottom/blob/f19b14d6db63dcb07ffa45b4433e72284a9d53b6/packages/component/src/ScrollToBottom/Composer.js#L91
For what we observed, #1 is fired about 20ms before #2. There is a chance that this stickyCheckTimeout is being scheduled between 1 and 2. That means, if we just look at #1 to decide if we should scroll, we will always scroll, in oppose to the user's intention.
That's why I think you should use setTimeout()
Since there isn't a reproducible code for me tweak and show you. My suggestion is tweak your code slightly. Chatbot requires constant streaming of data when a new message arrives calculate the height of the div element created for the message. If the div element is greater than the widget height scroll to the top else you can choose to leave it as it is.
I have a problem with pausing the story.
below are some points:
without clicking for next story pause works fine
when next story is clicked the story will jump to the next story with is code window.location.href = '#'+storyId;
after next story clicked the problem with pause occurs
pause can be triggred with space bar or right click (contextmenu)
for pause these functions are called in this fashion:
toggleAnimation()
pauseAnimation(); in this function this code editor.postMessage( {'request':command.pause}, getDomain() ); triggers listener();
listener() with command command.pause this comes into this switch block
case command.pause :
requestAnimationFrame(localPauseAnimation);
play=false;
syncPrompters();
break;
localPauseAnimation();
below code is responsible for animation (inside animation()):
styleSheet.insertRule('\
.prompt.move {\
transform: translateY('+destination+'px) scale('+(flipH?-1:1)+','+(flipV?-1:1)+') !important;\
transition: transform '+time+'ms '+curve+';\
}', 0);
I'm working with this open source project https://imaginarysense.github.io/Teleprompter-Core/ it is very difficult for me to crack this code
steps to reproduce:
extract downloaded folder(https://www.dropbox.com/s/e7c2d4fynwl1d6a/Teleprompter-Core-master.tar.gz?dl=0) find index.html run into browser
click on Prompt It on the top right corner
(wait for 10sec) stories will come slides into window, press space bar it will stop correctly
when next stores (red color) button is pressed then press space bar for pause stories will jump now on the subsequent press of space bar
whole code for animation can be found in js/teleprompter.js
whole code for animation can be found in js/teleprompter.js
Question: pause and play should work as normal, without any jump
project link: https://www.dropbox.com/s/e7c2d4fynwl1d6a/Teleprompter-Core-master.tar.gz?dl=0
Play and pause animation depends on cursor position. Current cursor potion value is calculated by top position of div with class name "prompt move". I think problem with top position value of prompt div. The top value of prompt div change when you call window.location.href = '#'+storyId;. So current cursor position will be changed.
Following function is responsible to calculate cursor position.
function getCurrPos(obj) {
// There's more than a way to calculate the current position.
// This is the original method, slower and more reliable. Used only for Intergalactic Style, where the other method fails.
if (promptStyleOption===4) {
if (!obj)
obj=prompt;
var computedStyle = window.getComputedStyle(obj, null),
theMatrix = computedStyle.getPropertyValue("transform"),
// Reading data from matrix.
mat = theMatrix.match(/^matrix3d\((.+)\)$/);
if (mat) return parseFloat(mat[1].split(', ')[13]);
mat = theMatrix.match(/^matrix\((.+)\)$/);
return mat ? parseFloat(mat[1].split(', ')[5]) : 0;
}
// This method is faster, and it's prefered because it generates less lag. Unfortunatelly it fails to calculate in 3D space.
else
return prompt.getBoundingClientRect().top;
}
The issue will be solved if we change getCurrPos function to following way.
function getCurrPos(obj) {
// There's more than a way to calculate the current position.
// This is the original method, slower and more reliable. Used only for Intergalactic Style, where the other method fails.
if (!obj)
obj=prompt;
var computedStyle = window.getComputedStyle(obj, null),
theMatrix = computedStyle.getPropertyValue("transform"),
// Reading data from matrix.
mat = theMatrix.match(/^matrix3d\((.+)\)$/);
if (mat) return parseFloat(mat[1].split(', ')[13]);
mat = theMatrix.match(/^matrix\((.+)\)$/);
return mat ? parseFloat(mat[1].split(', ')[5]) : 0;
}
N:B This issue will not occur by default when we prompt it by setting
Prompter style to whiteboard.
I am currently switching the menu of my site from pure JavaScript to jQuery. My menu has a rollout / rollin effect.
The menu has an outer wrapper which has an onmouseout event set. If this fires, the relatedTarget is checked whether it's a child of the outer wrapper. If not, the rollin shall happen.
What happens right now is, that if the mouse is moved from the menu's inner wrapper (this is to center the actual menu) to the menu's outer wrapper, the onmouseout fires. There seems to be a tiny part which doesn't belong to the menuOuterWrapper.
The site isn't online right now, so I've prepared a Fiddle here. You will see the problem if you move your mouse from the gray area above the handle to the left or right dark area. The menu will roll in and then immediately out again. The rollin shall only occur when the mouse is moved out of the outer wrapper, i.e. under the dark gray area (or the light gray handle area). To see the dark gray areas, you might have to increase the width of the result block. [EDIT: I reduced the width of inner to 600px, so the dark side areas should be visible by default now.]
SO tells me that I shall include code when linking to JSFiddle. I don't want to break the rules but I'll be honest: I'm clueless where the problem comes from. My best idea is that I made a mistake in my isChildOf implementation, so I'll give you this:
jQuery.fn.isChildOf = function (parentId) {
if ($(this).parents("#" + parentId).length > 0) {
return true;
} else {
return false;
}
};
$('#outer').on('mouseout', function(event) {
if (!$(event.relatedTarget).isChildOf("outer")) {
mouseIsOverMenu = false;
menu_rollin();
}
});
Although this is a minimal example, I did nearly the same with pure JS, where it worked fine. So I guess it's something in the jQuery part. Since these are my first steps with jQuery, it is even more likely.
Every help you can provide is highly appreciated :)
[UPDATE]
I got it working now. The problem was that I didn't check for the relatedTarget to be "outer" itself. So when the mouse leaves the content div and enters the outer div, mouseout fires and of course, outer is no child of itself. So I amended it to
$('#outer').on('mouseout', function(event) {
if (!(event.relatedTarget.id == "outer") &&
!$(event.relatedTarget).isChildOf("outer")) {
mouseIsOverMenu = false;
menu_rollin();
}
});
and that fixed the problem.
if i understood your question right.
This might help
$('#inner').on('mouseover', function() {
mouseIsOverMenu = true;
setTimeout(menu_rollout, 500);
});
$('#inner').on('mouseout', function(event) {
if (!$(event.relatedTarget).isChildOf("outer")) {
mouseIsOverMenu = false;
menu_rollin();
}
});
What i did is i have changed the id of #outer to #inner.
This is a dirty hack, but your problem seems to be with the mouseout function applying too frequently, and what functionality you really want is capturing the mouse leaving the bottom of the menu/content.
Here's some code that will do just that.
$('#outer').on('mouseout', function(event) {
if(event.clientY >= document.getElementById('outer').offsetHeight){
mouseIsOverMenu = false;
menu_rollin();
}
});
here's the associated jsFiddle
I'm pretty new at Raphael JS, and SVG in general. Currently I'm using SVG and Raphael on a map-functionality.
I'm having an issue with a hover effect which offsets the given element you hover with 10px. However, if you move your mouse slowly into the element the hoverIn and hoverOut will happen a bunch of times resulting in flickering.
I think I could resolve this by cloning the countries and leave it hidden and stationary, when hovering. I could do this I say, because the map contains hundreds of shapes...
What is the approach? What should I do?
If I understand correctly the element moves when you hover over it, which cause the hoverOut event. What do you want to happen with slow mouse movements? It moves once, stays moved until the mouse gets inside?
You need to set a variable on the element to show when it's been shifted 10px. Then you can do something like (pseudocode)
hoverIn() {
if (isShifted) {
inWhenShifted = true
} else {
// offset element
isShifted = true
}
hoverOut() {
if (isShifted) {
if (inWhenShifted) {
// put element back
isShifted = false
inWhenShifted = false
} else {
// do nothing?, this is the case where the hoverOut fired
// because we moved the element
}
} else {
// do nothing?, this is the case where we hoverOut again after shifting
// the element back
}
}