How to get center point of svg polygon? - javascript

I have an SVG image and I need to get the center point of all polygons for painting text. I am trying to do this with the below script:
function calculateCenterPoint(areas) {
var maxX = 0,
minX = Infinity,
maxY = 0,
minY = Infinity;
Array.prototype.forEach.call(areas, function (e) {
var i = 0,
coords = e.getAttribute('points').split(',');
while (i < coords.length) {
var x = parseInt(coords[i++], 10),
y = parseInt(coords[i++], 10);
if (x < minX)
minX = x;
if (x > maxX)
maxX = x;
if (y < minY)
minY = y;
if (y > maxY)
maxY = y;
}
});
return {
x: minX + (maxX - minX) / 2,
y: minY + (maxY - minY) / 2
}; }
but it is not working in IE 11, or edge.
Links:
http://istra46760.tmweb.ru/poselki/ushakovskie-dachi.html
https://gyazo.com/ba906bde72e5394c8a0275281108663b

instead of looking at the points, get the bounding rect of the svg
const el = document.querySelector("path");
const bbox = el.getBoundingClientRect();
const center = {
x: bbox.left + bbox.width / 2,
y: bbox.top + bbox.height / 2
};
or you could do
const bbox = el.getBBox();

Related

FabricJS: pan canvas while drawing

Here is the link to the codepen: https://codepen.io/Jsbbvk/pen/RwGBwOO
const edgePadding = 80;
const panSpeed = 5;
const expandCanvasEdge = (x, y) => {
let pan = {
x: 0,
y: 0,
};
const width = canvas.getWidth(),
height = canvas.getHeight();
if (x <= edgePadding) {
//left
const speedRatio = 1 - Math.max(0, x) / edgePadding;
pan.x = panSpeed * speedRatio;
} else if (x >= width - edgePadding) {
//right
const speedRatio =
1 - (width - Math.min(width, x)) / edgePadding;
pan.x = -panSpeed * speedRatio;
}
if (y <= edgePadding) {
//top
const speedRatio = 1 - Math.max(0, y) / edgePadding;
pan.y = panSpeed * speedRatio;
} else if (y >= height - edgePadding) {
//bottom
const speedRatio =
1 - (height - Math.min(height, y)) / edgePadding;
pan.y = -panSpeed * speedRatio;
}
if (pan.x || pan.y) {
canvas.relativePan(new fabric.Point(pan.x, pan.y));
}
}
canvas.on('mouse:move', function(opt) {
if (this.isMouseDown && this.isDrawingMode) {
let {x, y} = canvas.getPointer(opt.e, true);
expandCanvasEdge(x, y);
}
if (!this.isDrawingMode && this.isDragging) {
//panning
var e = opt.e;
var vpt = this.viewportTransform;
vpt[4] += e.clientX - this.lastPosX;
vpt[5] += e.clientY - this.lastPosY;
this.requestRenderAll();
this.lastPosX = e.clientX;
this.lastPosY = e.clientY;
}
});
In the demo, when you draw close to the edge of the canvas, the canvas should pan to allow more drawing space.
However, while the panning is happening, the drawing (path) is static on the canvas; it doesn't stretch as the canvas pans.
Is there a way to fix this issue?
I did some deep research for you and found a few examples.
You can overcome this situation by using the relativePan function.
One of the examples I have found:
function startPan(event) {
if (event.button != 2) {
return;
}
var x0 = event.screenX,
y0 = event.screenY;
function continuePan(event) {
var x = event.screenX,
y = event.screenY;
fc.relativePan({ x: x - x0, y: y - y0 });
x0 = x;
y0 = y;
}
function stopPan(event) {
$(window).off('mousemove', continuePan);
$(window).off('mouseup', stopPan);
};
$(window).mousemove(continuePan);
$(window).mouseup(stopPan);
$(window).contextmenu(cancelMenu);
};
function cancelMenu() {
$(window).off('contextmenu', cancelMenu);
return false;
}
$(canvasWrapper).mousedown(startPan);
You can determine a roadmap by examining the resources and demos here.
JSFiddle demo https://jsfiddle.net/tornado1979/up48rxLs/

Canvas JS How to get height and width of polygon shape?

I created a small canvas js script and draw outline on shape here is the script
context.beginPath();
context.moveTo(coordinates[0].x, coordinates[0].y);
for (let index = 1; index < coordinates.length; index++) {
context.lineTo(coordinates[index].x, coordinates[index].y);
}
context.lineWidth = 2;
context.strokeStyle = "red";
context.fillStyle = "rgba(255, 0, 0, 0.3)";
context.fill()
context.closePath();
context.stroke();
But i am unable to get its width and height of shape, actually i want to display and line as tooltip for user reference.
Here i attach image you can see black line on top of Dice (i did for your reference in photoshop). i want to show that line.
i am noob, if any one can help me with example code that would be great.
Example image
You can get the min/max X and Y like this:
var minx = coordinates[0].x, maxx = coordinates[0].x, miny = = coordinates[0].y, maxy = = coordinates[0].y;
for (let index = 1; index < coordinates.length; index++) {
if (coordinates[index].x < minx) minx = coordinates[index.x]);
if (coordinates[index].x > maxx) maxx = coordinates[index.x]);
if (coordinates[index].y < miny) miny = coordinates[index.y]);
if (coordinates[index].y > maxy) maxy = coordinates[index.y]);
}
You can calculate height and width using the min and max values.
If your polygon looks like following, this could be the fastest solution.
var polygon = [1678, 385, 1726, 388, 1725, 427, 1679, 427];
var minX = Math.min(...polygon.filter((_, i) => i % 2 === 0));
var maxX = Math.max(...polygon.filter((_, i) => i % 2 === 0));
var minY = Math.min(...polygon.filter((_, i) => i % 2 === 1));
var maxY = Math.max(...polygon.filter((_, i) => i % 2 === 1));
var width = maxX - minX;
var height = maxY - minY;

Drag Bound with Konva.Layer

I am using KonvaJs in my project. I need to implement drag bound to Konva.Layer. My layer has so many other shapes and images. I need to restrict the movement of layer up to 50% of it's width and height. The way I have done in this plunkr. The problem arises when user zoom-in or zoom-out the layer using mouse wheel. After the zoom, I don't know why the drag bound is behaving differently. Seems like I am not able to do the Math correctly. I need to have the same behavior i.e. the way movement of layer is restricted when user does not perform zoom. This is what I am doing:
//... a helper object for zooming
var zoomHelper = {
stage: null,
scale: 1,
zoomFactor: 1.1,
origin: {
x: 0,
y: 0
},
zoom: function(event) {
event.preventDefault();
var delta;
if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
if (event.originalEvent.detail > 0) {
//scroll down
delta = 0.2;
} else {
//scroll up
delta = 0;
}
} else {
if (event.originalEvent.wheelDelta < 0) {
//scroll down
delta = 0.2;
} else {
//scroll up
delta = 0;
}
}
var evt = event.originalEvent,
mx = evt.clientX - zoomHelper.stage.getX(),
my = evt.clientY - zoomHelper.stage.getY(),
zoom = (zoomHelper.zoomFactor - delta),
newscale = zoomHelper.scale * zoom;
zoomHelper.origin.x = mx / zoomHelper.scale + zoomHelper.origin
.x - mx / newscale;
zoomHelper.origin.y = my / zoomHelper.scale + zoomHelper.origin
.y - my / newscale;
zoomHelper.stage.setOffset({
x: zoomHelper.origin.x,
y: zoomHelper.origin.y
});
zoomHelper.stage.setScale({
x: newscale,
y: newscale
});
zoomHelper.stage.draw();
zoomHelper.scale *= zoom;
preCalculation();
}
};
// Code goes here
var w = window.innerWidth;
var h = window.innerHeight;
var height, minX, minY, maxX, maxY;
var stage = new Konva.Stage({
container: 'container',
width: w,
height: h
});
zoomHelper.stage =stage;
var layer = new Konva.Layer({
draggable: true,
dragBoundFunc: function(pos) {
console.log('called');
var X = pos.x;
var Y = pos.y;
if (X < minX) {
X = minX;
}
if (X > maxX) {
X = maxX;
}
if (Y < minY) {
Y = minY;
}
if (Y > maxY) {
Y = maxY;
}
return ({
x: X,
y: Y
});
}
});
stage.add(layer);
function preCalculation(){
// pre-calc some bounds so dragBoundFunc has less calc's to do
height = layer.getHeight();
minX = stage.getX() - layer.getWidth() / 2;
maxX = stage.getX() + stage.getWidth() - layer.getWidth() / 2;
minY = stage.getY() - layer.getHeight() / 2;
maxY = stage.getY() + stage.getHeight() - layer.getHeight() / 2;
console.log(height, minX, minY, maxX, maxY);
}
preCalculation();
var img = new Image();
img.onload = function() {
var floorImage = new Konva.Image({
image: img,
width: w,
height: h
});
layer.add(floorImage);
layer.draw();
};
img.src = 'https://s.yimg.com/pw/images/coverphoto02_h.jpg.v3';
$(stage.container).on('mousewheel DOMMouseScroll', zoomHelper.zoom);
While using dragBoundFunc you have to return absolute position of layer. As you are changing attributes of top node (stage) it can be hard to maintain absolute position. So you can try to set bound function inside 'dragmove' event:
layer.on('dragmove', function() {
var x = Math.max(minX, Math.min(maxX, layer.x()));
var y = Math.max(minY, Math.min(maxY, layer.y()));
layer.x(x);
layer.y(y);
});
http://plnkr.co/edit/31MUmOjXBUVuaHVJsL3c?p=preview

Constraints of movement of rectangle inside a polygon

I'm using a library (PolyK) to calculate the position where a rectangle could be dragged inside a polygon (U shape).
I'm using ray-cast to get the delta point ( point outside of the polygon ) to calculate the new position but I cannot get it to work.
Fiddle
Any one have some advice, or know any library?
JavaScript:
// a basic poly
var p=[30, 30, 30, 193, 168, 193, 168, 142, 340, 142, 340, 396, 498, 396, 498, 30];
var s = document.getElementById('ray').getContext('2d');
var heroCanvas = document.getElementById('hero').getContext('2d');
var hero = { x: 0, y: 0, width: 50, height: 40 };
var canvas = document.getElementById('canvas').getContext('2d');
canvas.fillStyle = '#f00';
canvas.beginPath();
canvas.moveTo(p[0], p[1]);
for(var i = 2; i< p.length; i+=2){
canvas.lineTo(p[i], p[i+1]);
}
canvas.closePath();
canvas.stroke();
document.onmousemove = function(event){
var x = event.offsetX;
var y = event.offsetY;
var resolve = calculatePosition(x, y);
updateHero(resolve.x, resolve.y);
}
function calculatePosition(x, y){
// get bounds of poly
var bounds = PolyK.GetAABB(p);
// get vertices
var v1 = {x: x, y: y};
var v2 = {x: x, y: y + hero.height};
var v3 = {x: x + hero.width, y: y + hero.height};
var v4 = {x: x + hero.width, y: y};
// check which vertice is outside of polygon
var c1 = PolyK.ContainsPoint(p, v1.x, v1.y);
var c2 = PolyK.ContainsPoint(p, v2.x, v2.y);
var c3 = PolyK.ContainsPoint(p, v3.x, v3.y);
var c4 = PolyK.ContainsPoint(p, v4.x, v4.y);
// constrain movement inside the poly bounds
if( x < bounds.x )
x = bounds.x;
if( x + hero.width > bounds.x + bounds.width)
x = bounds.x + bounds.width - hero.width;
if( y < bounds.y )
y = bounds.y;
if( y + hero.height > bounds.y + bounds.height)
y = bounds.y + bounds.height - hero.height;
// get delta position with ray cast
var delta = {x: 0, y: 0};
console.log(c1, c2, c3, c4);
if(c1 && !c2 && c3 && c4){
delta = getDelta(v2, 3);
x = x+ delta.x;
y = y+ delta.y;
} else if(!c1 && !c2 && c3 && c4){
delta = getDelta(v2, 0);
x = x + delta.x;
y = y;
} else if(!c1 && !c2 && !c3 && c4){
delta = getDelta(v1, 0);
x = x + delta.x;
y = y;
} else if(c1 && !c2 && !c3 && c4){
delta = getDelta(v2, 3);
x = x;
y = y + delta.y;
} else if(c1 && c2 && !c3 && c4){
delta = getDelta(v3, 3);
x = x+ delta.x;
y = y+ delta.y;
} else if (c1 && c2 && !c3 && !c4){
delta = getDelta(v3, 2);
x = x + delta.x;
y = y;
} else if(c1 && !c2 && !c3 && !c4) {
delta = getDelta(v1, 2);
x = x;
y = y + delta.y;
}
return {
x: x,
y: y
};
}
function getDelta(point, n){
var points = [];
var rn = 4;
var diff = 2*Math.PI/rn;
var iscc = {dist:0, edge:0, norm:{x:0, y:0}, refl:{x:0, y:0}};
for(var i=0; i<rn; i++)
{
var dx = Math.cos(i*diff);
var dy = Math.sin(i*diff);
var isc = PolyK.Raycast(p, point.x, point.y, dx, dy, iscc);
if(!isc) iscc.dist = 4000;
points.push({x: dx*iscc.dist, y:dy*iscc.dist});
}
return points[n];
}
function updateHero(x, y){
heroCanvas.clearRect(0,0,600,500);
heroCanvas.beginPath();
heroCanvas.fillStyle = '#ff0000';
heroCanvas.rect(x, y, hero.width, hero.height);
heroCanvas.stroke();
}
thanks

Rectangle Coordinate Projection into another Rectangle

So I would like to project coordinates from one rectangle in javascript to another, in essence, scaling coordinates from one rectangle to another. How would I do that?
function Rectangle(maxX, minX, maxY, minY) {
this.maxX = maxX;
this.minX = minX;
this.maxY = maxY;
this.minY = minY;
}
So 2 Rectangles with different size and coordinates. I want to draw into one rectangle and scale that proportionally into the other rectangle.
Something like this?
var src = new Rectangle(6, 0, 6, 2);
var dst = new Rectangle(4, 2, 8, 0);
function Rectangle(maxX, minX, maxY, minY) {
this.maxX = maxX;
this.minX = minX;
this.maxY = maxY;
this.minY = minY;
}
var canvas = document.querySelector("canvas");
var width = canvas.width, height = canvas.height;
var w = width / 2 + 0.5, h = height / 2 + 0.5;
var sx = width / 20, sy = height / 20;
var context = canvas.getContext("2d");
context.strokeStyle = "#808080";
context.fillStyle = "#000080";
tween(src, dst, 25, 1, 1000);
function tween(src, dst, fps, seconds, delay) {
var frames = fps * seconds;
var srcMaxX = src.maxX;
var srcMinX = src.minX;
var srcMaxY = src.maxY;
var srcMinY = src.minY;
var maxX = dst.maxX - srcMaxX;
var minX = dst.minX - srcMinX;
var maxY = dst.maxY - srcMaxY;
var minY = dst.minY - srcMinY;
drawRectangle(srcMaxX, srcMinX, srcMaxY, srcMinY);
setTimeout(function loop(frame, delay) {
var dstMaxX = srcMaxX + maxX * frame / frames;
var dstMinX = srcMinX + minX * frame / frames;
var dstMaxY = srcMaxY + maxY * frame / frames;
var dstMinY = srcMinY + minY * frame / frames;
drawRectangle(dstMaxX, dstMinX, dstMaxY, dstMinY);
if (frame < frames) setTimeout(loop, delay, frame + 1, delay);
}, delay, 1, 1000 / fps);
}
function drawRectangle(maxX, minX, maxY, minY) {
context.clearRect(0, 0, width, height);
drawLine(0, h, width, h);
drawLine(w, 0, w, height);
var x = w + sx * minX;
var y = h - sy * maxY;
var wth = sx * (maxX - minX);
var hgt = sy * (maxY - minY);
context.fillRect(x, y, wth, hgt);
}
function drawLine(x1, y1, x2, y2) {
context.beginPath();
context.moveTo(x1, y1);
context.lineTo(x2, y2);
context.stroke();
}
canvas {
border: 1px solid #000000;
}
<canvas width="400" height="400"></canvas>
Hope this helps.
With these functions:
function Point(x, y) {
this.x = x;
this.y = y;
}
function Rect(xMin, xMax, yMin, yMax) {
this.xMin = xMin;
this.xMax = xMax;
this.yMin = yMin;
this.yMax = yMax;
}
Rect.prototype.width = function() {
return this.xMax - this.xMin;
};
Rect.prototype.height = function() {
return this.yMax - this.yMin;
};
function RectProjection(a, b) {
var xScale = b.width() / a.width();
var yScale = b.height() / a.height();
var xOffset = b.xMin - xScale * a.xMin;
var yOffset = b.yMin - yScale * a.yMin;
return function (p) {
return Point(xScale * p.x + xOffset, yScale * p.y + yOffset);
};
}
You can then do something like this:
var proj = projection(new Rectangle(0, 2, 0, 3), new Rectangle(2, 6, 2, 8));
var q = proj(new Point(1, 2));
Where q is Point(4, 6).

Categories