mouseout event handler isn't trrigering - easeljs

I have a strange behavior in my app:
I have a collection of shapes that each one of them has a mouseover and mouseout event handlers.
When the user moves over a shape, its color changes and then when he moves out of it, its color returns to the original color.
The thing that I don't understand is sometimes, the mouseout event isn't trigering at all and the color of the shape remains with the hovered state.
I try to print to the console and couldn't find a problem. All I know is that it doesn't enters the mouseouse handler
var onMouseOver = function (e, sha, container) {
if (seat.isHovered) return;
$('body').css('cursor', 'pointer');
var curHoveredShape = sha;
var newShape = new createjs.Shape();
newShape .addEventListener('mouseout', function (e) {
onShapeMouseOut(e, e.target, e.target.parent);
});
newShape .graphics.beginFill(hoverdSeatColor).drawRoundRect(0, 0, 5, 5, 1.5);
newShape .x = curHoveredSeat.x;
newShape .y = curHoveredSeat.y;
newShape .parent = container;
sha.removeEventListener("mouseover", arguments.callee);
container.removeChild(sha);
container.addChild(newShape );
newShape .isHovered = true;
lastHoveredSeat = newShape ;
stage.update();
}
Here's the code for the mouseout:
var onMouseOut = function (e) {
var curShape= e.target;
var container = e.target.parent;
$('body').css('cursor', 'pointer');
var newShape = new createjs.Shape();
newShape.graphics.beginFill(selectedSeatColor).drawRoundRect(0, 0, 5, 5, 1.5);
newShape.x = curShape.x;
newShape.y = curShape.y;
newShape.parent = container;
curShape.removeEventListener("mouseout", arguments.callee);
container.removeChild(curShape);
container.addChild(newShape);
newShape.isHovered = false;
lastHoveredSeat = null;
newShape.addEventListener('mouseover', function(e){
onSeatMouseOver(e, e.target, e.target.parent);
});
stage.update();
$(mapManagerObj).trigger("onSeatHoveredOut");
}

Related

Leaflet - Change and revert polygon feature style

I make a little app using leaflet to display information about polygons.
Here's how the code works :
A crosshair is displayed in the center of the screen on top of the map
When map pans, crosshair remains in the center on the screen
When crosshair overlaps a polygon, polygon information is displyed in a div
the purpose of this system is to help polygon selecting on mobile for very small polygons
I came up with the following app : https://www.laurentgontier.com/Crosshair/
I need to be able to change polygon style when it is overlaped by crosshair and revert to default style when crosshair leaves polygon.
so far, I wasn't able to achieve this.
Here's the part of code :
//Geojson layer display
var geojsonLayer = new L.GeoJSON.AJAX("map.geojson",{
onEachFeature: onEachFeature
});
geojsonLayer.addTo(map);
//Crosshair display
var crosshairIcon = L.icon({
iconUrl: 'Cible.png',
iconSize: [30, 30], // size of the icon
iconAnchor: [15, 15], // point of the icon which will correspond to marker's location
});
crosshair = new L.marker(map.getCenter(), {icon: crosshairIcon, clickable:false});
crosshair.addTo(map);
// Move the crosshair to the center of the map when the user pans
map.on('move', function(e) {
crosshair.setLatLng(map.getCenter());
});
// Move the crosshair to the center of the map when the user pans
map.on('moveend', function(e) {
var hasHit = false;
var newCenter = map.getCenter();
geoJsonLayers.forEach(function(layer){
var currLayerFeature = layer.feature;
var layerPlace = currLayerFeature.properties.Place;
var layerCoordinates = currLayerFeature.geometry.coordinates[0]
var xp = [], yp =[];
for(var i = 0; i<layerCoordinates.length; i++){
xp.push(layerCoordinates[i][0]); yp.push(layerCoordinates[i][1]);
}
if(checkPointForHit(xp, yp , newCenter.lng, newCenter.lat)){
displayPlace.innerHTML = layerPlace; hasHit = true}
})
if(!hasHit)displayPlace.innerHTML = 'Not overlaping polygon'
});
function checkPointForHit(xp/*array of xpointsOfPolygon*/, yp /*array of ypointsOfPolygon*/, x, y) {
var i, j, c = 0, npol = xp.length;
for (i = 0, j = npol-1; i < npol; j = i++) {
if ((((yp[i] <= y) && (y < yp[j])) ||
((yp[j] <= y) && (y < yp[i]))) &&
(x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i])) {
c =!c;
}
}
return c;
}
Any idea about that ?
Use the turfjs library and then use booleanContains:
map.on('moveend', function(e) {
var hasHit = false;
geojsonLayer.resetStyle()
geoJsonLayers.forEach(function(layer){
var layerPlace = layer.feature.properties.Place;
if(turf.booleanContains(layer.toGeoJSON(),crosshair.toGeoJSON())){
displayPlace.innerHTML = layerPlace;
hasHit = true;
layer.setStyle({color: 'red'});
}
})
if(!hasHit){
displayPlace.innerHTML = 'Not overlaping polygon';
}
});
When you change the event from moveend to move the color is updated while moveing
Add DOM Script
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://cdn.jsdelivr.net/npm/#turf/turf#5.1.6/turf.min.js';
document.getElementsByTagName('head')[0].appendChild(script);
map.on('move moveend', function(e) {
var hasHit = false;
var newCenter = map.getCenter();
geojsonLayer.resetStyle()
geoJsonLayers.forEach(function(layer){
var layerPlace = layer.feature.properties.Place;
if(turf.booleanContains(layer.toGeoJSON(),crosshair.toGeoJSON())){
displayPlace.innerHTML = layerPlace;
hasHit = true;
layer.setStyle({color: 'red'});
}
})
if(!hasHit){
displayPlace.innerHTML = 'Not overlaping polygon';
}
});

Chart js - avoid overlapping of tooltips in pie chart

I've used chart js library for make pie chart. I want to display tooltips always. I've done this. I've attached screenshot.
But now the tooltips are overlapped . How to solve this?
This is my code
myPieChart = new Chart(pie_chart).Pie(data_results.comp.pie, {
tooltipTemplate: "<%= value %> %",
scaleFontSize: 14,
scaleFontColor: "#333",
tooltipFillColor: "rgba(0,0,0,0)",
onAnimationComplete: function()
{
this.showTooltip(this.segments, true);
},
tooltipEvents: [],
tooltipFontColor: "#000",
});
I want to change tooltip position if already one present in that position.
Actually to detect overlapping tooltips is very difficult.
I solved it in the end by deactivating the color in the toolbox, reducing the size of the tooltip, moving the tooltip closer to the outer border and hiding all tooltips, which represent less than 2%. Example looks like that:
I used for that the following code:
Chart.Tooltip.positioners.outer = function(elements) {
if (!elements.length) {
return false;
}
var i, len;
var x = 0;
var y = 0;
for (i = 0, len = elements.length; i < len; ++i) {
var el = elements[i];
if (el && el.hasValue()) {
var elPosX = el._view.x+0.95*el._view.outerRadius*Math.cos((el._view.endAngle-el._view.startAngle)/2+el._view.startAngle);
var elPosY = el._view.y+0.95*el._view.outerRadius*Math.sin((el._view.endAngle-el._view.startAngle)/2+el._view.startAngle);
if (x < elPosX) {
x = elPosX;
}
if (y < elPosY) {
y = elPosY;
}
}
}
return {
x: Math.round(x),
y: Math.round(y)
};
},
Chart.pluginService.register({
beforeRender: function (chart) {
if (chart.config.options.showAllTooltips) {
// create an array of tooltips
// we can't use the chart tooltip because there is only one tooltip per chart
chart.pluginTooltips = [];
chart.config.data.datasets.forEach(function (dataset, i) {
chart.getDatasetMeta(i).data.forEach(function (sector, j) {
if ((sector._view.endAngle-sector._view.startAngle) > 2*Math.PI*0.02) {
chart.pluginTooltips.push(
new Chart.Tooltip({
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options.tooltips,
_active: [sector]
}, chart)
);
}
});
});
// turn off normal tooltips
chart.options.tooltips.enabled = false;
}
},
afterDraw: function (chart, easing) {
if (chart.config.options.showAllTooltips) {
// we don't want the permanent tooltips to animate, so don't do anything till the animation runs atleast once
if (!chart.allTooltipsOnce) {
if (easing !== 1)
return;
chart.allTooltipsOnce = true;
}
// turn on tooltips
chart.options.tooltips.enabled = true;
Chart.helpers.each(chart.pluginTooltips, function (tooltip) {
tooltip.initialize();
tooltip._options.position = "outer";
tooltip._options.displayColors = false;
tooltip._options.bodyFontSize = tooltip._chart.height*0.025;
tooltip._options.yPadding = tooltip._options.bodyFontSize*0.30;
tooltip._options.xPadding = tooltip._options.bodyFontSize*0.30;
tooltip._options.caretSize = tooltip._options.bodyFontSize*0.5;
tooltip._options.cornerRadius = tooltip._options.bodyFontSize*0.50;
tooltip.update();
// we don't actually need this since we are not animating tooltips
tooltip.pivot();
tooltip.transition(easing).draw();
});
chart.options.tooltips.enabled = false;
}
}
});

Removing geojson layers Mapbox.js/Leaflet.js

I'm having trouble removing multiple geojson layers at a time. When I keep them as feature layers, there is memory of each and every layer added, one right after the other. But when they become marker layers only the last layer clicked is removed.
I've tried adding them to a group and calling clearLayers on the group, but that still only removes the last layer added, not all. Tried passing an id also, but that didn't seem to work either.
$(function() {
var geojson;
var map = L.mapbox.map('map')
.setView([29.9629, -90.0603], 6);
var filters = document.getElementById('filters');
var layerTwo = L.mapbox.featureLayer()
.loadURL('panel/data/tamorethan5.geojson')
.on('ready', layer)
var layerOne = L.mapbox.featureLayer()
.loadURL('panel/data/talessthan5.geojson')
.on('ready', layer)
var layerThree = L.mapbox.featureLayer()
.loadURL('panel/data/palessthan5.geojson')
.on('ready', layer)
var layerFour = L.mapbox.featureLayer()
.loadURL('panel/data/pamorethan5.geojson')
.on('ready', layer)
function layer() {
var assetLayerGroup = new L.LayerGroup();
var layer = this
var name = layer.getGeoJSON().name;
var item = filters.appendChild(document.createElement('div'));
var checkbox = item.appendChild(document.createElement('input'));
var label = item.appendChild(document.createElement('label'));
checkbox.type = 'checkbox';
checkbox.name ='radio';
checkbox.id = 'myCheckbox';
checkbox.value = name;
label.innerHTML = name;
label.class = label;
label.setAttribute('for', name);
checkbox.addEventListener('change', update);
function update(val) {
if (checkbox.checked) {
console.log(layer)
drawLocations(layer._geojson)
} else {
newMapLayer.clearLayers();
}
}
drawLocations = function(layer) {
L.stamp(layer)
newMapLayer = L.geoJson(layer, {
style: style,
onEachFeature: onEachFeature,
pointToLayer: function(feature, latlng) {
var rad = 3;
var col = getColor(feature.properties, 'status');
return L.circleMarker(latlng, {
radius: rad,
fillColor: "#ff7800",
stroke: true,
weight: 2,
opacity: 0.8,
fillOpacity: 0.8,
className: "circle"
});
}
}).addTo(map);
};
} //end layer
Hm, okay - a few tweaks are necessary or recommended here:
drawLocations(layer._geojson)
Anything starting with a underscore in leaflet or Mapbox should be considered off-limits. Use the .getGeoJSON method instead.
drawLocations(layer.getGeoJSON());
It doesn't look like you're actually adding layers to the assetLayerGroup. If you wanted to do that, you would call
var assetLayerGroup = L.layerGroup().addTo(map);
Right after the
var map = L.mapbox.map('map')
.setView([29.9629, -90.0603], 6);
lines, and instead of calling .addTo(map) on your L.geoJson layers, you would call .addTo(assetLayerGroup).
Then calling assetLayerGroup.clearLayers() would remove all of the added layers.

jssor multiple instances - change the slide of second jssor instance on $EVT_POSITION_CHANGE event of the first jssor instance

Can anyone/jssor support help me how to change the images of second and third jssor sliders when slide show position change event trigger from the first jssor slider? I would be so much appreciated.
thanks,
c
this jssor_slider2.$GoTo(1); is not working.
++++++++++++++++++++++++++++++
function OnSlidePositionChange(slideIndex, fromIndex) {
var jssor_slider2 = new $JssorSlider$('slider2_container', { $AutoPlay: false });
if (slideIndex == 3)
jssor_slider2.$GoTo(1);
else
jssor_slider2.$GoTo(slideIndex + 1);
}
jssor_slider1.$On($JssorSlider$.$EVT_POSITION_CHANGE, OnSlidePositionChange);
++++++++++++++++++++++++++++++
<script>
jssor_slider1_starter("slider1_container");
jssor_slider2_starter("slider2_container");
jssor_slider3_starter("slider3_container");
</script>
script.js file
jssor_slider1_starter = function (containerId) {
var jssor_slider1 = new $JssorSlider$(containerId, {
...
}
function OnSlidePositionChange(slideIndex, fromIndex) {
//HELP ME PLEASE HERE.....
//var jssor_slider2 = new $JssorSlider$('slider2_container', {});
//if (slideIndex == 3)
// nestedSliders[1].$GoTo(1);
//else
// nestedSliders[1].$GoTo(slideIndex + 1);
}
jssor_slider1.$On($JssorSlider$.$EVT_POSITION_CHANGE, OnSlidePositionChange);
}
jssor_slider2_starter = function (containerId) {
var jssor_slider2 = new $JssorSlider$(containerId, {
......
}
}
jssor_slider3_starter = function (containerId) {
var jssor_slider3 = new $JssorSlider$(containerId, {
......
}
}
$JssorSlider$.$EVT_POSITION_CHANGE fires continuously while sliding.
$JssorSlider$.$EVT_PARK fires while slide change.
Please do this job this way,
function jssor_slider3_starter(containerId_1, containerId_2, containerId_3)
{
var options1 = {};
var options2 = {};
var options3 = {};
...
var jssor_slider1 = new $JssorSlider$(containerId_1, options1);
var jssor_slider2 = new $JssorSlider$(containerId_2, options2);
var jssor_slider3 = new $JssorSlider$(containerId_3, options3);
...
function OnSlidePark(slideIndex, fromIndex) {
if (slideIndex == 3)
jssor_slider2.$GoTo(1);
else
jssor_slider2.$GoTo(slideIndex + 1);
}
jssor_slider1.$On($JssorSlider$.$EVT_PARK, OnSlidePark);
...
}

Famo.us not loading Constructor of Strip View in Timbre Example

I am working no Timbre View Example of Famo.us, and what I am trying to achieve is simply open the page by clicking on strip view options in the app and closing the Menu Drawer as soon as I click on the Strip View option
for achieving this functionality I've read the Broad Cast and Listing from the Famo.us documentation. and wrote the following code in my example.
1) created a function to Broadcasting from an event handler with emit method and called it in Constructor of the Strip View.
Strip View:
define(function(require, exports, module) {
var View = require('famous/core/View');
var Surface = require('famous/core/Surface');
var Transform = require('famous/core/Transform');
var StateModifier = require('famous/modifiers/StateModifier');
var ImageSurface = require('famous/surfaces/ImageSurface');
var HeaderFooter = require('famous/views/HeaderFooterLayout');
var FastClick = require('famous/inputs/FastClick');
var check = true;
Boolean(check);
function StripView() {
View.apply(this, arguments);
_createBackground.call(this);
_createIcon.call(this);
_createTitle.call(this);
_setListenersForStripView.call(this);
}
StripView.prototype = Object.create(View.prototype);
StripView.prototype.constructor = StripView;
StripView.DEFAULT_OPTIONS = {
width: 320,
height: 55,
angle: -0.2,
iconSize: 32,
iconUrl: 'img/strip-icons/famous.png',
title: 'Famo.us',
fontSize: 26,
onload: 'StripView()'
};
function allFunctions()
{
_createBackground();
_createIcon();
_createTitle();
}
function _createBackground() {
this.backgroundSurface = new Surface({
size: [this.options.width, this.options.height],
properties: {
backgroundColor: 'black',
boxShadow: '0 0 1px black'
}
});
var rotateModifier = new StateModifier({
transform: Transform.rotateZ(this.options.angle)
});
var skewModifier = new StateModifier({
transform: Transform.skew(0, 0, this.options.angle)
});
this.add(rotateModifier).add(skewModifier).add(this.backgroundSurface);
// this.backgroundSurface.on("touchend", function(){alert("Click caught")})
}
function _createIcon() {
var iconSurface = new ImageSurface({
size: [this.options.iconSize, this.options.iconSize],
content: this.options.iconUrl,
pointerEvents: 'none'
});
var iconModifier = new StateModifier({
transform: Transform.translate(24, 2, 0)
});
this.add(iconModifier).add(iconSurface);
// iconSurface.on("click", function(){alert("Click caught")})
}
function _createTitle() {
this.titleSurface = new Surface({
size: [true, true],
pointerEvents: 'none',
content: this.options.title,
properties: {
color: 'white',
fontFamily: 'AvenirNextCondensed-DemiBold',
fontSize: this.options.fontSize + 'px',
textTransform: 'uppercase',
// pointerEvents : 'none'
}
});
var titleModifier = new StateModifier({
transform: Transform.thenMove(Transform.rotateZ(this.options.angle), [75, -5, 0])
});
this.add(titleModifier).add(this.titleSurface);
}
function _setListenersForStripView() {
this.backgroundSurface.on('touchend', function() {
this._eventOutput.emit('menuToggleforStripView');
alert('clicked on title');
}.bind(this));
}
module.exports = StripView;
});
2) Then created a Trigger Method in App View
App View:
define(function(require, exports, module) {
var View = require('famous/core/View');
var Surface = require('famous/core/Surface');
var Modifier = require('famous/core/Modifier');
var Transform = require('famous/core/Transform');
var StateModifier = require('famous/modifiers/StateModifier');
var Easing = require('famous/transitions/Easing');
var Transitionable = require('famous/transitions/Transitionable');
var GenericSync = require('famous/inputs/GenericSync');
var MouseSync = require('famous/inputs/MouseSync');
var TouchSync = require('famous/inputs/TouchSync');
GenericSync.register({'mouse': MouseSync, 'touch': TouchSync});
var PageView = require('views/PageView');
var StripView = require('views/StripView');
var MenuView = require('views/MenuView');
var StripData = require('data/StripData');
function AppView() {
View.apply(this, arguments);
this.menuToggle = false;
this.pageViewPos = new Transitionable(0);
this.stripViewPos = new Transitionable(0);
_createPageView.call(this);
_StripView.call(this);
_createMenuView.call(this);
_setListeners.call(this);
_handleSwipe.call(this);
_setListenersForStripView.call(this);
}
AppView.prototype = Object.create(View.prototype);
AppView.prototype.constructor = AppView;
AppView.DEFAULT_OPTIONS = {
openPosition: 276,
transition: {
duration: 300,
curve: 'easeOut'
},
posThreshold: 138,
velThreshold: 0.75
};
function _createPageView() {
this.pageView = new PageView();
this.pageModifier = new Modifier({
transform: function() {
return Transform.translate(this.pageViewPos.get(), 0, 0);
}.bind(this)
});
this._add(this.pageModifier).add(this.pageView);
}
function _StripView() {
this.stripView = new StripView();
this.stripModifier = new Modifier({
transform: function() {
return Transform.translate(this.stripViewPos.get(), 0, 0);
}.bind(this)
});
this._add(this.stripModifier).add(this.stripView);
}
function _createMenuView() {
this.menuView = new MenuView({stripData: StripData});
var menuModifier = new StateModifier({
transform: Transform.behind
});
this.add(menuModifier).add(this.menuView);
}
function _setListeners() {
this.pageView.on('menuToggle', this.toggleMenu.bind(this));
}
function _setListenersForStripView() {
this.stripView.on('menuToggleforStripView', this.toggleMenu.bind(this));
}
function _handleSwipe() {
var sync = new GenericSync(
['mouse', 'touch'],
{direction: GenericSync.DIRECTION_X}
);
this.pageView.pipe(sync);
sync.on('update', function(data) {
var currentPosition = this.pageViewPos.get();
if (currentPosition === 0 && data.velocity > 0) {
this.menuView.animateStrips();
}
this.pageViewPos.set(Math.max(0, currentPosition + data.delta));
}.bind(this));
sync.on('end', (function(data) {
var velocity = data.velocity;
var position = this.pageViewPos.get();
if (this.pageViewPos.get() > this.options.posThreshold) {
if (velocity < -this.options.velThreshold) {
this.slideLeft();
} else {
this.slideRight();
}
} else {
if (velocity > this.options.velThreshold) {
this.slideRight();
} else {
this.slideLeft();
}
}
}).bind(this));
}
AppView.prototype.toggleMenu = function() {
if (this.menuToggle) {
this.slideLeft();
} else {
this.slideRight();
this.menuView.animateStrips();
}
};
AppView.prototype.slideLeft = function() {
this.pageViewPos.set(0, this.options.transition, function() {
this.menuToggle = false;
}.bind(this));
};
AppView.prototype.slideRight = function() {
this.pageViewPos.set(this.options.openPosition, this.options.transition, function() {
this.menuToggle = true;
}.bind(this));
};
module.exports = AppView;
});
now what this code does, is create another strip overlapping the previous strips and it only works on the newly created strip view but not on the other strips which means when it comes back to srip view it loads only the DEFAULT_OPTIONS of strip view because the strip which is being generated newly and overlaping is titled famo.us
Please let me know where I am going wrong and how can I open a new view in my application by closing menu drawer.
Do you have a folder named 'data' with the 'StripData.js' file on your famo.us project?
I'm asking because I downloaded the the Starter Kit and I didn't find that file inside.