Related
I am trying to understand the filterPredicate of MatTableDataSource, and when I thought I was close, I am missing some logic.
I want to filter through a datasource and if the array's value is blank or "", then it shouldn't filter for every value that is defined as "". In other words, filter with what it does know and not what it doesn't know.
I tried to assign the values to null if the length of the array is equal to 0. But even that did not work.
Typescript
this.registeredUserService.GetAllAdverts().subscribe(val => {
this.dataSource = new MatTableDataSource<Card>(val);
this.dataSource.paginator = this.paginator;
this.dataSource.filterPredicate = (myObject: IFilter, filterString: any) => {
let filterObj: IFilter = JSON.parse(filterString);
if (!filterObj.provinceName.includes(myObject.provinceName) ||
!filterObj.vehicleMake.includes(myObject.vehicleMake) ||
!filterObj.vehicleModel.includes(myObject.vehicleModel) ||
!filterObj.vehicleYear.includes(myObject.vehicleYear) ||
!filterObj.vehicleColor.includes(myObject.vehicleColor))
{
return false;
}
else {
return true;
}
}
filter()//whenever triggered, it should do the filtering
{
this.myFilter.provinceName = this.search.value.provinceSelector;
this.myFilter.vehicleMake = this.search.value.makeSelector;
this.myFilter.vehicleModel = this.search.value.modelSelector;
this.myFilter.vehicleColor = this.search.value.colorSelector;
this.myFilter.vehicleYear = this.search.value.yearSelector;
if (this.myFilter.provinceName.length == 0 &&
this.myFilter.vehicleMake.length == 0 &&
this.myFilter.vehicleModel.length == 0 &&
this.myFilter.vehicleColor.length == 0 &&
this.myFilter.vehicleYear.length == 0) {
this.dataSource.filter = '';
}
else {
this.dataSource.filter = JSON.stringify(this.myFilter);
}
}
myFilter: IFilter = {
provinceName: [],
vehicleMake: [],
vehicleModel: [],
vehicleColor: [],
vehicleYear: []
}
interface IFilter{
provinceName:any[],
vehicleMake:any[],
vehicleModel:any[],
vehicleColor:any[],
vehicleYear:any[]
}
What it should do: Filter based on my query
What it does: Only does filtering as soon as all the values are filled.
You just have to check the filter attribute before if it exists and length is greater 0 and when then search for it in your object.
this.registeredUserService.GetAllAdverts().subscribe(val => {
this.dataSource = new MatTableDataSource<Card>(val);
this.dataSource.paginator = this.paginator;
this.dataSource.filterPredicate = (myObject: IFilter, filterString: any) => {
let filterObj: IFilter = JSON.parse(filterString);
if (
(filterObj.provinceName && filterObj.provinceName.length > 0 && !filterObj.provinceName.includes(myObject.provinceName)) ||
(filterObj.vehicleMake && filterObj.vehicleMake.length > 0 && !filterObj.vehicleMake.includes(myObject.vehicleMake)) ||
(filterObj.vehicleModel && filterObj.vehicleModel.length > 0 && !filterObj.vehicleModel.includes(myObject.vehicleModel)) ||
(filterObj.vehicleYear && filterObj.vehicleYear.length > 0 && !filterObj.vehicleYear.includes(myObject.vehicleYear)) ||
(filterObj.vehicleColor && filterObj.vehicleColor.length > 0 && !filterObj.vehicleColor.includes(myObject.vehicleColor))
) {
return false;
} else {
return true;
}
}
});
I'm already using snapToPoint so that connections are only possible on the constraints of a vertex. However currently I can connect multiple edges to the same connection point. Is there a built-in way to allow only one connection per connection point?
If no and as I'm new to mxGraph, is there any recommendation on where to put the code in order to get the desired behaviour, e.g. listening to mxEvent.CELL_CONNECTED or mxEvent.CONNECT_CELL? Or do I have to overwrite/reuse any predefined method like mxGraph.cellConnected?
had the same issue, wanting to limit the number of connections to a connection constraint.
I ended up removing connection constraints that already have an edge connected them
10-02-2021 update: found a better way:
graph.getAllConnectionConstraints = function (terminal) {
if (terminal != null && this.model.isVertex(terminal.cell)) {
// connection points: North, East, South, West
var allConnectionConstraints = [
new mxConnectionConstraint(new mxPoint(0.5, 0), true),
new mxConnectionConstraint(new mxPoint(1, 0.5), true),
new mxConnectionConstraint(new mxPoint(0.5, 1), true),
new mxConnectionConstraint(new mxPoint(0, 0.5), true)
];
let result = allConnectionConstraints;
// Remove the ones that have an edge connected to them
if (terminal.cell.edges) {
terminal.cell.edges.forEach((edge) => {
const edgeState = this.view.getState(edge);
const source = edge.source.id === terminal.cell.id;
const edgeConnectionConstraint = graph.getConnectionConstraint(
edgeState,
terminal,
source
);
// edgeConnectionConstraint does not include name property
const itemToDelete = result.find(
(item) =>
item.dx === edgeConnectionConstraint.dx &&
item.dy === edgeConnectionConstraint.dy &&
item.point.equals(edgeConnectionConstraint.point)
);
if (itemToDelete) {
result = result.filter((x) => x !== itemToDelete);
}
result.removeAll(
(item) =>
item.dx === edgeConnectionConstraint.dx &&
item.dy === edgeConnectionConstraint.dy &&
item.point.equals(edgeConnectionConstraint.point)
);
});
}
return result;
}
return null;
};
https://codesandbox.io/s/mxgraph-react-example-forked-uwru4
below is original post...
var graph = this.graph;
this.graph.getAllConnectionConstraints = function (terminal) {
if (terminal != null && this.model.isVertex(terminal.cell)) {
// connection points: North, East, South, West
var allConnectionConstraints = [new mxConnectionConstraint(new mxPoint(.5, 0), true),
new mxConnectionConstraint(new mxPoint(1, .5), true),
new mxConnectionConstraint(new mxPoint(.5, 1), true),
new mxConnectionConstraint(new mxPoint(0, .5), true)];
var result = [];
// loop through all connection constraints
allConnectionConstraints.forEach(connectionConstraint => {
var add = true;
// see if an edge is already connected to this constraint
if (terminal && terminal.cell && terminal.cell.edges) {
terminal.cell.edges.forEach(edge => {
var edgeStyle = graph.getCellStyle(edge);
var edgeX = -1;
var edgeY = -1;
// is this edge comming in or going out?
if (edge.source.id === terminal.cell.id) {
// going out
edgeX = edgeStyle.exitX;
edgeY = edgeStyle.exitY;
} else if (edge.target.id === terminal.cell.id) {
// comming in
edgeX = edgeStyle.entryX;
edgeY = edgeStyle.entryY;
}
if (connectionConstraint.point.x === edgeX &&
connectionConstraint.point.y === edgeY) {
// already a connection to this connectionConstraint, do not add to result
add = false;
}
});
}
if (add) {
result.push(connectionConstraint);
}
});
// return all connectionConstraints for this terminal that do not already have a connection
return result;
}
return null;
};
https://codesandbox.io/s/mxgraph-react-example-4ox9f
I need some help with my code. I want to make the str sprite invisible after 10 seconds.
I'm using this link for help: http://phaser.io/examples/v2/time/basic-timed-event
var game = new Phaser.Game(500, 550, Phaser.AUTO);
//var picture;
var Pacman = function (game) {
this.map = null;
this.layer = null;
this.pacman = null;
this.safetile = 14;
this.gridsize = 16;
this.speed = 100;
this.threshold = 3;
this.turnSpeed = 200;
this.marker = new Phaser.Point();
this.turnPoint = new Phaser.Point();
this.directions = [ null, null, null, null, null ];
this.opposites = [ Phaser.NONE, Phaser.RIGHT, Phaser.LEFT, Phaser.DOWN, Phaser.UP ];
this.current = Phaser.NONE;
this.turning = Phaser.NONE;
this.score=0;
this.scoreText='';
this.bonus=0;
this.bonusText='';
};
Pacman.prototype = {
init: function () {
this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
this.scale.pageAlignHorizontally = true;
this.scale.pageAlignVertically = true;
Phaser.Canvas.setImageRenderingCrisp(this.game.canvas);
this.physics.startSystem(Phaser.Physics.ARCADE);
},
preload: function () {
// We need this because the assets are on github pages
// Remove the next 2 lines if running locally
this.load.baseURL = 'https://nikosdaskalos.github.io/pacman/';
this.load.crossOrigin = 'anonymous';
this.load.image('str', 'assets/str.png');
this.load.image('dot', 'assets/dot.jpg');
this.load.image('coin', 'assets/coin.jpg');
this.load.image('tiles', 'assets/pacman-tiles.png');
this.load.spritesheet('pacman', 'assets/pacman.png');
this.load.tilemap('map', 'assets/pacman-map.json', null, Phaser.Tilemap.TILED_JSON);
// Needless to say, graphics (C)opyright Namco
},
create: function () {
this.map = this.add.tilemap('map');
this.map.addTilesetImage('pacman-tiles', 'tiles');
this.layer = this.map.createLayer('Pacman');
//picture = game.add.sprite(game.world.centerX, game.world.centerY, 'str');
//picture.anchor.setTo(0.5, 0.5);
//game.time.events.add(Phaser.Timer.SECOND * 4, fadePicture, this);
this.dots = this.add.physicsGroup();
this.map.createFromTiles(36, this.safetile, 'str', this.layer, this.dots);
this.map.createFromTiles(7, this.safetile, 'dot', this.layer, this.dots);
this.map.createFromTiles(35, this.safetile, 'coin', this.layer, this.dots);
// The dots will need to be offset by 6px to put them back in the middle of the grid
this.dots.setAll('x', 6, false, false, 1);
this.dots.setAll('y', 6, false, false, 1);
// Pacman should collide with everything except the safe tile
this.map.setCollisionByExclusion([this.safetile], true, this.layer);
// Position Pacman at grid location 14x17 (the +8 accounts for his anchor)
this.pacman = this.add.sprite((14 * 16) + 8, (17 * 16) + 8, 'pacman', 0);
this.pacman.anchor.set(0.5);
//this.pacman.animations.add('munch', [0, 1, 2, 1], 20, true);
this.physics.arcade.enable(this.pacman);
this.pacman.body.setSize(16, 16, 0, 0);
this.cursors = this.input.keyboard.createCursorKeys();
//this.pacman.play('munch');
this.move(Phaser.LEFT);
this.scoreText = game.add.text(0, 500, 'Score: 0', { fontSize: '34px Arial', fill: 'white' });
lives = game.add.group();
game.add.text(game.world.width - 340, 500, 'Lives : ', { fontSize: '34px Arial', fill: 'white' });
this.bonusText = game.add.text(360, 500, 'Bonus: 0', { fontSize: '20px Arial', fill: 'white' });
for (var i = 0; i < 3; i++)
{
var pacman = lives.create(game.world.width - 235 + (30 * i), 517, 'pacman');
pacman.anchor.setTo(0.5, 0.5);
pacman.angle = 90;
pacman.alpha = 0.4;
}
},
//function fadePicture() {
//game.add.tween(picture).to( { alpha: 0 }, 2000, Phaser.Easing.Linear.None, true);
//},
checkKeys: function () {
if (this.cursors.left.isDown && this.current !== Phaser.LEFT)
{
this.checkDirection(Phaser.LEFT);
}
else if (this.cursors.right.isDown && this.current !== Phaser.RIGHT)
{
this.checkDirection(Phaser.RIGHT);
}
else if (this.cursors.up.isDown && this.current !== Phaser.UP)
{
this.checkDirection(Phaser.UP);
}
else if (this.cursors.down.isDown && this.current !== Phaser.DOWN)
{
this.checkDirection(Phaser.DOWN);
}
else
{
// This forces them to hold the key down to turn the corner
this.turning = Phaser.NONE;
}
},
checkDirection: function (turnTo) {
if (this.turning === turnTo || this.directions[turnTo] === null || this.directions[turnTo].index !== this.safetile)
{
// Invalid direction if they're already set to turn that way
// Or there is no tile there, or the tile isn't index 1 (a floor tile)
return;
}
// Check if they want to turn around and can
if (this.current === this.opposites[turnTo])
{
this.move(turnTo);
}
else
{
this.turning = turnTo;
this.turnPoint.x = (this.marker.x * this.gridsize) + (this.gridsize / 2);
this.turnPoint.y = (this.marker.y * this.gridsize) + (this.gridsize / 2);
}
},
turn: function () {
var cx = Math.floor(this.pacman.x);
var cy = Math.floor(this.pacman.y);
// This needs a threshold, because at high speeds you can't turn because the coordinates skip past
if (!this.math.fuzzyEqual(cx, this.turnPoint.x, this.threshold) || !this.math.fuzzyEqual(cy, this.turnPoint.y, this.threshold))
{
return false;
}
// Grid align before turning
this.pacman.x = this.turnPoint.x;
this.pacman.y = this.turnPoint.y;
this.pacman.body.reset(this.turnPoint.x, this.turnPoint.y);
this.move(this.turning);
this.turning = Phaser.NONE;
return true;
},
move: function (direction) {
var speed = this.speed;
if (direction === Phaser.LEFT || direction === Phaser.UP)
{
speed = -speed;
}
if (direction === Phaser.LEFT || direction === Phaser.RIGHT)
{
this.pacman.body.velocity.x = speed;
}
else
{
this.pacman.body.velocity.y = speed;
}
// Reset the scale and angle (Pacman is facing to the right in the sprite sheet)
/* this.pacman.scale.x = 1;
this.pacman.angle = 0;
if (direction === Phaser.LEFT)
{
this.pacman.scale.x = -1;
}
else if (direction === Phaser.UP)
{
this.pacman.angle = 270;
}
else if (direction === Phaser.DOWN)
{
this.pacman.angle = 90;
}
this.current = direction;
},*/
this.add.tween(this.pacman).to( { angle: this.getAngle(direction) }, this.turnSpeed, "Linear", true);
this.current = direction;
},
getAngle: function (to) {
// About-face?
if (this.current === this.opposites[to])
{
return "180";
}
if ((this.current === Phaser.UP && to === Phaser.LEFT) ||
(this.current === Phaser.DOWN && to === Phaser.RIGHT) ||
(this.current === Phaser.LEFT && to === Phaser.DOWN) ||
(this.current === Phaser.RIGHT && to === Phaser.UP))
{
return "-90";
}
return "90";
},
eatDot: function (pacman, dot) {
dot.kill();
var audio = new Audio('assets/pacman_chomp.wav');
audio.play()
this.score+=10;
this.scoreText.text= 'Score: ' + this.score;
//setTimeout(audio.play(),2000);
if (this.dots.total === 0)
{
this.dots.callAll('revive');
}
},
/*function muteAudio() {
var audio = document.getElementById('audioPlayer');
if (audio.mute = false) {
document.getElementById('audioPlayer').muted = true;
}
else {
audio.mute = true
document.getElementById('audioPlayer').muted = false;
}
}*/
eatCoin: function(pacman,coin){//pente
coin.kill();
this.score+=20;
this.scoreText.text= 'Score: ' + this.score;
var audio = new Audio('assets/pacman_eatfruit.wav');
audio.play()
if(this.coins.total===0)
{
this.coins.callAll('revive');
}
},
eatStr: function(pacman,str){//pente
str.kill();
this.bonus+=100;
this.bonusText.text= 'Bonus: ' + this.bonus;
var audio = new Audio('assets/pacman_eatfruit.wav');
audio.play()
if(this.strs.total===0)
{
this.strs.callAll('revive');
}
},
update: function () {
this.physics.arcade.collide(this.pacman, this.layer);
this.physics.arcade.overlap(this.pacman, this.dots, this.eatDot, null, this);
this.physics.arcade.overlap(this.pacman, this.dots, this.eatCoin, null, this);
this.physics.arcade.overlap(this.pacman, this.dots, this.eatStr, null, this);
this.marker.x = this.math.snapToFloor(Math.floor(this.pacman.x), this.gridsize) / this.gridsize;
this.marker.y = this.math.snapToFloor(Math.floor(this.pacman.y), this.gridsize) / this.gridsize;
// Update our grid sensors
this.directions[1] = this.map.getTileLeft(this.layer.index, this.marker.x, this.marker.y);
this.directions[2] = this.map.getTileRight(this.layer.index, this.marker.x, this.marker.y);
this.directions[3] = this.map.getTileAbove(this.layer.index, this.marker.x, this.marker.y);
this.directions[4] = this.map.getTileBelow(this.layer.index, this.marker.x, this.marker.y);
this.checkKeys();
if (this.turning !== Phaser.NONE)
{
this.turn();
}
}
};
game.state.add('Game', Pacman, true);
</script>
</body>
</html>
So, can anyone help me with making the str invisible after 10 seconds?
You were pretty close.
I'm going to use pacman as an example, since I'm not 100% sure how you were going to fade out the coins. When Pacman eats them?
First, you want the following fadePicture function:
fadePicture: function() {
game.add.tween(this.pacman).to( { alpha: 0 }, 2000, Phaser.Easing.Linear.None, true);
},
Note how that was changed from function fadePicture().
Next, in your create function you can refer to it:
this.game.time.events.add(Phaser.Timer.SECOND * 4, this.fadePicture, this);
That replaces the following:
//game.time.events.add(Phaser.Timer.SECOND * 4, fadePicture, this);
I've created a JSFiddle with the relevant changes.
If you do want your coins to fade then I would try updating fadePicture to accept a dot/str parameter and then game.add.tween on that.
My Kendo Tree-view has many child nodes and sub nodes .Problem with getting sub child's nodes with redundant code
Here is my code .
nodes = rep.GetTreeViewData(CompanyId);
var productTreeData = nodes.Select(p => new
{
Text = p.CategoryName,
Url = p.ActionLink,
hasChildren = p.SubCategories.Any(),
// Expanded = true,
EntityType = p.EntityType,
Selected = currurl.ToLower() == p.ActionLink.ToLower() ? true : false,
ImageUrl = p.EntityType == "Company" ? "/Content/Images/company.gif" : "/Content/Images/geolocation1.gif",
Children = p.SubCategories.Select(c => new
{
Text = c.SubCategoryName,
Url = c.ActionLink,
// Expanded = true,
hasChildren = c.SubCategories.Any(),
EntityType = c.EntityType,
Selected = currurl.ToLower() == c.ActionLink.ToLower() ? true : false,
ImageUrl = c.EntityType == "Company" ? "/Content/Images/company.gif" : "/Content/Images/geolocation1.gif",
Children = c.SubCategories.Select(d => new
{
Text = d.SubCategoryName,
Url = d.ActionLink,
// Expanded = true,
hasChildren = d.SubCategories.Any(),
EntityType = d.EntityType,
Selected = currurl.ToLower() == d.ActionLink.ToLower() ? true : false,
ImageUrl = d.EntityType == "Company" ? "/Content/Images/company.gif" : "/Content/Images/geolocation1.gif",
Children = d.SubCategories.Select(f => new
{
Text = f.SubCategoryName,
Url = f.ActionLink,
//Expanded = true,
hasChildren = f.SubCategories.Any(),
EntityType = f.EntityType,
Selected = currurl.ToLower() == f.ActionLink.ToLower() ? true : false,
ImageUrl = f.EntityType == "Company" ? "/Content/Images/company.gif" : "/Content/Images/geolocation1.gif",
Children = f.SubCategories.Select(g => new
{
Text = g.SubCategoryName,
Url = g.ActionLink,
// Expanded = true,
hasChildren = g.SubCategories.Any(),
EntityType = g.EntityType,
Selected = currurl.ToLower() == g.ActionLink.ToLower() ? true : false,
ImageUrl = g.EntityType == "Company" ? "/Content/Images/company.gif" : "/Content/Images/geolocation1.gif",
})
})
})
})
});
This is my view
#(Html.Kendo().TreeView()
.Name("treeview-right")
.ExpandAll(true)
//.LoadOnDemand(false)
//.Events(events=>events.DataBound("DataBound"))
.DataSource(d => d
.Model(m => m
.HasChildren("hasChildren")
.Children("Children"))
.Read(r => r.Action("_ProductTree", "Home")))
.DataTextField("Text")
.DataUrlField("Url")
.DataImageUrlField("ImageUrl")
)
By this process am getting all child's and sub child's of individual parent up to four level hierarchy ..if i need another level i need to write one more children code.
Am struggling from 2 days to simplify this process .
Thanks
This looks like it could be solved with recursion. This should be pretty close.
var productTreeData = new ListofYourTreeViewModelHere();
foreach (var node in rep.GetTreeViewData(CompanyId))
{
productTreeData.Add(FillTree(node));
}
...
}
private YourTreeViewModelHere FillTree(p)
{
var tv = new YourTreeViewModelHere();
tv.Text = p.CategoryName,
tv.Url = p.ActionLink,
tv.hasChildren = p.SubCategories.Any(),
tv.EntityType = p.EntityType,
tv. Selected = currurl.ToLower() == p.ActionLink.ToLower() ? true : false,
tv.ImageUrl = p.EntityType == "Company" ? "/Content/Images/company.gif" : "/Content/Images/geolocation1.gif";
foreach(var sub in p.SubCategories)
{
tv.Children.Add(FillTree(x));
}
}
Impress.js supports a number of attributes:
data-x, data-y, data-z will move the slide on the screen in 3D space;
data-rotate, data-rotate-x, data-rotate-y rotate the element around the specified axis (in degrees);
data-scale – enlarges or shrinks the slide.
div id="intro" class="step" data-x="0" data-y="0">
<h2>Introducing Galaxy Nexus</h2>
<p>Android 4.0<br /> Super Amoled 720p Screen<br />
<img src="assets/img/nexus_1.jpg" width="232" height="458" alt="Galaxy Nexus" />
<!-- We are offsetting the second slide, rotating it and making it 1.8 times larger -->
<div id="simplicity" class="step" data-x="1100" data-y="1200" data-scale="1.8" data-rotate="190">
<h2>Simplicity in Android 4.0</h2>
<p>Android 4.0, Ice Cream Sandwich brings an entirely new look and feel..</p>
<img src="assets/img/nexus_2.jpg" width="289" height="535" alt="Galaxy Nexus" />
Impress.js
(function ( document, window ) {
'use strict';
// HELPER FUNCTIONS
var pfx = (function () {
var style = document.createElement('dummy').style,
prefixes = 'Webkit Moz O ms Khtml'.split(' '),
memory = {};
return function ( prop ) {
if ( typeof memory[ prop ] === "undefined" ) {
var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1),
props = (prop + ' ' + prefixes.join(ucProp + ' ') + ucProp).split(' ');
memory[ prop ] = null;
for ( var i in props ) {
if ( style[ props[i] ] !== undefined ) {
memory[ prop ] = props[i];
break;
}
}
}
return memory[ prop ];
}
})();
var arrayify = function ( a ) {
return [].slice.call( a );
};
var css = function ( el, props ) {
var key, pkey;
for ( key in props ) {
if ( props.hasOwnProperty(key) ) {
pkey = pfx(key);
if ( pkey != null ) {
el.style[pkey] = props[key];
}
}
}
return el;
}
var byId = function ( id ) {
return document.getElementById(id);
}
var $ = function ( selector, context ) {
context = context || document;
return context.querySelector(selector);
};
var $$ = function ( selector, context ) {
context = context || document;
return arrayify( context.querySelectorAll(selector) );
};
var translate = function ( t ) {
return " translate3d(" + t.x + "px," + t.y + "px," + t.z + "px) ";
};
var rotate = function ( r, revert ) {
var rX = " rotateX(" + r.x + "deg) ",
rY = " rotateY(" + r.y + "deg) ",
rZ = " rotateZ(" + r.z + "deg) ";
return revert ? rZ+rY+rX : rX+rY+rZ;
};
var scale = function ( s ) {
return " scale(" + s + ") ";
};
var getElementFromUrl = function () {
// get id from url # by removing `#` or `#/` from the beginning,
// so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work
return byId( window.location.hash.replace(/^#\/?/,"") );
};
// CHECK SUPPORT
var ua = navigator.userAgent.toLowerCase();
var impressSupported = ( pfx("perspective") != null ) &&
( document.body.classList ) &&
( document.body.dataset ) &&
( ua.search(/(iphone)|(ipod)|(android)/) == -1 );
var roots = {};
var impress = window.impress = function ( rootId ) {
rootId = rootId || "impress";
// if already initialized just return the API
if (roots["impress-root-" + rootId]) {
return roots["impress-root-" + rootId];
}
// DOM ELEMENTS
var root = byId( rootId );
if (!impressSupported) {
root.className = "impress-not-supported";
return;
} else {
root.className = "";
}
// viewport updates for iPad
var meta = $("meta[name='viewport']") || document.createElement("meta");
// hardcoding these values looks pretty bad, as they kind of depend on the content
// so they should be at least configurable
meta.content = "width=1024, minimum-scale=0.75, maximum-scale=0.75, user-scalable=no";
if (meta.parentNode != document.head) {
meta.name = 'viewport';
document.head.appendChild(meta);
}
var canvas = document.createElement("div");
canvas.className = "canvas";
arrayify( root.childNodes ).forEach(function ( el ) {
canvas.appendChild( el );
});
root.appendChild(canvas);
var steps = $$(".step", root);
// SETUP
// set initial values and defaults
document.documentElement.style.height = "100%";
css(document.body, {
height: "100%",
overflow: "hidden"
});
var props = {
position: "absolute",
transformOrigin: "top left",
transition: "all 0s ease-in-out",
transformStyle: "preserve-3d"
}
css(root, props);
css(root, {
top: "50%",
left: "50%",
perspective: "1000px"
});
css(canvas, props);
var current = {
translate: { x: 0, y: 0, z: 0 },
rotate: { x: 0, y: 0, z: 0 },
scale: 1
};
var stepData = {};
var isStep = function ( el ) {
return !!(el && el.id && stepData["impress-" + el.id]);
}
steps.forEach(function ( el, idx ) {
var data = el.dataset,
step = {
translate: {
x: data.x || 0,
y: data.y || 0,
z: data.z || 0
},
rotate: {
x: data.rotateX || 0,
y: data.rotateY || 0,
z: data.rotateZ || data.rotate || 0
},
scale: data.scale || 1,
el: el
};
if ( !el.id ) {
el.id = "step-" + (idx + 1);
}
stepData["impress-" + el.id] = step;
css(el, {
position: "absolute",
transform: "translate(-50%,-50%)" +
translate(step.translate) +
rotate(step.rotate) +
scale(step.scale),
transformStyle: "preserve-3d"
});
});
// making given step active
var active = null;
var hashTimeout = null;
var goto = function ( el ) {
if ( !isStep(el) || el == active) {
// selected element is not defined as step or is already active
return false;
}
// Sometimes it's possible to trigger focus on first link with some keyboard action.
// Browser in such a case tries to scroll the page to make this element visible
// (even that body overflow is set to hidden) and it breaks our careful positioning.
//
// So, as a lousy (and lazy) workaround we will make the page scroll back to the top
// whenever slide is selected
//
// If you are reading this and know any better way to handle it, I'll be glad to hear about it!
window.scrollTo(0, 0);
var step = stepData["impress-" + el.id];
if ( active ) {
active.classList.remove("active");
}
el.classList.add("active");
root.className = "step-" + el.id;
// `#/step-id` is used instead of `#step-id` to prevent default browser
// scrolling to element in hash
//
// and it has to be set after animation finishes, because in chrome it
// causes transtion being laggy
window.clearTimeout( hashTimeout );
hashTimeout = window.setTimeout(function () {
window.location.hash = "#/" + el.id;
}, 1000);
var target = {
rotate: {
x: -parseInt(step.rotate.x, 10),
y: -parseInt(step.rotate.y, 10),
z: -parseInt(step.rotate.z, 10)
},
translate: {
x: -step.translate.x,
y: -step.translate.y,
z: -step.translate.z
},
scale: 1 / parseFloat(step.scale)
};
// check if the transition is zooming in or not
var zoomin = target.scale >= current.scale;
// if presentation starts (nothing is active yet)
// don't animate (set duration to 0)
var duration = (active) ? "1s" : "0";
css(root, {
// to keep the perspective look similar for different scales
// we need to 'scale' the perspective, too
perspective: step.scale * 1000 + "px",
transform: scale(target.scale),
transitionDuration: duration,
transitionDelay: (zoomin ? "500ms" : "0ms")
});
css(canvas, {
transform: rotate(target.rotate, true) + translate(target.translate),
transitionDuration: duration,
transitionDelay: (zoomin ? "0ms" : "500ms")
});
current = target;
active = el;
return el;
};
var prev = function () {
var prev = steps.indexOf( active ) - 1;
prev = prev >= 0 ? steps[ prev ] : steps[ steps.length-1 ];
return goto(prev);
};
var next = function () {
var next = steps.indexOf( active ) + 1;
next = next < steps.length ? steps[ next ] : steps[ 0 ];
return goto(next);
};
window.addEventListener("hashchange", function () {
goto( getElementFromUrl() );
}, false);
window.addEventListener("orientationchange", function () {
window.scrollTo(0, 0);
}, false);
// START
// by selecting step defined in url or first step of the presentation
goto(getElementFromUrl() || steps[0]);
return (roots[ "impress-root-" + rootId ] = {
goto: goto,
next: next,
prev: prev
});
}
})(document, window);
// EVENTS
(function ( document, window ) {
'use strict';
// keyboard navigation handler
document.addEventListener("keydown", function ( event ) {
if ( event.keyCode == 9 || ( event.keyCode >= 32 && event.keyCode <= 34 ) || (event.keyCode >= 37 && event.keyCode <= 40) ) {
switch( event.keyCode ) {
case 33: ; // pg up
case 37: ; // left
case 38: // up
impress().prev();
break;
case 9: ; // tab
case 32: ; // space
case 34: ; // pg down
case 39: ; // right
case 40: // down
impress().next();
break;
}
event.preventDefault();
}
}, false);
// delegated handler for clicking on the links to presentation steps
document.addEventListener("click", function ( event ) {
// event delegation with "bubbling"
// check if event target (or any of its parents is a link)
var target = event.target;
while ( (target.tagName != "A") &&
(target != document.body) ) {
target = target.parentNode;
}
if ( target.tagName == "A" ) {
var href = target.getAttribute("href");
// if it's a link to presentation step, target this step
if ( href && href[0] == '#' ) {
target = document.getElementById( href.slice(1) );
}
}
if ( impress().goto(target) ) {
event.stopImmediatePropagation();
event.preventDefault();
}
}, false);
// delegated handler for clicking on step elements
document.addEventListener("click", function ( event ) {
var target = event.target;
// find closest step element
while ( !target.classList.contains("step") &&
(target != document.body) ) {
target = target.parentNode;
}
if ( impress().goto(target) ) {
event.preventDefault();
}
}, false);
// touch handler to detect taps on the left and right side of the screen
document.addEventListener("touchstart", function ( event ) {
if (event.touches.length === 1) {
var x = event.touches[0].clientX,
width = window.innerWidth * 0.3,
result = null;
if ( x < width ) {
result = impress().prev();
} else if ( x > window.innerWidth - width ) {
result = impress().next();
}
if (result) {
event.preventDefault();
}
}
}, false);
})(document, window);
My question is the Impress.js supposedly to process the data-x, data-y, data-scale attribute of the div tag. But I don't see where the code in Impress.js is doing that. Can someone point it out?
This intro to datasets may help.
First this part checking support for .dataset:
// CHECK SUPPORT
var ua = navigator.userAgent.toLowerCase();
var impressSupported = ( pfx("perspective") != null ) &&
( document.body.classList ) &&
( document.body.dataset ) &&
( ua.search(/(iphone)|(ipod)|(android)/) == -1 );
Then this part of the code, about halfway down:
steps.forEach(function ( el, idx ) {
var data = el.dataset,
step = {
translate: {
x: data.x || 0,
y: data.y || 0,
z: data.z || 0
},
rotate: {
x: data.rotateX || 0,
y: data.rotateY || 0,
z: data.rotateZ || data.rotate || 0
},
scale: data.scale || 1,
el: el
};