I'm trying to load multiple sliders using noUISlider and it's not working. When using the first slider, the values changes for the second and third. How do I go about refactoring the code for one slider so I can easily add additional sliders with different options?
Here's a fiddle and below is my code.
// noUISlider
var actSlider = document.getElementById('act-slider');
noUiSlider.create(actSlider, {
start: [0, 50],
connect: false,
step: 1,
range: {
'min': 0,
'max': 50
},
format: {
to: function (value) {
return value + '';
},
from: function (value) {
return value.replace('', '');
}
}
});
// Connect bar
var connectBar = document.createElement('div'),
connectBase = actSlider.getElementsByClassName('noUi-base')[0],
connectHandles = actSlider.getElementsByClassName('noUi-origin');
// Give the bar a class for styling and add it to the slider.
connectBar.className += 'connect';
connectBase.appendChild(connectBar);
actSlider.noUiSlider.on('update', function (values, handle) {
// Pick left for the first handle, right for the second.
var side = handle ? 'right' : 'left',
// Get the handle position and trim the '%' sign.
offset = (connectHandles[handle].style.left).slice(0, -1);
// Right offset is 100% - left offset
if (handle === 1) {
offset = 100 - offset;
}
connectBar.style[side] = offset + '%';
});
// Value tooltips
var tipHandles = actSlider.getElementsByClassName('noUi-handle'),
tooltips = [];
// Add divs to the slider handles.
for (var i = 0; i < tipHandles.length; i++) {
tooltips[i] = document.createElement('div');
tooltips[i].className += 'value-tooltip';
tipHandles[i].appendChild(tooltips[i]);
}
// When the slider changes, write the value to the tooltips.
actSlider.noUiSlider.on('update', function (values, handle) {
tooltips[handle].innerHTML = values[handle];
});
You can wrap your slider creation in a function, and call it for all elements where you want a slider created.
noUiSlider also supports tooltips (from version 8.1.0) and connect options, so you don't have to implement those yourself if you don't want to make very specific changes.
As for different options for every slider, there are several ways to do this. I've added an example using data attributes for the step option.
The following code initializes a slider on all elements with a .slider class.
function data ( element, key ) {
return element.getAttribute('data-' + key);
}
function createSlider ( slider ) {
noUiSlider.create(slider, {
start: [0, 50],
connect: false,
step: Number(data(slider, 'step')) || 1,
range: {
'min': 0,
'max': 50
},
tooltips: true,
connect: true,
format: {
to: function (value) {
return value + '';
},
from: function (value) {
return value.replace('', '');
}
}
});
}
Array.prototype.forEach.call(document.querySelectorAll('.slider'), createSlider);
Here's a jsFiddle demonstrating this code.
Related
I am new to Phaserjs, trying to create basic drag-drop style game.
I have created the game and add arcade physics (this.game.physics.arcade.enable(this.orange_outline);)
Currently overlap happen as soon as the edges collide.
I want to detect that my code should trigger when 50% overlap happen. is it possible in phaserjs?
var GameState = {
init:function(){
this.physics.startSystem(Phaser.Physics.ARCADE);
},
create: function () {
this.background = this.game.add.sprite(0, 0, 'background');
this.overlapHappen = false;
this.orange_outline = this.game.add.sprite(459,199,'orange_outline');
this.orange_outline.frame = 2;
this.orange_outline.anchor.setTo(.5);
this.orange_outline.customParams = {myName:'orange_outline',questionImg:'orange'};
this.orange_inner = this.game.add.sprite(150,197,'orange_inner');
this.orange_inner.anchor.setTo(.5);
this.orange_inner.customParams = {myName:'orange_inner',questionImg:'orange',targetKey:this.orange_outline,targetImg:'orange_outline'};
this.orange_inner.frame = 1;
this.orange_inner.inputEnabled = true;
this.orange_inner.input.enableDrag();
this.orange_inner.input.pixelPerfectOver = true;
this.orange_inner.events.onDragStart.add(this.onDragStart,this);
// this.game.physics.enable(this.orange_inner,Phaser.Physics.ARCADE);
this.game.physics.arcade.enable(this.orange_inner);
this.game.physics.arcade.enable(this.orange_outline);
this.orange_inner.events.onDragStop.add(this.onDragStop,this);
},
update: function () {
//this.orange.animations.play('orange_one',1)
},
onDragStart:function(sprite,pointer){
//console.log(sprite.key + " dragged")
},
onDragStop:function(sprite,pointer){
var endSprite = sprite.customParams.targetKey;
//console.log(sprite.customParams);
this.stopDrag(sprite,endSprite)
},
stopDrag:function(currentSprite,endSprite){
if (!this.game.physics.arcade.overlap(currentSprite, endSprite, function() {
var currentSpriteTarget = currentSprite.customParams.targetImg;
var endSpriteName = endSprite.customParams.myName;
if(currentSpriteTarget === endSpriteName){
currentSprite.input.draggable = false;
currentSprite.position.copyFrom(endSprite.position);
currentSprite.anchor.setTo(endSprite.anchor.x, endSprite.anchor.y);
}
console.log(currentSpriteTarget,endSpriteName);
})) {
//currentSprite.position.copyFrom(currentSprite.originalPosition);
console.log('you')
}
}
}
In stopDrag() I am detecting overlap.
You can try to get the amount of horizontal and vertical overlap amount and check if it satisfies a certain threshold. This can be done in additional overlap function callback, that is called processCallback in documentation. As an example:
if (!this.game.physics.arcade.overlap(currentSprite, endSprite, function() {
//your callback !
},function() {
if (this.game.physics.arcade.getOverlapX(currentSprite, endSprite) > currentSprite.width / 2
&& this.game.physics.arcade.getOverlapY(currentSprite, endSprite) > currentSprite.height / 2) {
//Overlaping !
return true;
} else {
//as if no overlap occured
return false;
}
},this) {
//
}
Another way to do this (other than what Hamdi Douss offers) is to resize your body to only take up 50% of the area. This will automatically ensure that collisions/overlap don't occur unless the reduced bodies touch each other.
To view your current body, use Phaser's debug methods
this.game.debug.body(someSprite, 'rgba(255,0,0,0.5)');
Was wondering if there is a plug-in already available for FLOT chart legend to be interactive like in highcharts
Providing the example out here
http://jsfiddle.net/yohanrobert/T3Dpf/1/
However, in a turn of event I tried my hand on mouseover event through jquery
$(".legendLabel").mouseover(function(){
// Unhighlight all points
console.log($(this))
plot.unhighlight();
// The X value to highlight
var value = parseInt($(this).context.innerText.replace('Series ',''))-1;
// Retrieve the data the plot is currently using
var data = plot.getData();
// Iterate over each series and all points
for (var s=0; s<data.length; s++) {
var series = data[s];
if(s==value){
for (var p=0; p<series.data.length; p++) {
plot.highlight(s, p);
}
}
}
});
Can anyone help me achieve the interactivity like in the example?
Extended togglePlot function for different plot types (we save the original plot type in the hidden property):
togglePlot = function (seriesIdx) {
var plotTypes = ['lines', 'points', 'bars'];
var someData = somePlot.getData();
var series = someData[seriesIdx];
$.each(plotTypes, function (index, plotType) {
if (series[plotType]) {
if (series[plotType].show) {
series[plotType].show = false;
series[plotType].hidden = true;
}
else if (series[plotType].hidden) {
series[plotType].show = true;
series[plotType].hidden = false;
}
}
});
somePlot.setData(someData);
somePlot.draw();
}
For highlighting a data series like in highcharts add a highlightPlot function like this (here only for line series):
highlightPlot = function (seriesIdx) {
var someData = somePlot.getData();
$.each(someData, function (index, series) {
someData[index].lines.lineWidth = (index == seriesIdx ? 4 : 2);
});
somePlot.setData(someData);
somePlot.draw();
}
I also changed the inline event handlers to jQuery event handling to make it cleaner:
$(document).on({
click: function () {
togglePlot($(this).data('index'));
return false;
},
mouseover: function () {
highlightPlot($(this).data('index'));
},
mouseout: function () {
highlightPlot(-1);
},
}, 'a.legend');
See this updated fiddle for the full example.
In my update() function, I use pointerOver() to detect when the pointer is over a sprite. This normally works fine. However, if I happen to be dragging another sprite at the time, the pointerOver() function always returns false.
I thought I'd work around it by getting the location of the pointer and comparing it with the location and bounds of my sprite, but the pointer location is always (-1, -1).
Here's some example code to demonstrate the problem:
var game = new Phaser.Game( 800, 600, Phaser.AUTO, '', { preload: preload, create: create, update: update, render: render });
var triangle;
var square;
var isOver;
var pointerX;
var pointerY;
function preload()
{
game.load.image( 'triangle', 'assets/triangle.png' );
game.load.image( 'square', 'assets/square.png' );
}
function create()
{
triangle = game.add.sprite( 100, 100, "triangle" );
triangle.inputEnabled = true;
triangle.input.enableDrag( false, true );
square = game.add.sprite( 100, 200, "square" );
square.inputEnabled = true;
}
function update()
{
isOver = square.input.pointerOver() ? "Yes" : "No";
}
function render()
{
game.debug.text( "Mouse over square: " + isOver, 200, 100 );
game.debug.text( "Pointer: (" + game.input.pointer1.x + ", " + game.input.pointer1.y + ")", 200, 116 );
}
I found this post about using a sprite's input.priorityID: Phaser JS how to stop event Propagation(firing) from textButton.events.onInputDown event to game.input.onDown event?
Using the priorityID fixed it for when the triangle is on top the square and the triangle is not being dragged, but the problem remains when it's being dragged.
How do I detect when the pointer is over a sprite, even when I'm dragging another sprite?
Thanks.
I had a similar issue recently and I hope this will still be of help to you.
I found out that upon initiating a drag, the input on all sprites except for the one you're dragging becomes disabled. That probably happens internally and I couldn't find a way to override it.
What I did is the following: all the objects (in my case instances of Tile) I want to be draggable are held within a Board object, which in turn holds a reference to my Game state. In the Game state I have a flag dragIsActive. In the object class itself I have (TypeScript)
this.tileSprite.events.onDragStart.add(() => {
this.parentBoard.gameState.dragIsActive = true;
});
this.tileSprite.events.onDragStop.add(() => {
this.parentBoard.gameState.dragIsActive = false;
});
The equivalent JavaScript would be
this.tileSprite.events.onDragStart.add(function() {
this.parentBoard.gameState.dragIsActive = true;
});
this.tileSprite.events.onDragStop.add(function() {
this.parentBoard.gameState.dragIsActive = false;
});
called from the object's constructor.
In Game I have the following:
update() {
if (this.dragIsActive) {
var firstTile : Tile = this.game.input.activePointer.targetObject.sprite.parent;
this.board.tiles.forEach((t : Tile) => {
if (firstTile.tileSprite.overlap(t.tileSprite)) {
this.board.tilesToSlide.push(t);
}
});
this.board.tilesToSlide.forEach((tileToSlide) => {
// Do the processing on that array here.
});
}
}
JavaScript (just the forEach loop):
this.board.tiles.forEach(fucntion(t) {
if (firstTile.tileSprite.overlap(t.tileSprite)) {
this.board.tilesToSlide.push(t);
}
});
In my case the check is for two sprites overlapping, but in your case you can check if one just point of interest (e.g. the position of the sprite you're dragging) is inside the bounds of another sprite:
if (secondSprite.getBounds().containsPoint(firstSprite.position)) {
// This should be equivalent to pointerOver() while dragging something.
}
P.S. I hope you're aware that a sprite's position is at the top left of its bounding box unless explicitly set to something else. Set via sprite.anchor.set(x, y) - (0, 0) being top left (the default) and (1, 1) - bottom right.
you can also use this method to see if the point is contained within the sprite bounds.
if( Phaser.Rectangle.contains( sprite.body, this.game.input.x, this.game.input.y) ){
console.log('collide')
}
Background
I have a primefaces line chart (date on x, integer >= 0 on y) extended with jqplot options:
function extender() {
this.cfg.axes = {
xaxis : {
renderer : $.jqplot.DateAxisRenderer,
rendererOptions : {
tickRenderer:$.jqplot.CanvasAxisTickRenderer
},
tickOptions : {
fontSize:'10pt',
fontFamily:'Tahoma',
angle:-40,
formatString:'%b-%y'
},
tickInterval:'2592000000'
},
yaxis : {
min: 0,
rendererOptions : {
tickRenderer:$.jqplot.CanvasAxisTickRenderer,
},
tickOptions: {
fontSize:'10pt',
fontFamily:'Tahoma',
angle:0,
formatString: '%d'
}
},
};
this.cfg.axes.xaxis.ticks = this.cfg.categories;
}
I'm using the jqplot extender to have custom date interval on the x-axis and this is working fine:
Problem
When I use the option min: 0 in the y-axis the formatting of numbers goes really funky, especially when there are small values:
Note that the minY attribute in primefaces doesn't work (probably because the extender overwrites it)
To fix that, I use formatString: %d. It works but it creates problem with the number of ticks:
As you see on the screenshot, there are several times the line for the value 1.
Question
How can make sure I don't get several times the same value on the y-axis?
I can't really have a static number of ticks because when the data grows large (let's say around 100), I do want several values on the y-axis (e.g 20, 40, etc...)
I managed to solve my issue using ideas from Mehasse's post.
Defining the max value like suggested by Mehasse didn't remove the unwanted tick lines but helped me to find the answer.
By default, primefaces/jqplot wants to have 4 y-axis tick lines. Thus, if the max value is below 4, there will be duplication in the y-axis label when they are rounded up (formatString: '%d').
What I basically want, is the tick interval to be either Max(y) \ 4 when Max(y) > 4, or 1 otherwise:
function actionPlanExtender() {
var series_max =maxSeries(this.cfg.data);
var numberOfTicks =4;
var tickInterval = Math.max(1, Math.ceil(series_max/numberOfTicks));
this.cfg.axes = {
xaxis : {
renderer : $.jqplot.DateAxisRenderer,
rendererOptions : {
tickRenderer:$.jqplot.CanvasAxisTickRenderer
},
tickOptions : {
fontSize:'10pt',
fontFamily:'Tahoma',
angle:-40,
formatString:'%b-%y'
},
tickInterval:'2592000000'
},
yaxis : {
min: 0,
rendererOptions : {
tickRenderer:$.jqplot.CanvasAxisTickRenderer,
},
tickOptions: {
fontSize:'10pt',
fontFamily:'Tahoma',
angle:0,
formatString: '%d',
},
tickInterval: tickInterval
},
};
this.cfg.axes.xaxis.ticks = this.cfg.categories;
}
To compute the y-max value, I'm getting the plot value using this.cfg.data which is of the form [series_1,..., series_n] with series_i = [[x_1, y_1],..., [x_m, y_m]]
The maxSeries function looks like:
function maxSeries(datas) {
var maxY = null;
var dataLength = datas.length;
for ( var dataIdx = 0; dataIdx < dataLength; dataIdx++) {
var data = datas[dataIdx];
var l = data.length;
for ( var pointIdx = 0; pointIdx < l; pointIdx++) {
var point = data[pointIdx];
var y = point[1];
if (maxY == null || maxY < y) {
maxY = y;
}
}
}
return maxY;
}
Note that in my case I know my case I don't have value below 0. This code should be updated if this is not the case.
I was surprised when I first started using JQPlot that it doesn't pick reasonable axis labels out of the box. It's actually easy to fix.
I'm going to assume that you want your y axis to start at zero. If that's not true, you'll need to modify this code a bit.
// This is YOUR data set
var series = [882, 38, 66, 522, 123, 400, 777];
// Instead of letting JQPlot pick the scale on the y-axis, let's figure out our own.
var series_max = Math.max.apply(null, series);
var digits = max.toString().length;
var scale = Math.pow(10, max_digits - 1);
var max = (Math.ceil(series_max / scale)) * scale;
$.jqplot(
'foo',
[series],
{
axes: {
yaxis: {
min: 0,
max: max
}
}
// Put your other config stuff here
}
)
The basic idea here is that we want to round up to some nice, round value near the maximum value in our series. In particular, we round up to the nearest number that has zeroes in all digits except the left-most. So the max 882 will result in a y-axis max of 1000.
I'm starting to work only with YUI3. I include component scrollView, but it did not work mousewheel event, in the options I have not found how to turn on it. I would appreciate any help.
var scrollView = new Y.ScrollView({
id: "scrollview",
srcNode: '.scrollview-item',
height: 375,
flick: {
minDistance: 10,
minVelocity: 0.3,
axis: "y"
}
});
scrollView.render();
I stumbled upon this as well, after some trial and error, I managed to get that working(note, that it is just plain scrolling, without an easing).
var DOM_MOUSE_SCROLL = 'DOMMouseScroll',
fixArgs = function(args) {
var a = Y.Array(args, 0, true), target;
if (Y.UA.gecko) {
a[0] = DOM_MOUSE_SCROLL;
// target = Y.config.win;
} else {
// target = Y.config.doc;
}
if (a.length < 3) {
// a[2] = target;
} else {
// a.splice(2, 0, target);
}
return a;
};
Y.Env.evt.plugins.mousewheel = {
on: function() {
return Y.Event._attach(fixArgs(arguments));
},
detach: function() {
return Y.Event.detach.apply(Y.Event, fixArgs(arguments));
}
};
This is the YUI mousewheel event, but it's changed a bit. The biggest issue was, that originally, either the window or document elements, which makes no sense(for example when you mousewheel over the #myelement you want that to be the returned target..)
Bellow is the code used to initialize the ScrollView and the function that handles the mousewheel event:
// ScrollView
var scrollView = new Y.ScrollView({
id: "scrollview",
srcNode: '#mycontainer',
height: 490,
flick: {
minDistance:10,
minVelocity:0.3,
axis: "y"
}
});
scrollView.render();
var content = scrollView.get("contentBox");
var scroll_modifier = 10; // 10px per Delta
var current_scroll_y, scroll_to;
content.on("mousewheel", function(e) {
// check whether this is the scrollview container
if ( e.currentTarget.hasClass('container') ) {
current_scroll_y = scrollView.get('scrollY');
scroll_to = current_scroll_y - ( scroll_modifier * e.wheelDelta );
// trying to scroll above top of the container - scroll to start
if ( scroll_to <= scrollView._minScrollY ) {
// in my case, this made the scrollbars plugin to move, but I'm quite sure it's important for other stuff as well :)
scrollView._uiDimensionsChange();
scrollView.scrollTo(0, scrollView._minScrollY);
} else if ( scroll_to >= scrollView._maxScrollY ) { // trying to scroll beneath the end of the container - scroll to end
scrollView._uiDimensionsChange();
scrollView.scrollTo(0, scrollView._maxScrollY);
} else { // otherwise just scroll to the calculated Y
scrollView._uiDimensionsChange();
scrollView.scrollTo(0, scroll_to);
};
// if we have scrollbars plugin, flash the scrollbar
if ( scrollView.scrollbars ) {
scrollView.scrollbars.flash();
};
// prevent browser default behavior on mouse scroll
e.preventDefault();
};
});
So basically that's how I managed to that, but my next challenge is to get the scrollbar work like regular scrollbar(when you drag it, the container should move correspondingly...)
Hope this helps anyone :)