Draw Polygon with GPolygon without GMap - javascript

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

Related

Detect when user reaches maxBounds using Leaflet

I am using leaflet to show an interactive map to our users.
We want to let them browse through a limited area, and inform them they have to subscribe in case they want to see something too far away (using a pop up or equivalent).
So far I have seen that Leaflet supports a maxBounds option.
This is a good start that lets me prevent users to see larger areas.
Now I would like to be able to detect a maxBounds 'event' to show the user a pop up.
I have been looking into the Leaflet source code, but couldn't find an obvious way to do it.
so far I have found that the maxBounds option is fed into the setView method.
This method itself uses the _limitCenter method to define the center.
This goes a few levels deeper, down to the _getBoundsOffset method that finally uses the bounds.
_getBoundsOffset: function (pxBounds, maxBounds, zoom) {
var projectedMaxBounds = toBounds(
this.project(maxBounds.getNorthEast(), zoom),
this.project(maxBounds.getSouthWest(), zoom)
),
minOffset = projectedMaxBounds.min.subtract(pxBounds.min),
maxOffset = projectedMaxBounds.max.subtract(pxBounds.max),
dx = this._rebound(minOffset.x, -maxOffset.x),
dy = this._rebound(minOffset.y, -maxOffset.y);
return new Point(dx, dy);
},
The closest I could find so far would be to hook into the moveend event and check whether the center is out of my bounds manually.
However, it seems like this would be redundant with what leaflet is already doing.
Is there a better to leverage leaflet to achieve this?
Thanks
Just check if your defined bounds contain the map bounds. As long as the map bounds are inside the defined bounds, this will do nothing:
var myBounds = L.latLngBounds(...)
map.on('move moveend zoomend', function(){
if (!myBounds.contains(map.getBounds())) {
// Display popup or whatever
}
});
it seems like this would be redundant with what leaflet is already doing.
Don't worry about that. The overhead is negligible for this use case.

Sprite animations in paper.js

I'm working on my project in Paper.js.
In the part of It, I need to use sprite with animation.
To examplain It, I've got a space ship that can be everywhere on the screen, and there is an effect of disortion that happens sometimes.
I got prepared a spritesheet with 10 frames, and all I want is use Paper.js RASTER class to load It and animate on every frame.
The problem is in the positions, that I don't know how to calculate them...
When I load a raster
let slide = new Raster({
source: 'assets/sprite.png',
position: [0, 0]
});
I see center of a very long image, when I need to see the first frame.
My idea was to use group with containts mask (square)
let mask = new Rectangle({
position: [220, 100],
size: [186, 154],
});
That I can change position dynamically and animate the spread at the same time.
Is It possible that way?
It would be cool, If I cant calculate the position of raster against the mask, but for me now It seems impossible.
Anyone have idea how to attain this in a simple way?
Cheers.
I've looked into this in my project. The key is using a group with a pivot point. This code is admittedly unfinished and in raw javascript but it should give you a good idea:
var Sprite = paper.Group.extend({
_class: 'Sprite',
initialize: function Sprite(url, size) {
var maskSize = size || new paper.Size(256, 256);
var that = this;
this._raster = new paper.Raster(url);
this._raster.pivot = new paper.Point();
this._raster.on('load', function () {
that._spriteSheetWidth = Math.floor(this.size.width / maskSize.width);
that.setIndex(that._spriteIndex || 0);
});
this._clipRect = new paper.Path.Rectangle(new paper.Point(), maskSize);
Sprite.base.call(this, [this._clipRect, this._raster]);
this.clipped = true;
// Just use a blank point if you want the position to be in the corner
this.pivot = new paper.Point(maskSize.divide(2));
},
setIndex: function (index) {
if (typeof this._spriteSheetWidth !== "undefined") {
// TODO: FINISH SPRITE SHEET IMPLEMENTATION
}
this._spriteIndex = index;
}
});
I'm not actually using sprites in my project anymore so I never finished the implementation. But the complicated concepts should be completed above. Namely the way that paper.js implements pivot points and clipping masks. The position of an object is the center of it's bounds by default... this is kind of unweildy for a lot of reasons, like an images position will appear to change when it loads etc... or when the contents of a path change. So I like to set a pivot of 0,0 immediately after making any object. The next key section is that clipping masks only work on Groups. And finally you can extend the Group class to make a standard Sprite class.
Normal sprite shifting of this._raster.position.x and this._raster.position.y should finish this implementation off.
Edit: Finished my implementation... https://jsfiddle.net/willstott101/vgxq9kak/

.addHitRegion() doesn't work in Chrome

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");
});

Raphael.js function getBBox give back NAN/NAN/NAN in IE8

using Raphaël 2.1.4 - JavaScript Vector Library
do something like that:
var textDummy = paper.text(50,500, 'hello world').attr({fill: 'transparent', 'font-size': 14});
var textBox = textDummy.getBBox();
with chrome and firefox everything is fine,
but in IE8 it give back NaN/NaN/NaN,
par exemple textBox.height is NaN.
how i can fix this?
i found a workaround solution from this answer to the question
"Raphael JS and Text positioning"
If i use _getBBox() instead of getBBox() everything is working in ie 8 also.
_getBBox() is undocumented but used internally by Raphael itself, and it works!
I had the same problem in Rapahel 2.2.0 and 2.2.1, and using ._getBBox() didn't fix it for me.
What did fix it for me is falling back to .auxGetBBox() if it's defined and regular .getBBox() doesn't work, like this:
var bbox = path.getBBox( );
// Workaround for apparent bug in Raphael's VML module's getBBox() override
if( isNaN( bbox.x ) && path.auxGetBBox ){
bbox = path.auxGetBBox();
}
I don't have a fix for the underlying bug, but I have found the source of it.
In VML mode, Raphael takes the initial getBBox() function, saves it as auxGetBBox() on the element prototype, then replaces it with a function that appears to be broken.
It has calculations based on a variable defined as var z = 1/this.paper._viewBoxShift.scale;, which clearly expects _viewBoxShift.scale to be some factor of the scale of the current viewbox compared to the initial viewbox , but actually _viewBoxShift.scale is an object like this which appears to come from paperproto.getSize():
{ height: someNumber, width: someNumber }
This is where all the NaNs are coming from. Cannae divide by an object.
So this workaround works fine if no zoom is applied using a viewbox, but may give incorrect results if a zoom has been applied (something I can't get to work at all in recent versions of raphael in VML mode, but that's a seperate question). Fixing that will involve digging deep into Raphael's VML module to pipe a proper zoom factor into this z variable.

SVG to HTML map and area

I have been trying to convert map in SVG to HTML area map for three days. I`am trying to do that with this SVG.
I've tried to convert this SVG with several methods and programs, but all of them failed.
e.g.: inkscape, inkscapeMap, Adobe Illustrator, Polygonator, SVGtoHTML and more.
So I wrote my own PHP script to do the job. Its works fine, but it converts only polygons. But there are two paths in SVG which need to be convert to polygon as well. I've tried to convert these paths into polygons in Illustrator and Inkscape, but apparently there is no way how to force these programs to convert path into polygons. (SVG editors probably decide alone, if they do the conversion or not). I find this topic on SO. But I'am not able to get the JS work - I dont know what the param sample is, and more - browser said that function createElementNS is unknown.
The best result I'am able to reach is this HTML, but there is still two region missing (because they are in SVG in paths)
I would be pleased for any clue.
QUESTIONS
1) How to transform SVG paths into polygons? Is that possible?
2) Is there any software which converts SVG into HTML area maps?
3) Could you show my example parametrs, in this JS function (function written Phrogz):
function polygonSampledFromPath(path,samples){
var doc = path.ownerDocument;
var poly = doc.createElementNS('http://www.w3.org/2000/svg','polygon');
var points = [];
var len = path.getTotalLength();
var step = step=len/samples;
for (var i=0;i<=len;i+=step){
var p = path.getPointAtLength(i);
points.push( p.x+','+p.y );
}
poly.setAttribute('points',points.join(' '));
return poly;
}
3ad) Why is function createElementNS unknown?
PS: I hope you understand my English :)

Categories

Resources