I have an application I am developing that allows users to drop "Pins" on an SVG. These pins can be moved around the underlying SVG and the coordinates are saved in a database. The pins also have a "center of mass" of bottom center, I store the coordinates of the tip of the pin, not the 0,0 origin of the pin icon.
I am trying to implement a functionality, that will allow the pins to show larger when zoomed out of the underlying SVG, and scale smaller when zooming in (think google maps, if you look at a zoomed out map of all restaurants and then zoom in, the pins get smaller and more spread out).
I have this feature working on desktop web, see images below
However, on mobile, the same code causes the pins to exist in a different location, and when zooming I can see them scaling down to the top left point, and not the center bottom like the desktop client.
JS Code that is creating the scaling styles and logic:
if (instance) {
instance.dispose();
instance = panzoom($('#partialDiv')[0]);
var pins = Array.from(document.querySelectorAll('.draggable'));
instance.on('transform', function(pz) {
var transform = instance.getTransform();
pins.forEach(pin => {
if (transform.scale > 10 && transform.scale < 18) {
pin.setAttribute("transform", 'matrix(' +
15 / transform.scale + ', 0, 0, ' +
15 / transform.scale + ', ' +
pin.transform.baseVal[0].matrix.e + ', ' + pin.transform.baseVal[0].matrix.f + ')');
var pinStyle = pin.style;
pin.setAttribute("transform-origin", "" + pin.getBBox().width / 2 + " " + pin.getBBox().height + "0px");
pinStyle.transformBox = 'fill-box';
pin.style['-webkit-transform-origin-x'] = '50%';
pin.style['-webkit-transform-origin-y'] = 'bottom';
pinStyle.transformBox = 'fill-box';
} else if (transform.scale > 18) {
pin.setAttribute("transform", 'matrix(0.8, 0, 0, 0.8, ' +
pin.transform.baseVal[0].matrix.e + ', ' + pin.transform.baseVal[0].matrix.f + ')');
var pinStyle = pin.style;
pin.setAttribute("transform-origin", "" + pin.getBBox().width / 2 + " " + pin.getBBox().height + "0px");
pinStyle.transformBox = 'fill-box';
pin.style['-webkit-transform-origin-x'] = '50%';
pin.style['-webkit-transform-origin-y'] = 'bottom';
} else {
pin.setAttribute("transform", 'matrix(2, 0, 0, 2, ' +
pin.transform.baseVal[0].matrix.e + ', ' + pin.transform.baseVal[0].matrix.f + ')');
var pinStyle = pin.style;
pin.setAttribute("transform-origin", "" + pin.getBBox().width / 2 + " " + pin.getBBox().height + "0px");
pinStyle.transformBox = 'fill-box';
pin.style['-webkit-transform-origin-x'] = '50%';
pin.style['-webkit-transform-origin-y'] = 'bottom';
}
});
});
}
Why would the pins be displayed at a different origin on Chrome Desktop vs. Chrome IOS? Same is true for other desktop browsers and Safari on mobile. I have tried variations of webkit styles but it does not seem to change this behavior. Any advice is much appreciated.
After hours of troubleshooting I learned that there is a bug on IOS webkit 16.2+ that does not allow transform-origin to work with a transform attribute. Only the transform being performed in CSS will work with a transform-origin style.
Useful resource for anyone having an issue similar to me:
https://caniuse.com/mdn-svg_attributes_presentation_transform-origin
Related
I have written script to export my Google spreadsheet to a PDF, but the scale is wrong. I need to set a custom scale of 70%, but as far as I can tell, my options regarding scale customisation are:
1 = Normal 100%,
2 = Fit to width,
3 = Fit to height and
4 = Fit to Page.
Below is some redacted script.
var exporturl = 'https://docs.google.com/spreadsheets/d/' +
'xxxxxx' + //file ID
'/export?exportFormat=pdf&format=pdf' +
'&size=A4' +
'&portrait=true' +
'&scale=3' + // My question refers to this line
'&top_margin=0.50' +
'&bottom_margin=0.50' +
'&left_margin=0.50' +
'&right_margin=0.50' +
'&sheetnames=false&printtitle=false' +
'&pagenum=false' +
'&gridlines=true' +
'&fzr=FALSE' +
'&gid=' +
'yyyyyyy'; //the sheet's Id
Is it possible to set a custom scale or am I bound to the 4 options? Also, if anyone can suggest a workaround, I'd apprecite it.
I am using JavaFX WebView included in jdk-8u45 to open a web page which shows a map using OpenLayers 2.13.1. I'm trying to zoom in on the map using a ZoomBox with a BoxHandler. The zooming works like it should, but the problem is how the the rectangle is drawn.
The wanted result is that once I click on the map and start dragging, the rectangle should start drawing as I move the mouse. This works fine in all browsers, except inside my WebView. What happens is that only after I have moved my mouse a few cm in both x- and y-direction (e.g. diagonally), the rectangle starts drawing from this position (not the one where I started dragging). I have looked at the coordinates from the different mouse events, and they all seem to be correct, which is confirmed by the fact that it zooms in on the area I actually dragged over (e.g. not the area that is drawn).
JavaScript console.log stmts output coordinates from the moment I click on the map, but nothing is drawn in the beginning of the drag.
Has anyone had similar problems with WebView? As I said, the code works like a charm in all other browsers I have tried (Safari, Firefox, Chrome, IE). I have looked around on the internet, but I haven't been able to find an answer to my problem.
Code taken from BoxHandler.js:
startBox: function (xy) {
;;;console.log(xy);
;;;console.log("startbox xy=" + xy.x + "," + xy.y);
if(this.zoomBox){
this.removeBox();
}
this.zoomBox = OpenLayers.Util.createDiv('zoomBox',
this.dragHandler.start);
this.zoomBox.className = this.boxDivClassName;
this.zoomBox.style.zIndex = this.map.Z_INDEX_BASE["Popup"] - 1;
this.map.viewPortDiv.appendChild(this.zoomBox);
OpenLayers.Element.addClass(
this.map.viewPortDiv, "olDrawBox"
);
},
/**
* Method: moveBox
*/
moveBox: function (xy) {
var startX = this.dragHandler.start.x;
var startY = this.dragHandler.start.y;
;;;console.log("dragHandler.start.x=" + this.dragHandler.start.x);
;;;console.log("dragHandler.start.y=" + this.dragHandler.start.y);
var deltaX = Math.abs(startX - xy.x);
var deltaY = Math.abs(startY - xy.y);
this.zoomBox.style.width = Math.max(1, deltaX) + "px";
this.zoomBox.style.height = Math.max(1, deltaY) + "px";
this.zoomBox.style.left = xy.x < startX ? xy.x+"px" : startX+"px";
this.zoomBox.style.top = xy.y < startY ? xy.y+"px" : startY+"px";
console.log("zoombox width=" + this.zoomBox.style.width);
console.log("zoombox height=" + this.zoomBox.style.height);
console.log("zoombox left=" + this.zoomBox.style.left);
console.log("zoombox top=" + this.zoomBox.style.top);
// depending on the box model, modify width and height to take borders
// of the box into account
var box = this.getBoxCharacteristics();
;;;console.log("movebox xOffset=" + box.xOffset);
;;;console.log("movebox yOffset=" + box.yOffset);
if (box.newBoxModel) {
if (xy.x > startX) {
this.zoomBox.style.width =
Math.max(1, deltaX - box.xOffset) + "px";
}
if (xy.y > startY) {
this.zoomBox.style.height =
Math.max(1, deltaY - box.yOffset) + "px";
}
}
},
/**
* Method: endBox
*/
endBox: function(end) {
var result;
console.log(this.map.viewPortDiv.lastElementChild.style);
if (Math.abs(this.dragHandler.start.x - end.x) > 5 ||
Math.abs(this.dragHandler.start.y - end.y) > 5) {
var start = this.dragHandler.start;
var top = Math.min(start.y, end.y);
var bottom = Math.max(start.y, end.y);
var left = Math.min(start.x, end.x);
var right = Math.max(start.x, end.x);
result = new OpenLayers.Bounds(left, bottom, right, top);
} else {
result = this.dragHandler.start.clone(); // i.e. OL.Pixel
}
this.removeBox();
this.callback("done", [result]);
}
Also, I don't know if this is relevant, but when I inspect the HTML div element that holds the map (using Firebug Lite) it looks like the top border of the div is further down than it should be. The map (in correct position on the webpage) is extending beyond the top border. This is different behavior than in the other browsers I mentioned.
Any help would be appreciated.
I have put together a plain javascript/css image slider, started out as just a learning exercise but am now looking to apply it in the real world. The problem is that the animation is choppy on my desktop (which is a v. high spec gaming rig) - and even worse on a mobile (to the degree it's not really an animation anymore)
You can see it in action here:
www.chrishowie.co.uk/sands/
jsfiddle isolates much of the pertinent code - it's not a "this doesn't work" issue, so hopefully the fiddle gives enough to help optimize it.
http://jsfiddle.net/9aozrxy8/5/
In summary: I have a DIV with 4 images in a row, each image is 100% the width of the page. I use javascript to translateX (I have tried translate3d as heard this uses GPU, but didnt make much diff) and I set CSS transitions to ease-in the transform.
I also thought that potentially I am just trying to do too much on this site - but then I look at some other sites doing a heck of a lot more and it's smooth as silk. So I guess I'm missing something.
function slideRight() {
if (sliding) {
return false
};
window.sliding = true;
el = document.getElementById("slider");
cst = getComputedStyle(el);
transformst = cst.transform || cst.webkitTransform || cst.mozTransform;
widthst = cst.width;
widthst = widthst.replace("px", ""); // computed width of slider (7680px)
slidewidth = widthst / 4;
transformst = transformst.replace("matrix(", "");
transformst = transformst.replace(")", "");
transformst = transformst.split(",");
transformst = transformst[4]; // returns current transform in px without unit (px)
if (!transformst) {
transformst = 0;
}
var activebtn = "sldr" + Math.round((Number(transformst) / (-1 * slidewidth)));
document.getElementById(activebtn).classList.remove("sliderbuttonactive");
if (activebtn != "sldr3") {
document.getElementById("slider" + Math.round((2 + Number(transformst) / (-1 * slidewidth)))).style.visibility = "visible";
document.getElementById("slider" + Math.round((2 + Number(transformst) / (-1 * slidewidth)))).style.display = "initial";
document.getElementById("slider").style.transform = "translate3d(" + 25 * ((Number(transformst) / (slidewidth)) - 1) + "%, 0, 0)";
document.getElementById("slider").style.transform = "-webkit-translate3d(" + 25 * ((Number(transformst) / (slidewidth)) - 1) + "%, 0, 0)";
document.getElementById("slider").style.transform = "-moz-translate3d(" + 25 * ((Number(transformst) / (slidewidth)) - 1) + "%, 0, 0)";
document.getElementById("slider").style.transform = "-ms-translate3d(" + 25 * ((Number(transformst) / (slidewidth)) - 1) + "%, 0, 0)";
document.getElementById("leftslidebtn").style.visibility = "visible";
document.getElementById("leftslidebtn").style.display = "block";
}
activebtn = activebtn.replace("sldr", "");
activebtn = "sldr" + (1 + Number(activebtn));
document.getElementById(activebtn).classList.add("sliderbuttonactive");
if (Number(activebtn.replace("sldr", "")) == 3) {
document.getElementById("rightslidebtn").style.visibility = "hidden";
document.getElementById("rightslidebtn").style.display = "none";
}
setTimeout(function () {
window.sliding = false
}, 2000);
}
update: still not resolved but on mobile I have made it usable by reducing the image size for small screens and also not displaying images that are off-screen. Not perfectly smooth but getting there.
Thanks a lot,
C
Like Jeremy mentioned, that the "transition" in your JSFiddle caused the problem, it's also causing it on your website.
In your "Main.css" in line 221. Remove the "transition: top ease 2s;" from class .slide
Everything works fine then on Win8.1/Google Chrome/i7
I'm using jcrop and trying to make a "live" preview of the cropped area on an image.
The movement of the selected area works perfectly if the "Crop Selection" area is the same height and width as the destination preview div.
Check out the issue here: http://jsfiddle.net/fbaAW/
function showCoords(c)
{
var $this = this.ui.holder;
var original = $this.prev();
var preview = original.parent().find(".image");
var oH = original.height();
var oW = original.width();
var pH = preview.height();
var pW = preview.width();
var sH = c.h;
var sW = c.w;
var differenceH = pH - sH;
var differenceW = pW - sW;
//preview.css('width', c.w);
//preview.css('height', c.h);
//preview.css("background-size", Math.round(oW + differenceW) + "px" + " " + Math.round(oH + differenceH) + "px");
preview.css("background-position", Math.round(c.x) * -1 + "px" + " " + Math.round(c.y) * -1 + "px");
}
As you can see, I've commented out a few of my tests and attempts at getting this code to work properly but I just can't wrap my head around the relationship between the position and the size background properties in order to get this effect to work correctly.
Calculate the horizontal and vertical ratios between the selection size and the preview area size:
var rW = pW / c.w;
var rH = pH / c.h;
Then apply them to the background-size and background-position:
preview.css("background-size", (oW*rW) + "px" + " " + (oH*rH) + "px");
preview.css("background-position", rW * Math.round(c.x) * -1 + "px" + " " + rH * Math.round(c.y) * -1 + "px");
http://jsfiddle.net/fbaAW/1/
So, if the preview size is, say, 3 times the size of your jCrop selection area, it means you have scale the original image by 3, and compensate for the scaling when defining the background position.
Can anyone tell me why this wouldn't work on Safari?
// Set the height of the iFrame
var avail = document.parentWindow.screen.availHeight;
var screenTop = document.parentWindow.screenTop;
var divHeight = $('.header').css('height').replace('px','');
var divTop = $('.header').position().top;
alert('avail: ' + avail + '\nscreenTop: ' + screenTop + '\ndivHeight: ' + divHeight + '\ndivTop: ' + divTop);
$('#viewerFrame').css('height', (avail - screenTop - divTop - divHeight - 94) + 'px');
In IE, it works exactly as I want (which means it sizes the iFrame to take up all of the screen that's left after I take into account the size of the window, the header, and so forth...). Why doesn't it work in Safari?
document.parentWindow is IE-only.
You may use top or parent instead