So I am very new to javascript and web development in general. I am trying to make it so that when you hover over text a small text box pops up with a paragraph in it. The problem is that I need to add " in the text however when I do that the script doesn't work as it recognizes " as part of the code.
I am using nhpup popups to do that nhpopup site
This is what I am trying to add " to
/*
--------------------------------------------------------------------------
Code for link-hover text boxes
By Nicolas Höning
Usage: <a onmouseover="nhpup.popup('popup text' [, {'class': 'myclass', 'width': 300}])">a link</a>
The configuration dict with CSS class and width is optional - default is class .pup and width of 200px.
You can style the popup box via CSS, targeting its ID #pup.
You can escape " in the popup text with ".
Tutorial and support at http://nicolashoening.de?twocents&nr=8
--------------------------------------------------------------------------
The MIT License (MIT)
Copyright (c) 2014 Nicolas Höning
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
nhpup = {
pup: null, // This is the popup box, represented by a div
identifier: "pup", // Name of ID and class of the popup box
minMargin: 15, // Set how much minimal space there should be (in pixels)
// between the popup and everything else (borders, mouse)
default_width: 500, // Will be set to width from css in document.ready
move: false, // Move it around with the mouse? we are only ready for that when the mouse event is set up.
// Besides, having this turned off initially is resource-friendly.
/*
Write message, show popup w/ custom width if necessary,
make sure it disappears on mouseout
*/
popup: function(p_msg, p_config)
{
// do track mouse moves and update position
this.move = true;
// restore defaults
this.pup.removeClass()
.addClass(this.identifier)
.width(this.default_width);
// custom configuration
if (typeof p_config != 'undefined') {
if ('class' in p_config) {
this.pup.addClass(p_config['class']);
}
if ('width' in p_config) {
this.pup.width(p_config['width']);
}
}
// Write content and display
this.pup.html(p_msg).show();
// Make sure popup goes away on mouse out and we stop the constant
// positioning on mouse moves.
// The event obj needs to be gotten from the virtual
// caller, since we use onmouseover='nhpup.popup(p_msg)'
var t = this.getTarget(arguments.callee.caller.arguments[0]);
$jq(t).unbind('mouseout').bind('mouseout',
function(e){
nhpup.pup.hide();
nhpup.move = false;
}
);
},
// set the target element position
setElementPos: function(x, y)
{
// Call nudge to avoid edge overflow. Important tweak: x+10, because if
// the popup is where the mouse is, the hoverOver/hoverOut events flicker
var x_y = this.nudge(x + 10, y);
// remember: the popup is still hidden
this.pup.css('top', x_y[1] + 'px')
.css('left', x_y[0] + 'px');
},
/* Avoid edge overflow */
nudge: function(x,y)
{
var win = $jq(window);
// When the mouse is too far on the right, put window to the left
var xtreme = $jq(document).scrollLeft() + win.width() - this.pup.width() - this.minMargin;
if(x > xtreme) {
x -= this.pup.width() + 2 * this.minMargin;
}
x = this.max(x, 0);
// When the mouse is too far down, move window up
if((y + this.pup.height()) > (win.height() + $jq(document).scrollTop())) {
y -= this.pup.height() + this.minMargin;
}
return [ x, y ];
},
/* custom max */
max: function(a,b)
{
if (a>b) return a;
else return b;
},
/*
Get the target (element) of an event.
Inspired by quirksmode
*/
getTarget: function(e)
{
var targ;
if (!e) var e = window.event;
if (e.target) targ = e.target;
else if (e.srcElement) targ = e.srcElement;
if (targ.nodeType == 3) // defeat Safari bug
targ = targ.parentNode;
return targ;
},
onTouchDevice: function()
{
var deviceAgent = navigator.userAgent.toLowerCase();
return deviceAgent.match(/(iphone|ipod|ipad|android|blackberry|iemobile|opera m(ob|in)i|vodafone)/) !== null;
},
initialized: false,
initialize : function(){
if (this.initialized) return;
window.$jq = jQuery; // this is safe in WP installations with noConflict mode (which is default)
/* Prepare popup and define the mouseover callback */
jQuery(document).ready(function () {
// create default popup on the page
$jq('body').append('<div id="' + nhpup.identifier + '" class="' + nhpup.identifier + '" style="position:absolute; display:none; z-index:200;"></div>');
nhpup.pup = $jq('#' + nhpup.identifier);
// set dynamic coords when the mouse moves
$jq(document).mousemove(function (e) {
if (!nhpup.onTouchDevice()) { // turn off constant repositioning for touch devices (no use for this anyway)
if (nhpup.move) {
nhpup.setElementPos(e.pageX, e.pageY);
}
}
});
});
this.initialized = true;
}
};
if ('jQuery' in window) nhpup.initialize();
<a onmouseover="nhpup.popup('Action Relating to or affecting the fundamental nature of something; far-reaching or thorough. This is what we offer at Rad Surfing Bali. We provide the most radical way of learning how to surf.');" href='#'>Radical.</a>
Please help me add a " to the text in the html script.
Regards,
Kraz
You should escape '' chars with \.
Like this
<a onmouseover="nhpup.popup('Action Relating to or affecting the fundamental nature of something; far-reaching or thorough. This is what we offer at \'Rad Surfing Bali\'. We provide the most radical way of learning how to surf.');" href='#'>Radical.</a>
Here is working example https://jsfiddle.net/xkj66svc/
Related
I am trying to run a method whenever the screenX or screenY position of a rendered window changes. I have set up a a default value for these positions in my data section here:
data() {
return {
initialX: window.screenX,
initialY: window.screenY
};
},
I have computed properties here:
currentPopupX() {
return window.screenX;
},
currentPopupY() {
return window.screenY;
}
},
Finally, I have a watch set up here:
watch: {
currentPopupX() {
if (this.currentPopupX !== this.initialX) {
movePopup(this.popup, this.currentPopupX, this.currentPopupY);
}
},
currentPopupY() {
if (this.currentPopupY !== this.initialY) {
movePopup(this.popup, this.currentPopupX, this.currentPopupY);
}
},
However the computed property seems to only return on initial render and does not update after that. Is there something I am missing?
I have tried comparing initial data to computed properties in the watch expecting for the method to be executed on change, however it never changes.
Note:
The rendered window is a popup notification. A user wants to drag that notification to a new location (currently it renders in the center of the screen) and have that popup render in the position they dragged it to the next time it is rendered. For additional context, I'm trying to grab the new positions to pass them along to an IPC event.
At my opinion, you have to use an interval to detect the browser position since there's no window move event.
if the browser position.x or the browser position.y change, you may dispatch a custom event.
The event here when you move the window will change the color of the text from black to red.
const event = new CustomEvent("browserMove",{ detail: "browserPosition" });
window.addEventListener("browserMove", onBrowserMove);
let moveTimer=null;
let content=null;
let oldX = 0;
let oldY = 0;
document.addEventListener("DOMContentLoaded",onReady);
function onReady(e){
content = document.getElementById("content");
oldX = window.screenX;
oldY = window.screenY;
moveTimer = setInterval(detectBrowserMove,200);
}
function detectBrowserMove(){
let r = browserPosition();
if(r.x !== oldX || r.y !== oldY){
// dispatch an event here
window.dispatchEvent(event);
oldX = window.screenX;
oldY = window.screenY;
}
content.innerHTML = ("browser.x = " + r.x + ", browser.y = " + r.y);
}
function browserPosition() {
let position={};
position = {x:window.screenX, y:window.screenY};
return(position);
}
function onBrowserMove(e){
// write your code here
let x = window.screenX;
let y = window.screenY;
content.style.color="#ff0000";
}
<div id="content">
</div>
If I catch your problem correctly, you are saying that-
A notification window will open in the center by default. The user can
drag it anywhere and when next time the notification window will appear, it should pop up at the position where the user last dragged it.
If we take the problem in some other way, you need the last dragged position of the window to send to the API for the next time opening. So, instead of checking the window's position every time why not check for only the last/latest position before it closes?
What I mean is-
Let the notification window open.
Attach a unload listener to it.
Drag it anywhere you want multiple times.
When the window is about to close, look into the listener, and grab the latest position.
Here is how you can do it in Vue-
Create a window data variable in your Vue and assign your newly opened window object to it-
data() {
return {
// Save notification window object to this data property
vue_window: null;
}
}
Apply a watcher that when vue_window has some value, set a listener to it-
watch: {
vue_window(newVal) {
// Only if vue_window variable has some value
if (newVal) {
// this will fire when the window is about to close
newVal.onunload = () => {
// Here are the latest screen positions of the window
console.log(this.vue_window.screenX, this.vue_window.screenY);
};
}
},
},
That's it. When the window will be about to close, you will have the last and latest position of the window which you can save wherever you want.
Here is the demo of this logic- CodeSandBox Link
I couldn't create a snippet because the window is not opening in the snippet environment. I will add the snippet if found any solution to work with the window obj.
I currently have a giant table of "auditpoints", some of those points are "automated". If they are automated they receive a gear icon in their row. The gear icon is not the only icon each row receives. Each row, no matter if it's automated or not receives two other icons, a pencil and a toggle button. When an automated point "runs" the gear icon rotates until it is finished "running". I've have implemented some code to ran all of these points at once but I have a small problem. When you click my button to run all these points all three of the icons I have mentioned rotate and this is not the result I am looking for. The line commented out in my code snippet (and it's matching bracket) will prevent the code from running all of the automated points. Commenting out the line is what causes all the icons to rotate. I know this line is required to get the automated points to run properly as it used in the single execution of automated points I just don't know what to change it to. It obviously shouldn't be click because you are no longer clicking the gear icon to get a point to run I just don't know what to change it to but the classes in that click function are related to the gear icon.
Hopefully this is a very easy question to solve and doesn't waste anyone's time. Thank you!
private updateAuto() {
var self = this;
$(".auditPointRow").each(function () {
//self.el.on("click", ".update, .edit", function () {
var row = $(this).closest(".auditPointRow");
var id = row.data("id");
var automated = (<string>row.data("automated")).toLowerCase() == "true";
var running = true;
if (automated && $(this).closest(".edit").length == 0) {
var gear = $(this).find(".fa");
var maxTurns = 120;
gear.css("transition", "transform linear " + maxTurns * 2 + "s");
gear.css("transform", "rotate(" + (maxTurns * 360) + "deg)");
var request = $.ajax(self.root + "api/sites/" + self.site.ID + "/auditpoints/" + id, {
"type": "PATCH", data: JSON.stringify([
{
Op: "Replace"
, Path: "/score"
, Value: "run"
}
])
});
request.done(function () {
gear.css("transition", "").css("transform", "rotate(0deg)");
row.prev().find("td").css("background-color", "");
if (row.prev().qtip("api")) {
row.prev().qtip("api").destroy(true);
}
});
}
//}
});
}
I think I found a solution to my problem. I used .each again to go through all of the "gears" and only rotate them.
private updateAuto() {
var self = this;
//$(".auditPointRow").each(function () {
$(".update, .edit").each(function () {
//Left out the rest of the code so this answer isn't too
//long, none of it changed if that matters.
});
//});
}
For some reason the result runs very slowly (but it runs!) and I'm not sure why so if anyone has any better suggestion/optimizations please feel free to leave those here.
Edit: I realized I didn't to go through .each twice, that's what was slowing to down so I removed that first each that went over auditPoints and just did the ones with gears instead.
I am using PaperJS to make a canvas app that generates balloons with text inside each balloon. However I would like to allow the user to edit the text inside each balloon to whatever they want it to say.
Is it possible to allow a user to edit a PaperJS TextItem just like a HTML text input field?
The short answer is no, unless you implement parallel functionality from scratch. The solution I have used is to let the user draw a rectangle then overlay the rectangle on the canvas with a textbox or textarea at the same location using absolute positioning. It requires an additional level of abstraction but can work quite well.
It's non-trivial, but here's a basic framework that shows a bit about how it works. I may get around to making it available online at some point but it will take a bit so I'm not sure when. I'm also extracting this on-the-fly from a larger system so if you spot any errors let me know.
var rect;
var tool = new paper.Tool();
// create a paper rectangle. it's just a visual indicator of where the
// text will go.
tool.onMouseDown = function(e) {
rect = new paper.Path.Rectangle(
from: e.downPoint,
to: e.downPoint,
strokeColor: 'red',
);
}
tool.onMouseDrag = function(3) {
if (rect) {
rect.remove();
}
rect = new paper.path.Rectangle({
from: e.downPoint,
to: e.point,
strokeColor: 'red'
});
}
tool.onMouseUp = function(e) {
var bounds = rect.bounds;
var textarea = $("<textarea class='dynamic-textarea' " +
"style='position:absolute; left:" + bounds.x +
"px; top:" + bounds.y + "px; width: " + bounds.width +
"px; height: " + bounds.height +
"px; resize;' placeholder='Enter text'></textarea>");
// make the paper rectangle invisible for now. may want to show on
// mouseover or when selected.
rect.visible = false;
// add the text area to the DOM then remember it in the path
$("#parent-div").append(textarea);
rect.data.textarea = textarea;
// you may want to give the textarea focus, assign tab indexes, etc.
};
I have a code which drags a line from (x,y) co-ordinate to new mouse (x,y) co-ordinate. This works fine in desktop browsers, but for some reason it doesn't work in mobile browsers. I have added touch event listeners but I guess the co-ordinates are some how getting incorrect. Heres my code:
function getMouse(e) {
var element = canvas, offsetX = 0, offsetY = 0;
if (element.offsetParent) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
mx = (e.pageX - offsetX) - LINE_WIDTH;
my =( e.pageY - offsetY )- LINE_WIDTH;
}
function mouseDown(e){
getMouse(e);
clear(fctx);
var l = lines.length;
for (var i = l-1; i >= 0; i--) {
draw(fctx,lines[i]);
var imageData = fctx.getImageData(mx, my, 1, 1);
if (imageData.data[3] > 0) {
selectedObject = lines[i];
isDrag = true;
canvas.onmousemove = drag;
clear(fctx);
}
}
}
function mouseUp(){
isDrag = false;
}
canvas.onmousedown = mouseDown;
canvas.onmouseup = mouseUp;
canvas.addEventListener('touchstart', mouseDown, false);
canvas.addEventListener('touchend', mouseUp, false);
you can see the working part here: http://codepen.io/nirajmchauhan/pen/yYdMJR
Generating mouse events from touch events
OK seen this question up here for a while and no one is coming forward with an answer I will give one.
Touch events unlike mouse events involve many points of contact with the UI. To accommodate this the touch events supply an array of touchpoints. As a mouse can not be in two places at once the two interaction methods should really be handled separately for the best user experience. OP as you do not ask about detecting if the device is touch or mouse driven, I have left that for another person to ask.
Handling Both
Mouse and Touch events can coexist. Adding listeners for mouse or touch events on a device that does no have one or the other is not an issue. The missing input interface simply does not generate any events. This makes it easy to implements a transparent solution for your page.
It comes down to which interface you prefer and emulating that interface when the hardware for it is unavailable. In this case I will emulate the mouse from any touch events that are created.
Creating events programmatically.
The code uses the MouseEvent object to create and dispatch events. It is simple to use and the events are indistinguishable from real mouse events. For a detailed description of MouseEvents goto MDN MouseEvent
At its most basic.
Create a mouse click event and dispatch it to the document
var event = new MouseEvent( "click", {'view': window, 'bubbles': true,'cancelable': true});
document.dispatchEvent(event);
You can also dispatch the event to individual elements.
document.getElementById("someButton").dispatchEvent(event);
To listen to the event it is just the same as listening to the actual mouse.
document.getElementById("someButton").addEventListener(function(event){
// your code
));
The second argument in the MouseEvent function is where you can add extra information about the event. Say for example clientX and clientY the position of the mouse, or which or buttons for which button/s is being pressed.
If you have ever looked at the mouseEvent you will know there are a lot of properties. So exactly what you send in the mouse event will depend on what your event listener is using.
Touch events.
Touch events are similar to the mouse. There is touchstart, touchmove, and touchend. They differ in that they supply a array of locations, one item for each point of contact. Not sure what the max is but for this answer we are only interested in one. See MDN touchEvent for full details.
What we need to do is for touch events that involve only one contact point we want to generate corresponding mouse events at the same location. If the touch event returns more than one contact point, we can not know which their intended focus is on so we will simply ignore them.
function touchEventHandler(event){
if (event.touches.length > 1){ // Ignor multi touch events
return;
}
}
So now we know that the touch a single contact we can go about creating the mouse events based on the information in the touch events.
At its most basic
touch = event.changedTouches[0]; // get the position information
if(type === "touchmove"){
mouseEventType = "mousemove"; // get the name of the mouse event
// this touch will emulate
}else
if(type === "touchstart"){
mouseEventType = "mousedown"; // mouse event to create
}else
if(type === "touchend"){
mouseEventType = "mouseup"; // ignore mouse up if click only
}
var mouseEvent = new MouseEvent( // create event
mouseEventType, // type of event
{
'view': event.target.ownerDocument.defaultView,
'bubbles': true,
'cancelable': true,
'screenX':touch.screenX, // get the touch coords
'screenY':touch.screenY, // and add them to the
'clientX':touch.clientX, // mouse event
'clientY':touch.clientY,
});
// send it to the same target as the touch event contact point.
touch.target.dispatchEvent(mouseEvent);
Now your mouse listeners will receive mousedown, mousemove, mouseup events when a user touches the device at only one location.
Missing the click
All good so far but there is one mouse event missing, that is needed as well. "onClick" I am not sure if there is a equivilant touch event and just as an exercise I saw there is enough information in what we have to decide if a set of touch events could be considered a click.
It will depend on how far apart the start and end touch events are, more than a few pixels and its a drag. It will also depend on how long. (Though not the same as a mouse) I find that people tend to tap for click, while a mouse can be held, in lieu of conformation on the release, or drag away to cancel, this is not how people use the touch interface.
So I record the time the touchStart event happens. event.timeStamp and where it started. Then at the touchEnd event I find the distance it has moved and the time since. If they are both under the limits I have set I also generate a mouse click event along with the mouse up event.
So that is the basics way to convert touch events into mouse events.
Some CODE
Below is a tiny API called mouseTouch that does what I have just explained. It covers the most basic mouse interactions required in a simple drawing app.
// _______ _
// |__ __| | |
// _ __ ___ ___ _ _ ___ ___| | ___ _ _ ___| |__
// | '_ ` _ \ / _ \| | | / __|/ _ \ |/ _ \| | | |/ __| '_ \
// | | | | | | (_) | |_| \__ \ __/ | (_) | |_| | (__| | | |
// |_| |_| |_|\___/ \__,_|___/\___|_|\___/ \__,_|\___|_| |_|
//
//
// Demonstration of a simple mouse emulation API using touch events.
// Using touch to simulate a mouse.
// Keeping it clean with touchMouse the only pubic reference.
// See Usage instructions at bottom.
var touchMouse = (function(){
"use strict";
var timeStart, touchStart, mouseTouch, listeningElement, hypot;
mouseTouch = {}; // the public object
// public properties.
mouseTouch.clickRadius = 3; // if touch start and end within 3 pixels then may be a click
mouseTouch.clickTime = 200; // if touch start and end in under this time in ms then may be a click
mouseTouch.generateClick = true; // if true simulates onClick event
// if false only generate mousedown, mousemove, and mouseup
mouseTouch.clickOnly = false; // if true on generate click events
mouseTouch.status = "Started."; // just for debugging
// ES6 new math function
// not sure the extent of support for Math.hypot so hav simple poly fill
if(typeof Math.hypot === 'function'){
hypot = Math.hypot;
}else{
hypot = function(x,y){ // Untested
return Math.sqrt(Math.pow(x,2)+Math.pow(y,2));
};
}
// Use the new API and MouseEvent object
function triggerMouseEvemt(type,fromTouch,fromEvent){
var mouseEvent = new MouseEvent(
type,
{
'view': fromEvent.target.ownerDocument.defaultView,
'bubbles': true,
'cancelable': true,
'screenX':fromTouch.screenX,
'screenY':fromTouch.screenY,
'clientX':fromTouch.clientX,
'clientY':fromTouch.clientY,
'offsetX':fromTouch.clientX, // this is for old Chrome
'offsetY':fromTouch.clientY,
'ctrlKey':fromEvent.ctrlKey,
'altKey':fromEvent.altKey,
'shiftKey':fromEvent.shiftKey,
'metaKey':fromEvent.metaKey,
'button':0,
'buttons':1,
});
// to do.
// dispatch returns cancelled you will have to
// add code here if needed
fromTouch.target.dispatchEvent(mouseEvent);
}
// touch listener. Listens to Touch start, move and end.
// dispatches mouse events as needed. Also sends a click event
// if click falls within supplied thresholds and conditions
function emulateMouse(event) {
var type, time, touch, isClick, mouseEventType, x, y, dx, dy, dist;
event.preventDefault(); // stop any default happenings interfering
type = event.type ; // the type.
// ignore multi touch input
if (event.touches.length > 1){
if(touchStart !== undefined){ // don't leave the mouse down
triggerMouseEvent("mouseup",event.changedTouches[0],event);
}
touchStart = undefined;
return;
}
mouseEventType = "";
isClick = false; // default no click
// check for each event type I have the most numorus move event first, Good practice to always think about the efficancy for conditional coding.
if(type === "touchmove" && !mouseTouch.clickOnly){ // touchMove
touch = event.changedTouches[0];
mouseEventType = "mousemove"; // not much to do just move the mouse
}else
if(type === "touchstart"){
touch = touchStart = event.changedTouches[0]; // save the touch start for dist check
timeStart = event.timeStamp; // save the start time
mouseEventType = !mouseTouch.clickOnly?"mousedown":""; // mouse event to create
}else
if(type === "touchend"){ // end check time and distance
touch = event.changedTouches[0];
mouseEventType = !mouseTouch.clickOnly?"mouseup":""; // ignore mouse up if click only
// if click generator active
if(touchStart !== undefined && mouseTouch.generateClick){
time = event.timeStamp - timeStart; // how long since touch start
// if time is right
if(time < mouseTouch.clickTime){
// get the distance from the start touch
dx = touchStart.clientX-touch.clientX;
dy = touchStart.clientY-touch.clientY;
dist = hypot(dx,dy);
if(dist < mouseTouch.clickRadius){
isClick = true;
}
}
}
}
// send mouse basic events if any
if(mouseEventType !== ""){
// send the event
triggerMouseEvent(mouseEventType,touch,event);
}
// if a click also generates a mouse click event
if(isClick){
// generate mouse click
triggerMouseEvent("click",touch,event);
}
}
// remove events
function removeTouchEvents(){
listeningElement.removeEventListener("touchstart", emulateMouse);
listeningElement.removeEventListener("touchend", emulateMouse);
listeningElement.removeEventListener("touchmove", emulateMouse);
listeningElement = undefined;
}
// start adds listeners and makes it all happen.
// element is optional and will default to document.
// or will Listen to element.
function startTouchEvents(element){
if(listeningElement !== undefined){ // untested
// throws to stop cut and past useage of this example code.
// Overwriting the listeningElement can result in a memory leak.
// You can remove this condition block and it will work
// BUT IT IS NOT RECOGMENDED
throw new ReferanceError("touchMouse says!!!! API limits functionality to one element.");
}
if(element === undefined){
element = document;
}
listeningElement = element;
listeningElement.addEventListener("touchstart", emulateMouse);
listeningElement.addEventListener("touchend", emulateMouse);
listeningElement.addEventListener("touchmove", emulateMouse);
}
// add the start event to public object.
mouseTouch.start = startTouchEvents;
// stops event listeners and remove them from the DOM
mouseTouch.stop = removeTouchEvents;
return mouseTouch;
})();
// How to use
touchMouse.start(); // done using defaults will emulate mouse on the entier page
// For one element and only clicks
// HTML
<input value="touch click me" id="touchButton" type="button"></input>
// Script
var el = document.getElementById("touchButton");
if(el !== null){
touchMouse.clickOnly = true;
touchMouse.start(el);
}
// For drawing on a canvas
<canvas id="touchCanvas"></canvas>
// script
var el = document.getElementById("touchButton");
if(el !== null){
touchMouse.generateClick = false; // no mouse clicks please
touchMouse.start(el);
}
// For switching elements call stop then call start on the new element
// warning touchMouse retained a reference to the element you
// pass it with start. Dereferencing touchMouse will not delete it.
// Once you have called start you must call stop in order to delete it.
// API
//---------------------------------------------------------------
// To dereference call the stop method if you have called start . Then dereference touchMouse
// Example
touchMouse.stop();
touchMouse = undefined;
// Methods.
//---------------------------------------------------------------
// touchMouse.start(element); // element optional. Element is the element to attach listeners to.
// Calling start a second time without calling stop will
// throw a reference error. This is to stop memory leaks.
// YOU Have been warned...
// touchMouse.stop(); // removes listeners and dereferences any DOM objects held
//---------------------------------------------------------------
// Properties
// mouseTouch.clickRadius = 3; // Number. Default 3. If touch start and end within 3 pixels then may be a click
// mouseTouch.clickTime = 200; // Number. Default 200. If touch start and end in under this time in ms then may be a click
// mouseTouch.generateClick; // Boolean. Default true. If true simulates onClick event
// // if false only generate mousedown, mousemove, and mouseup
// mouseTouch.clickOnly; // Boolean. Default false. If true only generate click events Default false
// mouseTouch.status; // String. Just for debugging kinda pointless really.
So hope that helps you with your code.
I have an HTML5 canvas based Javascript component that needs to capture and release mouse events. In the control the user clicks an area inside it and drags to affect a change. On PC I would like the user to be able to continue dragging outside of the browser and for the canvas to receive the mouse up event if the button is released outside of the window.
However, according to my reading setCapture and releaseCapture aren't supported on Chrome.
Is there a workaround?
An article written in 2009 details how you can implement cross-browser dragging which will continue to fire mousemove events even if the user's cursor leaves the window.
http://news.qooxdoo.org/mouse-capturing
Here's the essential code from the article:
function draggable(element) {
var dragging = null;
addListener(element, "mousedown", function(e) {
var e = window.event || e;
dragging = {
mouseX: e.clientX,
mouseY: e.clientY,
startX: parseInt(element.style.left),
startY: parseInt(element.style.top)
};
if (element.setCapture) element.setCapture();
});
addListener(element, "losecapture", function() {
dragging = null;
});
addListener(document, "mouseup", function() {
dragging = null;
}, true);
var dragTarget = element.setCapture ? element : document;
addListener(dragTarget, "mousemove", function(e) {
if (!dragging) return;
var e = window.event || e;
var top = dragging.startY + (e.clientY - dragging.mouseY);
var left = dragging.startX + (e.clientX - dragging.mouseX);
element.style.top = (Math.max(0, top)) + "px";
element.style.left = (Math.max(0, left)) + "px";
}, true);
};
draggable(document.getElementById("drag"));
The article contains a pretty good explanation of what's going on, but there are a few gaps where knowledge is assumed. Basically (I think), in Chrome and Safari, if you handle mousemove on the document then, if the user clicks down and holds the mouse, the document will continue receiving mousemove events even if the cursor leaves the window. These events will not propagate to child nodes of the document, so you have to handle it at the document level.
Chrome supports setPointerCapture, which is part of the W3C Pointer events recommendation. Thus an alternative would be to use pointer events and these methods.
You might want to use the jquery Pointer Events Polyfill to support other browsers.