How to dynamically define the 'hero' in 'neon-animated-pages'? - javascript

I have two buttons in a page and I'd like the clicked one to play as hero in a transition to another page.
Say I have the first page:
<dom-module id="first-page">
<style>
.hero_from_1 {
position: fixed;
bottom: 0;
left: 0;
background-color: cornflowerblue;
}
.hero_from_2 {
position: fixed;
bottom: 0;
right: 0;
background-color: cornflowerblue;
}
</style>
<template>
<paper-button class="hero_from_1" raised on-tap="tapHandler_1">First Hero</paper-button>
<paper-button class="hero_from_2" raised on-tap="tapHandler_2">Second Hero</paper-button>
</template>
<script>
addEventListener('WebComponentsReady', function() {
Polymer({
is: 'first-page',
tapHandler_1: function(ev){
document.getElementsByClassName('hero_from_1')[0].setAttribute('id','hero_from');
document.getElementsByClassName('hero_from_2')[0].removeAttribute('id');
this.fire('second-page');
},
tapHandler_2: function(ev){
document.getElementsByClassName('hero_from_1')[0].removeAttribute('id');
document.getElementsByClassName('hero_from_2')[0].setAttribute('id','hero_from');
this.fire('second-page');
},
behaviors: [Polymer.NeonSharedElementAnimatableBehavior],
properties: {
animationConfig: {
value: function(){
return {
'entry':{
name: 'fade-in-animation',
node: this
},
'exit':[{
name: 'hero-animation',
id: 'hero',
fromPage: this
},{
name: 'fade-out-animation',
node: this
}]
}
}
},
sharedElements: {
value: function() {
return {
'hero': this.$.hero_from // changes in ids do not affect hero!!!
}
}
}
}
})
});
</script>
</dom-module>
with a standard sharedElements property, as documented in the project pages (https://elements.polymer-project.org/guides/using-neon-animations#page-transitions).
The problem is that even if I exchange the id of the buttons right after a click or tap event, the change does not propagate to the sharedElements function, and the animation does not work.
See fiddle:
http://jsfiddle.net/ferdinandkraft/qzxzeb1u/

The problem is that the sharedElements' function is evaluated at creation/attachment time, so it will not keep track of changing ids.
I've found a way to work aroud this, simply by setting the sharedElements property right after the tap event, just like any other property:
<dom-module id="first-page">
<style>
.hero_from_1 {
position: fixed;
bottom: 0;
left: 0;
background-color: cornflowerblue;
}
.hero_from_2 {
position: fixed;
bottom: 0;
right: 0;
background-color: cornflowerblue;
}
</style>
<template>
<paper-button class="hero_from_1" raised on-tap="tapHandler">First Hero</paper-button>
<paper-button class="hero_from_2" raised on-tap="tapHandler">Second Hero</paper-button>
</template>
<script>
addEventListener('WebComponentsReady', function() {
Polymer({
is: 'first-page',
tapHandler: function(ev){
this.sharedElements = {'hero': ev.target}; /////// here!!!
this.fire('second-page');
},
behaviors: [Polymer.NeonSharedElementAnimatableBehavior],
properties: {
animationConfig: {
value: function(){
return {
'entry':{
name: 'fade-in-animation',
node: this
},
'exit':[{
name: 'hero-animation',
id: 'hero',
fromPage: this
},{
name: 'fade-out-animation',
node: this
}]
}
}
},
/* sharedElements removed! */
}
})
});
</script>
</dom-module>
Note that ev.target will be the clicked button, so a single tapHandler will do the job!
See fiddle:
http://jsfiddle.net/ferdinandkraft/b1sw1q2o/

Related

Stop Event Propagation of Mapbox Layers

I have one layer and a basemap
mapboxgl.accessToken = '';
const coords = JSON.parse('{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[13.380550656438709,52.52208508665396]}},{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[13.380633221743006,52.52208172104466]}},{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[13.380686171093972,52.52208244564463]}},{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[13.380702060621635,52.5220511942754]}},{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[13.380527236009051,52.52205779286111]}}]}');
this.map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v9',
zoom: 19, // starting zoom
center: [13.380702060621635, 52.5220511942754]
});
this.map.on('load', async () => {
const controls = new mapboxgl.NavigationControl();
this.map.addControl(controls, 'top-right');
this.map.addSource('foo', {
type: 'geojson',
data: coords
});
this.map.addLayer({
id: 'points',
type: 'circle',
source: 'foo',
paint: {
'circle-radius': 5,
'circle-color': 'hotpink',
},
});
});
this.map.on('click', 'points', event => {
console.log('Layer click')
});
this.map.on('click', () => {
console.log('Basemap click')
});
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
#sidebar {
background-color: hotpink;
height: 100vh;
width: 200px;
position: relative;
z-index: 99999999999;
opacity: 0.5;
}
.popup-content {
display: inline-block
}
.pin-icon {
font-size: 20px;
color: blue
}
.vl {
border-left: 1px solid #bababa;
height: 15px;
padding: 0px;
margin: 10px;
}
<html>
<head>
<meta charset='utf-8' />
<title></title>
<meta name='viewport' content='initial-scale=1,maximum-;scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v1.2.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.2.0/mapbox-gl.css' rel='stylesheet' />
</head>
<body>
<div id='map'></div>
</body>
</html>
https://codepen.io/diesdasananas/pen/eqVLyj
Whenever I click on the circle layer, the event propagates through the basemap. Basemap click gets logged. I wonder how do I stop event propagation from the circle layer to the basemap? I cannto use event.stopPropagation() because Mapbox draws on the canvas...
One approach is to save the event coordinates of the click on the layer and then compare these coordinates with the underlying layer and its event coordinates.
let clickCoords = {};
this.map.on('click', 'points', event => {
clickCoords = event.point;
console.log('Layer click')
});
Now, detect a click on the map, not on the points layer
this.map.on('click', () => {
// check if coords are different, if they are different, execute whatever you need
if (clickCoords.x !== event.point.x && clickCoords.y !== event.point.y) {
console.log('Basemap click');
clickCoords = {};
}
});
Or, even better, use queryRenderedFeatures().
this.map.on('click', event => {
if (this.map.queryRenderedFeatures(event.point).filter(feature => feature.source === YOURLAYERNAME).length === 0) {
console.log('Basemap click');
}
});
Here is a Mapbox example.

introjs onafterchange fires before tooltip is positioned

While using introjs.js, I am trying to set the position of a tooltip (.introjs-tooltip) but, if I use the onafterchange event, my code runs, and then the position of the tooltip is set by introjs, and my values for top and left are overwritten. How can I make my change AFTER introjs has done it's calculations for the location of the tooltip?
<div>
<div class="divStep step1">
<span>Nothing much going on here</span>
</div>
<div id="step2" class="divStep step2">
<span>This is step 2</span>
</div>
<div id="step3" class="divStep step3">
<span>This is step 3</span>
</div>
</div>
body {
background-color: #00eeee;
}
.divStep {
display: block;
height: 100px;
width: 400px;
background-color: #fff;
margin: 10px;
padding: 10px;
}
.tt-step2 {
top: 0 !important;
left: 0 !important;
background-color: #ff0000;
}
var myIntro = {
tooltipPosition: 'bottom',
steps: [
{
intro: 'Howdy! This is step 1'
},
{
element: '#step2',
intro: 'This is step 2',
onbeforechange: function(){
console.log('onbeforechange step 2');
$('.introjs-tooltip').addClass('tt-step2');
console.log('has class? ' + $('.introjs-tooltip').hasClass('tt-step2'));
},
onchange: function(){
console.log('onchange step 2');
$('.introjs-tooltip').addClass('tt-step2');
console.log('has class? ' + $('.introjs-tooltip').hasClass('tt-step2'));
},
onafterchange: function(){
console.log('onafterchange step 2');
$('.introjs-tooltip').addClass('tt-step2');
console.log('has class? ' + $('.introjs-tooltip').hasClass('tt-step2'));
}
},
{
element: '#step3',
intro: 'This is step 3'
}
]
}
function launchIntro(){
var intro = introJs();
intro.setOptions(myIntro);
intro
.onbeforechange(function(){
currentStep = this._options.steps[this._currentStep];
if(currentStep.onbeforechange) {
currentStep.onbeforechange();
}
})
.onchange(function(){
currentStep = this._options.steps[this._currentStep];
if(currentStep.onchange) {
currentStep.onchange();
}
})
.onafterchange(function(){
currentStep = this._options.steps[this._currentStep];
if(currentStep.onafterchange) {
currentStep.onafterchange();
}
})
.start();
}
launchIntro();
I came across a similar issue. Currently IntroJS library has an open issue on github.
I had an assignment to heavily customize the elements styles and adjust some behavior.
I managed to handle the situation by using MutationObserver
Here's an example snippet:
const observer = new MutationObserver((mutations) => {
const { target } = mutations[0];
document.querySelector('.introjs-tooltip').style.top = `${
document.querySelector('.introjs-helperLayer').clientHeight
- document.querySelector('.introjs-tooltip').clientHeight - 10}px`;
return null; });
observer.observe(
document.querySelector('.introjs-tooltip'),
{ attributes: true, attributeOldValue: true, attributeFilter: ['style'] },
);

Video.js Customizing player controls

Im Searching how to customize the player for live use with dash.js,
as browser player not work wel with live session i trying to delete seekbar and time indicators for now, in the future i will search for a seekbar that can manage live buffer.
But I can't find the correct attribute to set seekBar: false and every time indicator off,
I find this list https://docs.videojs.com/tutorial-components.html but the components seems to not work.
Which are the correct attribute to exclude that controls? Or maybe is a syntax problem?
http://jsbin.com/aheVeCOG/2/edit?js,output
Volume control to false work:
var video = videojs('my_video_1', {
children: {
controlBar: {
children: {
volumeControl: false
}
}
}
});
My try don't work
var video = videojs('my_video_1', {
children: {
controlBar: {
children: {
ProgressControl: false
}
}
}
});
Thanks!
Massimo
Just need to fix typo it works, use lowserCase at first character instead:
progressControl instead of ProgressControl
var video = videojs('my_video_1', {
children: {
controlBar: {
children: {
progressControl: false
}
}
}
});
Working example:
http://jsbin.com/damahev/2/edit?html,js,output
I was instructed to use the CSS side to show/hide any undesirable values.
So, I've been using the top four lines in style defn below for mine:
<style>
.video-js .vjs-current-time { display: block; }
.video-js .vjs-time-divider { display: block; }
.video-js .vjs-duration { display: block; }
.video-js .vjs-remaining-time { display: none; }
#.video-js .vjs-mute-control { display: none; }
#.video-js .vjs-volume-menu-button { display: none; }
#.video-js .vjs-volume-bar { display: none; }
#.video-js .vjs-progress-control { display: none; }
</style>
The bottom-four lines (after removing leading '#' char) should work for you.
(Note that you can peruse the linked file 'video-js.css' for current defns.
This worked for me:
this.video = videojs('some-id', {
bigPlayButton: true,
controlBar: {
fullscreenToggle: false,
pictureInPictureToggle: false,
remainingTimeDisplay: false,
volumePanel: false,
currentTimeDisplay: true,
timeDivider: true,
durationDisplay: true
}
})
To make currentTimeDisplay, timeDivider and durationDisplay to work you also need to add this CSS:
.vjs-current-time {
display: inline-block !important;
}
.vjs-time-divider {
display: inline-block !important;
}
.vjs-duration {
display: inline-block !important;
}

Load JSON file in Sigma.js but can't bind overEdge Event

I want to load some data from a JSON file and graph them in Sigma.js, and bind overEdge and outEdge event with all edges. I read some examples in official document and solved the problem when I want to bind overNode event in my code, but the the same way using to bind overEdge event doesn't work. Here is my code:
<script>
sigma.parsers.json(
'../data/data.json',
{
container: 'graph-container',
type: 'canvas',
settings: {
defaultNodeColor: '#ec5148',
enableEdgeHovering: true,
edgeHoverColor: 'edge',
defaultEdgeHoverColor: '#000',
edgeHoverSizeRatio: 1,
edgeHoverExtremities: true,
}
},
function(s) {
s.graph.nodes().forEach(function(n) {
s.bind('overNode',
function(e) {
alert("node");
}
);
});
s.graph.edges().forEach(function(n) {
s.bind('overEdge',
function(e) {
alert('edge');
}
);
});
}
);
</script>
When I run my code, it seems that
enableEdgeHovering: true,
made some mistake like
Uncaught Error: The edge events feature is not compatible with the WebGL renderer
but when I delete that, my edge can not bind events. I see official example do the same, and their code can work on my browser, but my code can't.
May it isn't actually for you. This is working example from my project:
<div id="container">
<style>
#graph-container {
top: 0;
bottom: 0;
left: 0;
right: 0;
position: absolute;
}
</style>
<div id="graph-container"></div>
</div>
<script>
s = new sigma({
graph: 0,
container: 'graph-container',
renderer: {
container: document.getElementById('graph-container'),
type: 'canvas'
},
settings: {
doubleClickEnabled: false,
minEdgeSize: 0.5,
maxEdgeSize: 4,
enableEdgeHovering: true,
edgeHoverColor: '#000',
defaultEdgeHoverColor: 'red',
edgeHoverSizeRatio: 1,
edgeHoverExtremities: true,
defaultEdgeLabelSize: 20,
edgeLabelSize: 'proportional',
minArrowSize: 10,
}
});
sigma.parsers.json('data/arctic.json', s);
s.bind('overNode outNode clickNode doubleClickNode rightClickNode', function(e) {
console.log(e.type, e.data.node.label, e.data.captor);
});
</script>

How to access attribute value in polymer?

HTML
<my-element username="{{params.username}}"></my-element>
Element
<dom-module id="my-element">
<style>
:host {
display: block;
}
</style>
<template>
</template>
<script>
(function() {
Polymer({
is: 'my-elemnt',
ready: function(){
// get attribute value
});
})();
</script>
</dom-module>
I can access the attribute from the template but don't know how to it access from javascript.
inside the element it would be this.username but you might need to add that to properties for it to work
Polymer({
is: 'my-element',
properties: {
username: {
type: Object,
observer: '_updateUsername'
}
},
_updateUsername: function () {
// use this.username
}
});
<link rel="import" href="polymer/polymer.html"/>
<dom-module id="my-element" username>
<style>
:host {
display: block;
}
</style>
<template>
<p>{{username.name}}</p>
</template>
</dom-module>
<script>
(function () {
Polymer({
is: 'my-elemnt',
properties: {
username: {
type: Object,
notify: true
}
},
ready: function () {
console.log(this.username);
}
});
})();
</script>
If you haven't declared the property it will log - undefined
For more information about the new declaration way check -
https://www.polymer-project.org/1.0/docs/devguide/properties.html

Categories