We have a web application that displays a SVG map of an office. The map has small icons that represent users walking around with RF tags. This allows administrators of the system to see what rooms users are in. We are using Snap.SVG to load the office SVG file and manipulate it to display the user icons. The challenge is that the map scales to the size of the browser. Using JavaScript to determine the coordinates is not always accurate because the position of the SVG changes based on the browser size.
Here is an example of the map with the icons:
The icons are placed on the map based on X Y coordinates coming from our database. The values for the X Y coordinates are set for each location and were determined using Adobe Illustrator. Currently, we can only place one icon in a room at a time. Because we only have 1 set coordinates the icons overlap if more than one person is in a room at one time.
The second phase of this project is to allow users to draw on of the map to specify locations. Essentially, the user will set points and create a polygon to represent each location on the map. We would use the coordinates of the polygon along with the total area of the polygon to know where on the map we can place icons. This would allow users to define areas without a developer getting involved.
Here is an example of what we want to achieve .
I have been researching how to do this, but have not found anything outside of using something like the Google Maps API to draws polygons on a map. I did find this article that outlines how to dynamically pull points. We thought about using a grid system that is an overlay on the map and the user defines what grid elements are in what locations. So something like [A1,A2,B1,B2]. I persoanlly like the polygon approach as it is more visually appealing and is easier for a user to adopt.
We need some advice on where to start with this and if something like snap.svg is all we need or if we have to rely on other libraries in conjunction with snap.
Update:
With Ian's advice I found a fiddle that describes what he was talking about.
var S;
var pt;
var svg
var box;
window.onload = function(){
svg = $('#mysvg')[0];
S = Snap(svg);
console.log( S );
pt = pt = svg.createSVGPoint(); // create the point
// add the rectangle
box = S.rect(12,12, 12, 12);
box.attr({ fill : 'red', stroke : 'none' });
S.drag(
function(dx, dy, posX, posY, e){
//onmove
pt.x = posX - S.node.offsetLeft;
pt.y = posY - S.node.offsetTop;
console.log(pt.x + "," + pt.y);
// convert the mouse X and Y
//so that it's relative to the svg element
var transformed = pt.matrixTransform(svg.getCTM().inverse());
box.attr({ x : transformed.x, y : transformed.y });
},
function(){
//onstart
},
function(){
//onend
}
);
}
The Fiddle
Related
I'm trying to do something that seems simple, but not sure how it's not working. I have a map layer and I'm trying to draw circles via Extendscript. I'm trying to test just by trying to draw a simple circle at point 100,100 (I assume top left of map is 0,0), but when I execute it, the circle appears way further down than it should be (seems close to 200,700). Below is my code I'm using...
var dotRadius = 8.136 / 2;
var testDOT = mapLayer.pathItems.ellipse(100, 100, dotRadius*2, dotRadius*2, false, false);
testDOT.strokeWidth = 0.25;
testDOT.strokeColor = getColor("MAROON"); // defined above
testDOT.fillColor = getColor("MAROON");
the getColor just creates a CYMK Color object. Can anyone give me a clue on why the 100,100 point is not where I expect it to be?
TIA!
Just in case, it looks like your script used the 'relative' coordinate system (relative to zero point of current artboard).
To made it to use 'absolute' coordinates (relative to the top-left corner of the first artboard for a new document) you can add this line at the start of your script:
app.coordinateSystem = CoordinateSystem.DOCUMENTCOORDINATESYSTEM;
Or you can use the 'relative' coordinate system:
app.coordinateSystem = CoordinateSystem.ARTBOARDCOORDINATESYSTEM;
In this case you can move zero point of any artboard with this commands:
var doc = app.activeDocument;
doc.artboards[0].rulerOrigin = [0,0];
doc.artboards[1].rulerOrigin = [200,700];
// etc
I'm new Photoshop scripting and perhaps I'm not searching for the right terms. I'm trying to create 3 concentric circles at a user defined location. I have a script to create a circle but I'm not able to find a reference or snippet that will allow me to place an anchor or path or read the mouse coordinates or whatever to use as a center point for the circles. Basically I'd like to click on an image and have the script use that location as the origin for each of the circles. Any suggestions or references on how to do this would be greatly appreciated.
The Color Sampler tool provided the most direct way to create a user defined reference point for my application.
var colorsamplerRef=app.activeDocument.colorSamplers[0];
var currentPos= colorsamplerRef.position;
var x = currentPos[0];
var y = currentPos[1];
I'm currently making a force network visualization that involves a large number of nodes and edges (over 50k+) using a new library called stardust.js. Stardust uses WebGL to make the rendering of nodes and edges much quicker than Canvas/D3.
However, I am unable to figure out how to add zoom and pan to this visualization.
According to this thread on stardust's google group, the creator of the stardust library mentions that there is no support for zoom and pan right now, but it is possible to implement this by setting in the mark specification by setting zoom and pan specifications as parameters.
import { Circle } from P2D;
mark MyMark(translateX: float, translateY: float, scale: float, x: float, y: float, radius: float) {
Circle(Vector2(x * scale + translateX, y * scale + translateY), radius);
}
https://stackoverflow.com/editing-help
// In the js code you can do something like:
marks.attr("translateX", 10).attr("translateY", 15).attr("scale", 2);
This library uses a kind of Typescript language where one defines "marks" (which is what all the nodes and edges are), and it should be possible to define these marks with the above parameters. But how can one implement this?
Is there an easier way to do this? Can one add a library like Pixi.js on to this visualization to make it zoom and pan?
There is no need to define custom marks (it can be done with custom marks).
The position of the objects is controlled by a Stardust.scale().
var positions = Stardust.array("Vector2")
.value(d => [d.x, d.y])
.data(nodes);
var positionScale = Stardust.scale.custom("array(pos, value)")
.attr("pos", "Vector2Array", positions)
By modifying the value function you can zoom and translate.
By attaching the zoom to the canvas the star dust drag is no longer working. But that is a different problem.
I used the example https://stardustjs.github.io/examples/graph/
In the zoom callback save the zoom parameters and request a new render of the graph.
var fps = new FPS();
var zoom_scale = 1.0, zoom_t_x = 0.0, zoom_t_y = 0.0;
d3.select(canvas).call(d3.zoom().on("zoom", zoomed));
function zoomed() {
zoom_scale = d3.event.transform.k;
zoom_t_x = d3.event.transform.x;
zoom_t_y = d3.event.transform.y;
requestRender();
}
function render() {
positions.value(d => [d.x*zoom_scale + zoom_t_x, d.y*zoom_scale + zoom_t_y]);
......
}
The example contains an error.
When you use a slider the simulation never stops because the alphaTarget is set to 0.3.
force.alphaTarget(0.3).restart();
It should be changed to
force.alpha(0.3).alphaTarget(0).restart();
There is a know problem of Leaflet that when you use a custom tile provider, not with real earth images, set crs: L.CRS.Simple, Leaflet queries for images where Y coordinate is inverted in comparison to the math axis. So the first top-right image's location is 1x-1 instead of 1x1.
In the internet topics about inverting Y axis are rather old, so my question is: nowadays is there a normal short and built-in way to invert queried Y axis?
The only old solutions I've found were rewriting Leaflet internal objects, like extending L.CRS.Simple.
As noted in the Leaflet tutorial for WMS/TMS, the canonical way of inverting the Y coordinate for tile coordinates is using {-y} instead of {y} in the tile URL template. e.g.:
var layer = L.tileLayer('http://base_url/tms/1.0.0/tileset/{z}/{x}/{-y}.png');
Note, however, that (as of Leaflet 1.3.1) that only works for maps with a non-infinite coordinate system.
In your case, you might want to get around this by creating your own subclass of L.TileLayer. There is a complete guide on the Leaflet tutorial about extending layers, but the TL;DR version for a tilelayer that shifts its tile coordinates is:
L.TileLayer.CustomCoords = L.TileLayer.extend({
getTileUrl: function(tilecoords) {
tilecoords.x = tilecoords.x + 4;
tilecoords.y = tilecoords.y - 8;
tilecoords.z = tilecoords.z + 1;
return L.TileLayer.prototype.getTileUrl.call(this, tilecoords);
}
});
var layer = new L.TileLayer.CustomCoords(....);
And the specific case for just inverting the Y coordinate is:
L.TileLayer.InvertedY = L.TileLayer.extend({
getTileUrl: function(tilecoords) {
tilecoords.y = -tilecoords.y;
return L.TileLayer.prototype.getTileUrl.call(this, tilecoords);
}
});
var layer = new L.TileLayer.InvertedY(....);
Im trying to create an interactive seating layout like this Seats.io. However I dont need the exact features but just few things such as:
Plotting seats anywhere on the screen
Plotting list of seats from one point to another
Seats hover as circle when plotting from one mouse click point to another
After much research in Jquery and simultaneously on raphaeljs, I have decided to start working with raphaeljs. Im totally new to the vector graphics. So obviously there might be something that I may be missing. I have followed this fiddle to draw a straight line. I have also created another script to plot circles anywhere on the window(the circles will mean seats) following is the script
window.onload = function () {
var height = $(document).outerHeight(true);
var width = $(document).width();
var radius = 10;
var paper = Raphael(0, 0, width, height);
var i = 0;
$(document).click(function (e) {
i = i + 1;
var x = e.pageX;
var y = e.pageY;
var seat = paper.circle(x, y, radius)
.attr({stroke: "none", fill: "#f00", opacity: .4})
.data("i", i);
seat.mouseover(function () {
this.attr("opacity", 1);
});
seat.mouseout(function () {
this.attr("opacity", .4);
});
});
}
using the above script I'm able to plot circles(seats) on my screen. Now based on the fiddle example lines are drawn using 'path', so is it possible to load circles on every path and draw them as sequential line of circles one after the other, or do I have to take any different approach.
Also on a side note is there any opensource project or code for the Seats.io
Any help would be really appreciated
Ben from seats.io here.
http://raphaeljs.com/reference.html#Element.getPointAtLength is indeed what we use. You'll basically need to
calculate a helper path between start and end point. You already have that.
calculate the distance between seats (based on seat size): helperPath.getTotalLength() / (numberOfSeats - 1);
for each seat, call getPointAtLength and draw a circle around that
point: helperPath.getPointAtLength(distanceBetweenSeatsOnHelperPath * i++)
Obviously, it gets more interesting if you want to snap to a grid to align rows, curve rows, etc, but you should be able to get started with the above.