JointJS show message on validation Failed - javascript

I'm trying to show a toaster when the user tries to connect two elements that cannot be linked. The problem is JointJS calls the function validateConnection for all elements on the Graph when I start dragging the arrow not only when the arrow reaches the target, so I cannot place the toaster code there. I'm looking a way to check if a invalid connection attempt was done.
I know that I can listen to
paper.on('link:connect', function(linkView, evt, elementViewConnected, magnet, arrowhead) {console.log('Valid connection');});
But only to valid connections. Is there a way to get a invalid connection attempt?
My Paper:
const paper = this.paper = new rappid.joint.dia.Paper({
width: 1000,
height: 1000,
gridSize: 10,
drawGrid: true,
model: graph,
multiLinks: false,
linkPinning: false,
markAvailable: true,
perpendicularLinks: true,
defaultLink: function (cellView, magnet, link) {
return LinksService.getMyLink(cellView.model.attributes.link, data);
},
validateConnection: function (cellViewS, magnetS, cellViewT, magnetT, end) {
const idS = cellViewS.model.id;
const idT = cellViewT.model.id;
const links = appInstance.graph.getLinks();
if (flowContext.existsConnection(idS, idT, links)) {
return false;
}
return true;
},
});

validateConnection is used to prevent the user from creating invalid connections at all while they are interacting with the link. If you want to react to invalid connections (with a toast/message) you can use allowLink instead. (doc: https://resources.jointjs.com/docs/jointjs/v2.1/joint.html#dia.Paper.prototype.options.allowLink)

Related

iOS application fails to respond to mouse and touch events

I am developing an iOS application using Swift that incorporates web content by using WKWebView.
[URL Loading and Goal] Once a URL has been loaded inside this web view, I want to open a keyboard whenever the user wants to type.
[JavaScript Events] As browsing is based on eye coordinates, I want a JavaScript event to be triggered when the user's gaze is focused on an input field. On the basis of eye gaze coordinates, I can determine the underlying element of the webpage document. After this, I want to trigger a mouse event/touch event for clicks within the input element.
However, the system-level keyboard does not appear if I follow these steps.
Code:
touchPoint variable contains the current x and y coordinates of the eye gaze.
#IBOutlet var webView : WKWebView!
let jsStyle = """
function sendTouchEvent(x, y, element, eventType) {
const touchObj = new Touch({
identifier: Date.now(),
target: element,
clientX: x,
clientY: y,
radiusX: 2.5,
radiusY: 2.5,
rotationAngle: 10,
force: 0.5,
});
const touchEvent = new TouchEvent(eventType, {
cancelable: true,
bubbles: true,
touches: [touchObj],
targetTouches: [],
changedTouches: [touchObj],
shiftKey: true,
});
element.dispatchEvent(touchEvent);
}
function click(x, y)
{
var ev = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': true,
'screenX': x,
'screenY': y
});
var el = document.elementFromPoint(x, y);
if(el.nodeName == "INPUT") {
el.autofocus = true;
el.click();
el.focus();
sendTouchEvent(x, y, el, 'touchstart');
}
try {
el.dispatchEvent(ev);
} catch(error) {
console.log(error);
}
}
click(\(touchPoint.x), \(touchPoint.y));
"""
webView.evaluateJavaScript(jsStyle, completionHandler : { result, error in
print("### Evaluate JavaScript for current click!")
} => Called when eye gaze coordinates are received.
[Temporary Solution] In order to make this work, I created a native UITextField that acts as a proxy for the webpage element and opens the keyboard by becoming the first responder when I determine using JS that the eye gaze is focused on an input element.
My goal, however, is to remove the proxy logic and replace it with JavaScript code that opens the system-level keyboard.

quaggaJS: how to "pause" the decoder

I'm using quaggaJS (https://github.com/serratus/quaggaJS) to read barcodes in a web application. It works very well, and this is my initialization code:
Quagga.init({
inputStream: {
name: "Live",
type: "LiveStream",
constraints: {
width: 1280,
height: 720,
facingMode: "environment"
}
},
decoder: {
readers: ["code_39_reader"],
debug: {
drawBoundingBox: true,
showFrequency: false,
drawScanline: true,
showPattern: true
},
multiple: false
},
locator: {
halfSample: true,
patchSize: "medium"
}
}, function (err) {
if (err) {
alert(err);
return;
}
Quagga.registerResultCollector(resultCollector);
Quagga.start();
});
here the handling of the onDetected event:
Quagga.onDetected(function (data) {
Quagga.stop(); // <-- I want to "pause"
// dialog to ask the user to accept or reject
});
What does that mean?
When it recognize a barcode I need to ask the user if he wants to accept or reject the decoded value - and therefore repeat the process.
It would be nice to leave the captured image so he can actually see what he just captured.
Quagga.stop() works in most cases but it's not reliable because sometimes the canvas will turn black. I guess this is due the behavior of the stop() method:
the decoder does not process any more images. Additionally, if a camera-stream was requested upon initialization, this operation also disconnects the camera.
For this reason I'm looking for a way to pause the decoding, so the last frame is still there and the camera has not disconnected yet.
Any suggestion how to achieve this?
A better way to do it would be to first pause the video and then call Quagga.stop() so that the video element that Quagga creates for you will be paused and you don't see the blacked out image. Additionally, you can also have a restart/re-scan button to resume or rather restart the scanning process.
To get the view element you can do something like below:
Quagga.onDetected(function (result) {
var cameraFeed = document.getElementById("cameraFeedContainer")
cameraFeed.getElementsByTagName("video")[0].pause();
return;
});
You can get the image frame via Quagga.canvas.dom.image.
With that, you can overlay the videostream.
HTML
<div class="scanArea">
<div id="interactive" class="viewport"></div>
<div class="scanArea__freezedFrame"></div>
</div>
CSS
.scanArea {
position: relative;
}
.scanArea__freezedFrame {
position: absolute;
left: 0;
top: 0;
}
JavaScript
Quagga.onDetected(function(result) {
var canvas = Quagga.canvas.dom.image;
var $img = $('<img/>');
$img.attr("src", canvas.toDataURL());
$('.scanArea__freezedFrame').html($img);
});

Not able to make sprite interaction to work

I'm trying to build a simple game menu, containing some clickable sprites, which will be used as buttons to navigate around the menu.
( I'm using the latest pixi.js (v4.3.5) )
Structure of my app:
loader.module ( makes use of the pixi.loaders.Loader )
events.module (basic event sub/pub module)
base.view
menu.view ( extends base.view )
game.main
How it all works now ?
Both all resources and ui elements have to be explicitly defined, before initializing the view.
so in the menu.view, the follwoing attributes have to be defined.
this.resources = [
{ name: 'start', src: 'img/start.png'},
{ name: 'start2', src: 'img/start2.png'}
];
this.ui = [{
name: 'start', /// resource name
type: 'img',
pos: { x: 0, y: 0 }
}];
Now I only need to call view.init() to get it all loaded and drawn. On the visual side, evrything works perfectly, however the 'start' sprite (which has it's interactive and buttonMode set to true) is not reacting to any mouse events.
The below method is responsible for getting the required resource and returning a new sprite. It also enables the actual interaction functionality as part of this process. But the test function is never triggered for some reason.
__getSpriteObject( element ){
let sprite = new PIXI.Sprite( this.loader.loader.resources[ element.name ].texture );
sprite.x = element.pos.x;
sprite.y = element.pos.y;
sprite.interactive = true;
sprite.buttonMode = true;
console.log( sprite )
sprite.on('pointerdown', function(){
console.log("what")
})
return sprite;
}
If the above info isn't sufficient , here is also a working example.
I answered this here: http://www.html5gamedevs.com/topic/28474-not-able-to-make-sprite-interaction-to-work/?do=findComment&comment=163647 in any case anyone else is curious

Push my values to top of auto completion list in Ace editor

I'm using a custom completer that pulls values from a server using jQuery.getJSON.
My custom completions are showing up along with local and snippets and I'd like mine to always be at the top. I was thinking score would do that but not working like this. I'm giving score a value of 1000.
var langTools = ace.require("ace/ext/language_tools");
editor = ace.edit("editor");
editor.setOptions({
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
enableSnippets: true
});
var myCompleter = {
getCompletions: function(editor, session, pos, prefix, callback) {
if (prefix.length === 0) {
callback(null, []);
return;
}
$.getJSON("/server/completions", function(json) {
callback(null, json.map(function(c) {
return {value: c.value, caption: c.caption, meta: c.meta, score:c.score};
}));
})
}
};
langTools.addCompleter(myCompleter);
Any ideas? Thanks, /w
make sure completions you provide have higher score than default ones. default completers all give score 0, so something like {..., score:100 + (c.score || 0)}; should work
There is an additional processing on the score done in autocomplete.js (https://github.com/ajaxorg/ace/blob/4a55188fdb0eee9e2d3854f175e67408a1e47655/lib/ace/autocomplete.js#L488), based on a distance. What some ace plugins do (see for example https://github.com/ajaxorg/ace/blob/4a55188fdb0eee9e2d3854f175e67408a1e47655/lib/ace/mode/html_completions.js#L300) is set the score to Number.MAX_VALUE, and it works for me too: my completions appear on top of the list.

Check if element is not in an array to open a window

what I am doing here is some kind of a chat interface with your online and offline contacts which you can drag around the window. I m stuck trying to create a function to check if you already opened a chat window to avoid duplicated windows. This is the link of what i got so far. s2.enigmind.com/jgonzalez/nodeChat I hope you guys can see it.
This is the function in which I append the window elements this function get some parameters that i obtain from a JSON, the parameters are user id name and status.
function displayChatWindow(user, status, avatar, id){
var template = _.template($("#windowTemplate").html(), {userName: user, userStatus: status, userAvatar: avatar, userId: id});
stackingWidth = stackingWidth - boxWidth;
/*console.log(stackingWidth);*/
$("body").prepend(template);
$(".messages-container").slimScroll({
height: '200',
size: '10px',
position: 'right',
color: '#535a61',
alwaysVisible: false,
distance: '0',
railVisible: true,
railColor: '#222',
railOpacity: 0.3,
wheelStep: 10,
disableFadeOut: false,
start: "bottom"
});
$("#" + id).css({
top: absoluteY,
left: stackingWidth
});
$("#" + id).find(".minimize").on("click", displayOthersChat);
$(".chat input, .chat textarea").on("focus", cleanInputs);
$(".chat input, .chat textarea").on("blur", setInputs);
addWindow(id, stackingWidth);
}
what I have in my global scope is an array called var openedWindows = []; and in this array I am appending the user id and position with the addWindow function.
function addWindow(id, offset){
openedWindows.push({
id: id,
offset: offset
})
}
So far, every time i open a new window this one is added to the array, I've been using a for loop to see if the user and id is already in the array, but i don't actually know how to structure my code, because there is no way to check at the first time if the user is in the array because the array is empty, I will appreciate if you guys know how i could achieve this, I know my code is not the best, all this is for my learning purposes so i accept all kind of tips! Thank you very much.
you are already using underscore.js , so why not use its _.each() function to loop over all entries in openedWindows:
function addWindow(id, offset) {
var found = false;
_.each(openedWindows, function(el, idx) {
// 'el' is an item in openedWindows, and 'idx' is its position in the array
if (el.id === id) {
found = true;
}
});
if (found === false) {
openedWindows.push({
id: id,
offset: offset
});
}
}

Categories

Resources