.addHitRegion() doesn't work in Chrome - javascript

I have the latest Chrome version and I see in specs that it should support .addHitRegion() method, as mentioned on MDN. For some reason I get Uncaught TypeError: context.addHitRegion is not a function error.
My code is as simple as this:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath();
context.rect(10,10,100,100);
context.fill();
context.addHitRegion({'id': 'The First Button', 'cursor': 'pointer'});
How do I fix it?

Go here with your browser: chrome://flags
and then
Set the flag Experimental Web Platform features to true to enable it.

As the other answers states, you can enable this through flags, however: you won't be able to ask your users to do the same. And the support is limited to a few browsers. I would therefor recommend looking to other solutions - I list some here:
A notch better approach is to use Path2D objects. They provide the same flexibility in terms of defining hit shapes. Use these with isPointInPath() which also takes a path object. Store each path in an array which you loop through using the position to test with. Unfortunately though, also this is limited to a few browsers, but you can at least use a poly-fill such as this to fix that to some extend (see notes in the link for limitations).
A better option perhaps in regards to support and availability, and the one requiring a bit more work, is to rebuild each single path you want to test on the context itself, then use as above the isPointInPath() to see if the mouse position is inside that path.
If the shapes are simple such as rectangles or circles, you can do simple mathematical tests which is a performant alternative.

So you need to set the experimental flag here
From The compatibility table at the bottom of the page you linked:
This feature is behind a feature flag. Set the flag
ExperimentalCanvasFeatures to true to enable it.
To turn on experimental canvas features browse to “chrome://flags“, turn on “Enable experimental canvas features” and relaunch.

Unfortunately the hit region feature is now obsolete and doesn't appear to be enable-able. You can use isPointInPath() as an alternative. You'll need to create a path object to be able to pass into that function. Something like:
const rectangle = new Path2D();
ctx.beginPath();
rectangle.rect(10, 10, 100, 100);
ctx.fill(rectangle);
...then to check, you could put it into an event listener:
canvas.addEventListener("mousemove", (e) => {
if (ctx.isPointInPath(rectangle, e.offsetX, e.offsetY)) {
console.log("rectangle is hit");
});

Related

Detect when Path2D with SVG path string is supported

It appears Microsoft Edge partially supports the Path2D API - it doesn't support the usage SVG path strings, i.e.,
const path = new Path2D('M20 L30');
Is there a way to feature detect whether or not passing in SVG paths is supported?
There is no catchable error that gets thrown in this case, and passing an invalid string does not throw either in supporting browsers. (This sounds like a specs flow to me btw...)
So to be able to detect this exact case of the constructor being supported, but the argument getting ignored, we have to actually check if something got drawn or not...
You can do so by stroking a simple M0,0H1 Path2D and then check if the pixel at coords 0,0 of you context has been painted.
function supports() {
// no simple support
if (typeof Path2D !== 'function') return false;
// create a new context
var x = document.createElement('canvas')
.getContext('2d');
// stroke a simple path
x.stroke(new Path2D('M0,0H1'));
// check it did paint something
return !!x.getImageData(0, 0, 1, 1).data[3];
};
console.log(supports());
But note that Edge does not seem to support either the Path2D.addPath() method, so if you include a polyfill like Google's canvas-5-polyfill which does include a Path2D polyfill, then the whole Path2D will use the polyfilled version (because they also check for addPath support).

How can I draw from ImageData to canvas with zoom in Haxe?

Well, I fill ScreenBuffer:ImageData 480x360 and then want to draw it to the canvas 960x720. The task is to decrease the fillrate; the nowadays pixels are very small and we can make them bigger with some quality loss. I look for the operator with 2D-accelaration. But we can't write directly to js.html.Image and ImageData hasn't link to js.html.Image. I found an example for pure JS:
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas
However, it doesn't want to work in Haxe because there isn't 'zoom' element. And there is some information about restrictions in HTML at copying from one image to another.
Many thanks for answers!
The compiler writes "js.html.Element has no field getContext"
getElementById()'s return type is the generic js.html.Element class. Since in your case, you know you're dealing with a <canvas>, you can safely cast it to the more specific CanvasElement. This then lets you call its getContext() method:
var canvas:CanvasElement = cast js.Browser.document.getElementById('zoom');
var zoomctx = canvas.getContext('2d');

Avoid cleaning canvas in updateOptions call

I am working in a signals plot program trying to simulate the 'persistence' feature as available in many oscilloscopes.
I would like to prevent dygraph canvas to clean for every updateOptions call. Instead of that, my plot should be preserved until an explicit call for cleaning. This feature will allow me to check if a signal preserves its phase during a certain amount of time.
I tried to use block_redraw parameter set to false in updateOptions function without no success.
Any ideas?
This isn't really something dygraphs is designed to do. You're asking it to render the full history of its data source, rather than the current state of its data source.
That being said, here's the code that clears the plotting canvas:
DygraphCanvasRenderer.prototype.clear = function() {
this.elementContext.clearRect(0, 0, this.width, this.height);
};
So if you override that, it might do what you want:
DygraphCanvasRenderer.prototype.clear = function() {};
That being said, this is liable to break lots of things (like zooming and panning) in addition to giving you the behavior you want. You can see this if you visit the live random data demo page and copy that snippet into the JS console.
Good luck!

Draw Polygon with GPolygon without GMap

Anyone know how I can draw Polygons with GPolygon from Google Map without having a map, inside other elements? Or anyone know any framework to do it with the same features like GPolygon?
I would like to have this "draw polygon" on a custom element, like div:
<div id="MyArea"></div>
Check out Raphael, a javascript library that wraps around VML in IE and SVG in standards compliant browsers. It's fairly easy to use and quite well documented.
Granted, the path element (used to draw polygon and polylines) uses the SVG path string syntax which is a bit cryptic but quite easy to understand. You can of course extend Raphael to use a more simple syntax:
Raphael.fn.polygon = function () { // supply x,y coordinates as arguments
var self = this.path();
self.coords = [];
for (var i=0;i<arguments.length;i++) self.coords.push(arguments[i]);
self.update = function () {
var pathlist = [];
// the M command moves the cursor:
pathlist.push('M'+self.coords[0]+' '+self.coords[1]);
// the L command draws a line:
pathlist.push('L');
// Now push the remaining coordinates:
for (var i=2;i<self.coords.length;i++) {
pathlist.push(self.coords[i]);
}
// the Z command closes the path:
pathlist.push('Z');
self.attr('path',pathlist.join(' '));
}
self.update();
return self;
}
Which should allow you to do:
<div id="MyArea"></div>
<script>
var paper = Raphael("MyArea",640,480);
var mypolygon = paper.polygon(
10, 10,
20, 20,
10, 30
);
// you can even modify it after creation:
mypolygon.coords.push(15,20);
mypolygon.update();
</script>
Or create your own polygon API to taste if you don't like mine.
EDIT: fixed some small bugs.
I agree with slebetman that Raphael is totally great. Note, however, that neither SVG nor VML is currently supported in the Android browser. Canvas with excanvas.js may be a better bet for cross-browser work, if you are also targeting Android.
Also, if you really want to use the Google Map API, you can simply hide the map. But you would still be stuck with the Google logo due to the Terms of Use.
You can do this by using a tile with a single color in v2, but I believe there are other ways do this in v3.
Example of the v2 method: http://fisherwebdev.com/california
Example of hiding some of the map features in v3: http://fisherwebdev.com/mapcolors -- You can use this same technique to hide all features.
Play around with this to see what is possible to hide/show or restyle in v3: http://gmaps-samples-v3.googlecode.com/svn/trunk/styledmaps/wizard/index.html

Best way to detect that HTML5 <canvas> is not supported

The standard way to deal with situations where the browser does not support the HTML5 <canvas> tag is to embed some fallback content like:
<canvas>Your browser doesn't support "canvas".</canvas>
But the rest of the page remains the same, which may be inappropriate or misleading. I'd like some way of detecting canvas non-support so that I can present the rest of my page accordingly. What would you recommend?
This is the technique used in Modernizr and basically every other library that does canvas work:
function isCanvasSupported(){
var elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
}
Since your question was for detection when it's not supported, I recommend using it like so:
if (!isCanvasSupported()){ ...
There are two popular methods of detecting canvas support in browsers:
Matt's suggestion of checking for the existence of getContext, also used in a similar fashion by the Modernizr library:
var canvasSupported = !!document.createElement("canvas").getContext;
Checking the existence of the HTMLCanvasElement interface, as defined by the WebIDL and HTML specifications. This approach was also recommended in a blog post from the IE 9 team.
var canvasSupported = !!window.HTMLCanvasElement;
My recommendation is a variation of the latter (see Additional Notes), for several reasons:
Every known browser supporting canvas ― including IE 9 ― implements this interface;
It's more concise and instantly obvious what the code is doing;
The getContext approach is significantly slower across all browsers, because it involves creating an HTML element. This is not ideal when you need to squeeze as much performance as possible (in a library like Modernizr, for example).
There are no noticeable benefits to using the first method. Both approaches can be spoofed, but this not likely to happen by accident.
Additional Notes
It may still be necessary to check that a 2D context can be retrieved. Reportedly, some mobile browsers can return true for both above checks, but return null for .getContext('2d'). This is why Modernizr also checks the result of .getContext('2d').  However, WebIDL & HTML ― again ― gives us another better, faster option:
var canvas2DSupported = !!window.CanvasRenderingContext2D;
Notice that we can skip checking for the canvas element entirely and go straight to checking for 2D rendering support. The CanvasRenderingContext2D interface is also part of the HTML specification.
You must use the getContext approach for detecting WebGL support because, even though the browser may support the WebGLRenderingContext, getContext() may return null if the browser is unable to interface with the GPU due to driver issues and there is no software implementation. In this case, checking for the interface first allows you to skip checking for getContext:
var cvsEl, ctx;
if (!window.WebGLRenderingContext)
window.location = "http://get.webgl.org";
else {
cvsEl = document.createElement("canvas");
ctx = cvsEl.getContext("webgl") || cvsEl.getContext("experimental-webgl");
if (!ctx) {
// Browser supports WebGL, but cannot create the context
}
}
##Performance Comparison
Performance of the getContext approach is 85-90% slower in Firefox 11 and Opera 11 and about 55% slower in Chromium 18.
    
I usually run a check for getContext when I create my canvas object.
(function () {
var canvas = document.createElement('canvas'), context;
if (!canvas.getContext) {
// not supported
return;
}
canvas.width = 800;
canvas.height = 600;
context = canvas.getContext('2d');
document.body.appendChild(canvas);
}());
If it is supported, then you can continue the canvas setup and add it to the DOM. This is a simple example of Progressive Enhancement, which I (personally) prefer over Graceful Degradation.
Why not try modernizr ? It's a JS library that provides detection capability.
Quote:
Have you ever wanted to do
if-statements in your CSS for the
availability of cool features like
border-radius? Well, with Modernizr
you can accomplish just that!
try {
document.createElement("canvas").getContext("2d");
alert("HTML5 Canvas is supported in your browser.");
} catch (e) {
alert("HTML5 Canvas is not supported in your browser.");
}
There may be a gotcha here- some clients do not support all canvas methods.
var hascanvas= (function(){
var dc= document.createElement('canvas');
if(!dc.getContext) return 0;
var c= dc.getContext('2d');
return typeof c.fillText== 'function'? 2: 1;
})();
alert(hascanvas)
You can use canisuse.js script to detect if your browsers supports canvas or not
caniuse.canvas()
If you're going to get the context of your canvas, you might as well use it as the test:
var canvas = document.getElementById('canvas');
var context = (canvas.getContext?canvas.getContext('2d'):undefined);
if(!!context){
/*some code goes here, and you can use 'context', it is already defined*/
}else{
/*oof, no canvas support :(*/
}

Categories

Resources