Is there any way we can position the borderless window in the file neutralino.config.json?
like : "borderless": { ...args }
or any other ways?
Now it just starts at somewhere random and cannot be moved
You can call Neutralino.window.move(x,y) in your javascript. (0,0) is the (leftmost,top) of the screen. You can find other window functions at https://neutralino.js.org/docs/api/window.
As an extension of your question, and like Klauss A's instinct suggests, you can call Neutralino.window.setDraggableRegion('id-of-element') where id-of-element is, as the name suggests, an id of an element in your html. Then, when you click and drag that element, Neutralino will automatically call Neutralino.window.move(x,y). setDraggableRegion() is not in the docs, but you can see it in the tutorial they made on YouTube, and it is still in the code.
The thing is, how Neutralino does this is by posting a message to the server, which adds quite a bit of delay, causing the drag to stutter. Here is the relevant code snippet in a prettified version of the neutralino.js file:
...
t.move = function(e, t) {
return r.request({
url: "window.move",
type: r.RequestType.POST,
isNativeMethod: !0,
data: {
x: e,
y: t
}
})
}, t.setDraggableRegion = function(e) {
return new Promise(((t, i) => {
let r = document.getElementById(e),
o = 0,
u = 0;
function s(e) {
return n(this, void 0, void 0, (function*() {
yield Neutralino.window.move(e.screenX - o, e.screenY - u)
}))
}
r || i(`Unable to find dom element: #${e}`), r.addEventListener("mousedown", (e => {
o = e.clientX, u = e.clientY, r.addEventListener("mousemove", s)
})), r.addEventListener("mouseup", (() => {
r.removeEventListener("mousemove", s)
})), t()
}))
}
...
I suspected this formulation of adding to the lag, since function* is a generator, and thus is inherently untrustworthy (citation needed). I re-wrote it in plain javascript, and reduced some of the lag. It still stutters, just not as much.
var dragging = false, posX, posY;
var draggableElement = document.getElementById('id-of-element');
draggableElement.onmousedown = function (e) {
posX = e.pageX, posY = e.pageY;
dragging = true;
}
draggableElement.onmouseup = function (e) {
dragging = false;
}
document.onmousemove = function (e) {
if (dragging) Neutralino.window.move(e.screenX - posX, e.screenY - posY);
}
I hope this helps. I was digging around in all this because the caption bar (aka, title bar) of the window is different from my system's color theme. I thought, "maybe I'll create my own title bar in HTML, with CSS styling to match my app." But due to the stuttering issues, I find it is better to have a natively-draggable title bar that doesn't match anything. I'm still digging around in the Neutralino C++ code to see if I could modify it and add a non-client rendering message handler (on Windows), to color the title bar the same as my app and still have nice smooth dragging. That way it would look "borderless" but still be movable.
I am having the same problem. My naive instinct is telling me that probably could be a way to create a custom element bar and use a function upon click& drag to move the window around.
Moving Windows in Neutralino is Quite Simple.
You can use the Neutralino.window API to move the windows.
Example:
Neutralino.window.move(x, y);
here x and y are the Coordinates on which our window will move to.
Note the this moves the window from the Top Left Corner of the window.
I have made this Neutralino Template - NeutralinoJS App With Custom Titlebar which might be useful if you are making a custom titlebar for your application.
Related
Basically the problem is that after you rotate the camera, the points that are given as arguments in the callback for dragging are not what I expected. I'm guessing I have to Rotate the given points also but I just couldn't.
Can Someone explain what is going on, is this some kind of bug or what should I do in order the sprite to follow the mouse cursor?
Easiest way to explain the problem is to reproduce it:
1) Go to Phaser Example Runner
2) Copy- Paste this code:
var config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: {
preload: preload,
create: create
}
};
var game = new Phaser.Game(config);
function preload ()
{
this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
}
function create ()
{
var image = this.add.sprite(200, 300, 'eye').setInteractive();
this.cameras.main.setRotation(Math.PI);
image.on('pointerover', function () {
this.setTint(0x00ff00);
});
image.on('pointerout', function () {
this.clearTint();
});
this.input.setDraggable(image);
this.input.on('dragstart', function (pointer, gameObject) {
gameObject.setTint(0xff0000);
});
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
console.log(`x: ${dragX}, y: ${dragY}`);
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', function (pointer, gameObject) {
gameObject.clearTint();
});
}
3) Open the console, drag around the Eye and look at what coordinates are given.
4) If you remove line 24 (the rotation of the camera) Everything works as expected.
(The example is taken from Phaser 3 Official examples and a bit changed for the bug)
According to Phaser's API Documentation on the setRotation() method, the rotation given in radians applies to everything rendered by the camera. Unfortunately, your pointer isn't rendered by the camera so it doesn't get the same rotated coordinates. Not sure if this is a bug with the library or just a poorly documented exception, but I believe there is a workaround.
Create 2 variables to hold an initial position and a final position:
var image = this.add.sprite(200, 300, 'eye').setInteractive();
var initial = [];
var final = [];
Populate the initial position in your .on('dragstart') method:
this.input.on('dragstart', function (pointer, gameObject) {
initial = [
gameObject.x,
gameObject.y,
pointer.x,
pointer.y
];
gameObject.setTint(0xff0000);
});
Then, populate the final variable in your .on('drag') method:
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
final = [
gameObject.x, // not necessary but keeping for variable shape consistency
gameObject.y, // not necessary but keeping for variable shape consistency
pointer.x,
pointer.y
];
gameObject.x = initial[0] + (initial[2] - final[2]);
gameObject.y = initial[1] + (initial[3] - final[3]);
});
All we're doing here is keeping track of the change in pointer position and mimicking that change in our gameObject.
I need make an App that has about 30k Objects, a user can Pan, Zoom or "Select on click" any of those objects.
Fabric.js Canvas is being used
I have done the same using SVG's and the svg-pan-zoom plugin (no Canvas Element) with better results
Problem: there is a significant Lag while Zooming, Panning or Object on Click
will removing Fabric.js improve performance?
will switching to WebGL improve performance?
Have tried Fabric specific options
fabric.Object.prototype.objectCaching = false;
fabric.Object.prototype.statefullCache = false;
fabric.Object.prototype.noScaleCache = true;
fabric.Object.prototype.needsItsOwnCache = false;
UPDATE
Heres the updated Fiddle
for reference :
canvas-vs-svg-vs-div Stackoverflow
Stackoverflow
Don't Render in IO EVENTS!
Though not a complete fix to the update speed this answer will about double the interaction speed.
A common, almost standard, mistake made with mouse and event interaction with the canvas (and DOM) is to delegate rendering to mouse/touch events. This is very bad practice as mouse events fire at much higher rates than the display can display. It becomes worse when your rendering time is high as you queue up mouse events (pseudo render events) and do a re render for every movement of the mouse
Note blocking code will stop mouse events but as soon as the engine is idle the mouse will start firing at full rate again.
Use the mouse events just to get the mouse state. Use an animation loop that is synced to the display to render only when needed and there is time available. Things like the wheel and mouse movement deltas should be recorded cumulatively.
mouse.dx += event.movementX;
mouse.dy += event.movementY;
mouse.wheel += event.wheelDelta;
And consume them in the main render loop...
function update(){
// ... code to use mouse
// consume deltas
mouse.x = mouse.y = mouse.wheel = 0;
...this ensures that the mouse state is accurately followed when you may have many mouse events between render updates.
Example, separating events from rendering.
Change you code in the fiddle you provided to the following, on my machine it about doubled the rendering speed (which is still very slow).
// from just after the function applyZoom replace all the code
var mouse = { // holds the mouse state
x : 0,
y : 0,
down : false,
w : 0,
delta : new fabric.Point(0,0),
}
// event just track mouse state
function zoom(e) {
if(e != null) { e.preventDefault() }
var evt=window.event || e;
mouse.x = e.offsetX;
mouse.y = e.offsetY;
mouse.w += evt.detail? evt.detail*(-120) : evt.wheelDelta;
return false;
}
canvas.on('mouse:up', function (e) { mouse.down = false });
canvas.on('mouse:out', function (e) { mouse.down = false });
canvas.on('mouse:down', function (e) { mouse.down = true });
canvas.on('mouse:move', function(e) {
if (e && e.e) {
mouse.delta.x += e.e.movementX;
mouse.delta.y += e.e.movementY;
}
});
// main animation loop
function update(){
if(mouse.w !== 0){ // if the wheel has moved do zoom
var curZoom = canvas.getZoom();
canvas.zoomToPoint(
{ x : mouse.x, y: mouse.y },
canvas.getZoom() + mouse.w / 4000
);
mouse.w = 0; // consume wheel delta
}else if(mouse.down) { // if mouse button down
canvas.relativePan(mouse.delta);
}
// consume mouse delta
mouse.delta.x = 0;
mouse.delta.y = 0;
requestAnimationFrame(update);
}
requestAnimationFrame(update);
I am trying to work out a way to add a text to the top left corner of the viewport when two of my sprites overlap. One of them is an item and the other is my character. I can already detect for overlap and even "pick" the item (kill the sprite) when I click a key. However I would like that a text saying something like "Click "E" to pick the sword!" appeared while the collision function is active and when I kill the sprite by picking it up the text would vanish.
I tried including the text in the collision function itself but I suppose this way I am rendering the text multiple times (the fps drops a lot) and I just want to create it once and remove it according to my purposes. My code:
function collisionHandler(dude,the_sword) {
pickObject.onDown.add(function () {
the_sword.kill();
}, this);
}
game.physics.isoArcade.overlap(dude, the_sword, collisionHandler, null, this);
// message saying to pick // Where to put this?
var style = { font: "30px Arial", fill: "#ff0044"};
var pick_message = this.game.add.text(0,20,"Click 'E' to pick up the sword!",style);
pick_message.fixedToCamera = true;
Any idea on how to do this?
In your 'create' function:
var style = { font: "30px Arial", fill: "#ff0044"};
var pick_message = this.game.add.text(0,20,"Click 'E' to pick up the sword!",style);
pick_message.fixedToCamera = true;
pick_message.visible = false;
Then:
function collisionHandler(dude,the_sword) {
pick_message.visible = true;
pickObject.onDown.add(function () {
the_sword.kill();
pick_message.visible = false;
}, this);
}
game.physics.isoArcade.overlap(dude, the_sword, collisionHandler, null, this);
Something like that should work. If you want to perform other action, like opening the door, you can use:
pick_message.setText("Click 'Q' to open the door!");
You don't have to create new text evertime, you can use one for different purposes.
I am trying to zoom and pan a text which is draggable already. All the examples are on images or shapes and it seems I cannot adapt it to a text object. My questions are:
Do I have to use the anchors or is any simpler way zoom a text with Kineticjs?
I found an example regarding zooming a shape and the code crashes here:
var layer = new Kinetic.Layer({
drawFunc : drawTriangle //drawTriangle is a function defined already
});
Can we call a function while we are creating a layer?
I usually create a layer and then add the outcome of the function in it.
Any idea would be great, thanks.
I thought of many ways you could do this but this is the one I ended up implementing: jsfiddle
Basically, you have an anchor (which doesn't always have to be there, you can hide and show it if you would like. Let me know if you need help with that) and if you drag the anchor down it increases the fontSize, and if you drag the anchor up it decreases the fontSize.
I followed the exact same anchor tutorial but instead I added a dragBoundFunc to limit dragging to the Y-axis:
var anchor = new Kinetic.Circle({
x: x,
y: y,
stroke: '#666',
fill: '#ddd',
strokeWidth: 2,
radius: 8,
name: name,
draggable: true,
dragOnTop: false,
dragBoundFunc: function (pos) {
return {
x: this.getAbsolutePosition().x,
y: pos.y
};
}
});
And then I updated the updateAnchor() function to only detect the single anchor I added to the group named sizeAnchor:
var mY = 0;
function update(activeAnchor, event) {
var group = activeAnchor.getParent();
var sizeAnchor = group.get('.sizeAnchor')[0];
var text = group.get('.text')[0];
if (event.pageY < mY) {
text.setFontSize(text.getFontSize()-1);
} else {
text.setFontSize(text.getFontSize()+1);
}
sizeAnchor.setPosition(-10, 0);
mY = event.pageY;
}
Basically mY is used compared to the e.PageY to see if the mouse is moving up or down. Once we can determine the mouse direction, then we can decide if we should increase or decrease the fontSize!
Alternatively, you can use the mousewheel to do the exact same thing! I didn't implement it myself but it's definitely doable. Something like:
Mousewheel down and the fontSize decreases
Mousewheel up and the fontSize increases
Hopefully this emulates "Zooming" a text for you. And I guess being able to drag the text acts as "panning" right?
UPDATE (based on comment below)
This is how you would limit dragging to the Y-Axis using dragBoundFunc:
var textGroup = new Kinetic.Group({
x: 100,
y: 100,
draggable: true,
dragBoundFunc: function (pos) {
return {
x: this.getAbsolutePosition().x,
y: pos.y
};
}
});
See the updated jsfiddle (same jsfiddle as above)
I'm using Raphael Free Transform plugin to enable scaling, dragging and rotating.
In this particular scenario I want to devote one handle for resizing and another one for rotating, hence scale option is set only on axis x. I want to compensate scaling on y axis by correcting it on function callback to avoid 'image' distortions.
I would like to enable user to re-size raphael set using one handle and rotate raphael set using another one. Also, I would like to persist all transformation caused by scaling so it is not lost once user attempt o drag the objects.
var ft = paper.freeTransform(tmp, { scale: ['axisX'], rotate: ['axisY'] }, cbFreeTransform);
function cbFreeTransform(s, e) {
if (e.toString() == 'scale end') {
for (var i = 0, l = tmp.length; i < l; i++) {
var itm = tmp[i];
itm.scale(1, s.attrs.scale.x);
}
}
}
Here is fiddle: jsFiddle
Any help appreciated .
Found the solution in doing following:
On 'Scale End' event I've assigned x scale factor to y scale factor and call free transform apply method. That seems to work.
var ft = paper.freeTransform(tmp, { scale: ['axisX'], rotate: ['axisY'] }, cbFreeTransform);
function cbFreeTransform(s, e) {
if (e.toString() == 'scale end') {
ft.attrs.scale.y = s.attrs.scale.x;
ft.apply();
}
}