JCrop: previous image not updated? - dom

I developed a small JCrop file upload app; here is my code:
function createCropImage(event)
{
//alert(event.target.result);
document.getElementById("Imgpreview").src = event.target.result;
var img2 = document.getElementById("Imgpreview1").src = event.target.result;
// Create variables (in this scope) to hold the API and image size
var jcrop_api, boundx, boundy;
$('#Imgpreview1').Jcrop({
onChange: updatePreview,
onSelect: updatePreview,
aspectRatio: 1
},function(){
// Use the API to get the real image size
var bounds = this.getBounds();
boundx = bounds[0];
boundy = bounds[1];
// Store the API in the jcrop_api variable
jcrop_api = this;
});
function updatePreview(c)
{
$('#Xcoardinate').val( Math.round(c.x));
$('#Ycoardinate').val( Math.round(c.y));
$('#width').val( Math.round(c.w));
$('#height').val( Math.round(c.h));
if (parseInt(c.w) > 0)
{
var rx = 100 / c.w;
var ry = 100 / c.h;
$('#Imgpreview').css({
width: Math.round(rx * boundx) + 'px',
height: Math.round(ry * boundy) + 'px',
marginLeft: '-' + Math.round(rx * c.x) + 'px',
marginTop: '-' + Math.round(ry * c.y) + 'px'
});
}
};
}
Here Imgpreview is the preview image and Imgpreview1 is the source image. I first select an image through the browse button:
<input type="file" size="45" id="photoUploadElmt" name="upload" onchange="previewImg()" style="width:430px;"/>
The original image (Imgpreview1) and preview image (Imgpreview) are showing fine, but if I select another image, the preview image is correct but in place of Imgpreview1 I see the older image.
If I put following code in comments, then images are displayed properly but I lose the JCrop instance:
$('#Imgpreview1').Jcrop({
onChange: updatePreview,
onSelect: updatePreview,
aspectRatio: 1
},function(){
// Use the API to get the real image size
var bounds = this.getBounds();
boundx = bounds[0];
boundy = bounds[1];
// Store the API in the jcrop_api variable
jcrop_api = this;
});

The destroy method is unreliable, so create a custom one as in this similar question

Related

Saving user input from Popup in local storage not working properly

i have a marker with pop i was able to save user input from a form in my popup but the problem is it will only save if i have to click somewhere on the map first. heres my code...
L.marker([63.233627, 5.625])
.addTo(map)
.bindPopup('<form><select class="fodd" id="fodd-1"><option value="false">false</option><option
value="true">true</option></select><button type="button" id="btnInsert">Save</button></form>')
.on('click', foddStatus);
L.marker([72.181804, 45])
.addTo(map)
.bindPopup('<form><select class="fodd" id="fodd-2"><option value="false">false</option><option
value="true">true</option></select><button type="button" id="btnInsert">Save</button></form>')
.on('click', foddStatus);
function foddStatus(e) {
var btnInsert = document.getElementById("btnInsert");
btnInsert.onclick = function () {
// get user input when button is saved is clicked
var foddValue = document.querySelector('.fodd').value;
var foddLoc = document.querySelector('.fodd').id;
var midFodd = ":";
var var1 = foddLoc + midFodd;
var new_data = foddLoc + midFodd + foddValue;
console.log(new_data);
// if there is nothing saved on storage then save an empty array
if (localStorage.getItem('foddstatus') == null){
localStorage.setItem('foddstatus','[]');
}
// get old data and slap it to the new data
var old_data = JSON.parse(localStorage.getItem('foddstatus'));
old_data.push(new_data);
// save the old + new data to local storage
localStorage.setItem('foddstatus', JSON.stringify(old_data));
// console.log(key);
}
}
so what happens here on the first marker that I click the save button, it will save the values in localstorage, then when I go to the second marker and click the save button, it won't actually save on local storage. I have to click somewhere else on the map first in order to save the second marker's input on my localstorage.
this is a bit other approach to achive your goal, but maybe it helps.
This is only a test, without any validation etc. so please be aware of it!
I used here simple divs in the popups, inside an input and a button. Every button has its onclick attribute to call storeData function, which sets the localStorage key-value if the input is not empty. I used the input ids as keys.
The example snippet:
let ls = window.localStorage;
var map = L.map('map').setView([41, 21], 5);
var darkMap = L.tileLayer('https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png', {
maxZoom: 20,
attribution: '© Stadia Maps, © OpenMapTiles © OpenStreetMap contributors'
}).addTo(map);
var marker1 = L.marker([40, 10]).addTo(map);
var marker2 = L.marker([40, 30]).addTo(map);
marker1.bindPopup('<div><input class="ipt" id="ipt1" /><button onclick="storeData(this);" class="save">SAVE</button></div>');
marker2.bindPopup('<div><input class="ipt" id="ipt2" /><button onclick="storeData(this);" class="save">SAVE</button></div>');
function storeData(btn) {
let ipt = btn.parentNode.querySelector('.ipt');
if (ipt.value != '') {
ls.setItem(ipt.id, ipt.value);
let str = 'Data stored in localStorage with key: ' + ipt.id + ', value: ' + ls.getItem(ipt.id);
alert(str);
} else {
console.log('Empty input!');
}
}
And a working fiddle (Please open in non-incognito).

ChartJS: Custom tooltip always displaying

Im using ChartJS to create a graph on my website.
Im trying to create a custom tooltip. According to the documentation, this should be easy:
var myPieChart = new Chart(ctx, {
type: 'pie',
data: data,
options: {
tooltips: {
custom: function(tooltip) {
// tooltip will be false if tooltip is not visible or should be hidden
if (!tooltip) {
return;
}
}
}
}
});
My problem is that the tooptip is never false and because of this my custom tooltip is always displayed.
Please see this JSFiddle (line 42 is never executed)
Question: Is it a bug that tooltip is never false, or am I missing something?
The custom tooltip option is used for when you want to create/style your own tooltip using HTLM/CSS outside of the scope of the canvas (and not use the built in tooltips at all).
In order to do this, you must define a place outside of your canvas to contain your tooltip (e.g. a div) and then use that container within your tooltips.custom function.
Here is an example where I used a custom tooltip to display the hovered pie chart section percentage in the middle of the chart. In this example I'm generating my tooltip inside a div with id "chartjs-tooltip". Notice how I interact with this div in my tooltips.custom function to position and change the value.
Also, the correct way to check if the tooltip should be hidden is to check it's opacity. The tooltip object will always exist, but when it should not be visible, the opacity is set to 0.
Chart.defaults.global.tooltips.custom = function(tooltip) {
// Tooltip Element
var tooltipEl = document.getElementById('chartjs-tooltip');
// Hide if no tooltip
if (tooltip.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
// Set Text
if (tooltip.body) {
var total = 0;
// get the value of the datapoint
var value = this._data.datasets[tooltip.dataPoints[0].datasetIndex].data[tooltip.dataPoints[0].index].toLocaleString();
// calculate value of all datapoints
this._data.datasets[tooltip.dataPoints[0].datasetIndex].data.forEach(function(e) {
total += e;
});
// calculate percentage and set tooltip value
tooltipEl.innerHTML = '<h1>' + (value / total * 100) + '%</h1>';
}
// calculate position of tooltip
var centerX = (this._chartInstance.chartArea.left + this._chartInstance.chartArea.right) / 2;
var centerY = ((this._chartInstance.chartArea.top + this._chartInstance.chartArea.bottom) / 2);
// Display, position, and set styles for font
tooltipEl.style.opacity = 1;
tooltipEl.style.left = centerX + 'px';
tooltipEl.style.top = centerY + 'px';
tooltipEl.style.fontFamily = tooltip._fontFamily;
tooltipEl.style.fontSize = tooltip.fontSize;
tooltipEl.style.fontStyle = tooltip._fontStyle;
tooltipEl.style.padding = tooltip.yPadding + 'px ' + tooltip.xPadding + 'px';
};
Here is the full codepen example.
I hope that helps clear things up!

Preload Images for Photoswipe Gallery

So I have an array of images I want to load into a gallery using Photoswipe, but I'm having trouble predefining the image width and height. Specifically, I think I need to preload the images
Here's my JS to render the page, here I'm defining slides and listing as a local variable for the ejs page to use:
var sizeOf = require('image-size');
var url = require('url');
var http = require('http');
var slideshow = [];
for(var i = 0; i < listing.listing_images.length; i++) {
var image = listing.listing_images[i];
var width, height = 0;
var imgUrl = image.url;
var options = url.parse(imgUrl);
http.get(options, function (response) {
var chunks = [];
response.on('data', function (chunk) {
chunks.push(chunk);
}).on('end', function() {
var buffer = Buffer.concat(chunks);
**height = sizeOf(buffer).height;
width = sizeOf(buffer).width;**
});
});
var item = {
src: image.url,
h: height,
w: width
};
slideshow.push(item);
}
res.render('example.ejs', {
listing: listing,
slides: slideshow
});
And here is the script in the ejs page :
<% var slides = locals.slides %>
<script>
$('document').ready(function() {
var pswpElement = document.querySelectorAll('.pswp')[0];
// build items array using slideshow variable
var items = <%- JSON.stringify(slides) %>;
console.log(items);
// grab image
if (items.length > 0) {
// define options (if needed)
var options = {
// optionName: 'option value'
// for example:
index: 0 // start at first slide
};
// Initializes and opens PhotoSwipe
var gallery = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, items, options);
gallery.init();
}
</script>
Basically what's happening is the array of photoswipe items is being passed in fine, but the width and height aren't set until photoswipe initializes and triggers the img to load. So the images don't show, because their height and width aren't set yet.
Is there a way to trigger the loading of the images in the slideshow array so that the width & height are set before passing to Photoswipe? I've also tried seeing if I could just set them initially to 0, and then try and update the height and width later and try to force photoswipe to reload, but photoswipe doesn't recognize the image's new height/width.
Sorry if any of this is unclear/muddled with ejs nonsense, feel free to ask anything and I'd love to clarify.
Thanks
Ended up solving this leveraging the API:
gallery.listen('gettingData', function(index, item) {
// index - index of a slide that was loaded
// item - slide object
var img = new Image();
img.src = item.src;
item.h = img.height;
item.w = img.width;
});
gallery.invalidateCurrItems();
// updates the content of slides
gallery.updateSize(true);
If anyone happens to be reading this and there's a better way to read image size without creating a new img, or optimize this I'd love suggestions. :)

jssor size adjustor without maintaining aspect ratio

Since one of our organization's client asked us to change the slide show height slightly not width (reason on maintaining aspect ratio in small screen device the slider gets very small).
I know about this jssor function $ScaleWidth(width); but only have to adjust height.
So created the following function to resize based on the scale value of transform css property of jssor instantiated object's tag id, which is passed as parameter for the following function.
function jssorResolutionAdjustor(id)
{
setTimeout(function() {
var idObj = $('#' + id);
var immediateChild = idObj.children('div');
var transformMatrix = '';
var transformMatrixValues = '';
var transformCss = '';
transformMatrix = immediateChild.css('transform');
transformMatrixValues = transformMatrix.match(/-?[\d\.]+/g);
var scaleXValue = transformMatrixValues[0];
var scaleXValueFixed = parseFloat(scaleXValue).toFixed(2);
var scaleYValue = (scaleXValue * 1.2).toFixed(2);
if (scaleXValueFixed >= 0.75)
{
scaleYValue = 1;
}
if ('WebkitTransform' in document.body.style)
{
transformCss = {'-webkit-transform': 'scale(' + scaleXValue + ',' + scaleYValue + ')',
'transform': ''};
}
else if ('MozTransform' in document.body.style)
{
transformCss = {'-moz-transform': 'scale(' + scaleXValue + ',' + scaleYValue + ')'};
}
else if ('transform' in document.body.style)
{
transformCss = {'tansform': 'scale(' + scaleXValue + ',' + scaleYValue + ')'};
}
$(immediateChild).css(transformCss);
}, 0);
}
It worked flawlessly in desktop browser (firefox, chrome only I checked) but if opened on mobile phone (iphone, android) means it scaled to too big size. Also I checked the value in mobile and in desktop by adjusting browser screen size to phone screen size same value is returned in alert('scaleXValue=' + scaleXValue + '<-->' + 'scaleXValueFixed=' + scaleXValueFixed + '<-->' + 'scaleYValue=' + scaleYValue);.
I can't get any clue so here I attach the screen shot of failed solution in mobile.
And I call this function on loading and resizing the window.
jssorResolutionAdjustor('jssor_image_gallery');
$(window).resize(function() {
jssorResolutionAdjustor('jssor_image_gallery');
});
jssor_image_gallery is the id given in jssor instance
jssor_slider_image = new $JssorSlider$('jssor_image_gallery', options);
Updated (1):
Here is my jssor function
function imageJssor()
{
var _CaptionTransitions = [];
_CaptionTransitions["MCLIP|B"] = {$Duration: 600, $Clip: 8, $Move: true, $Easing: $JssorEasing$.$EaseOutExpo};
var options = {
$AutoPlay: false,
$ThumbnailNavigatorOptions: {
$Class: $JssorThumbnailNavigator$,
$ChanceToShow: 2,
$Cols: 6,
$Align: 260,
$SpacingX: 3, //[Optional] Horizontal space between each thumbnail in pixel, default value is 0
$ArrowNavigatorOptions: {
$Class: $JssorArrowNavigator$, //[Requried] Class to create arrow navigator instance
$ChanceToShow: 2, //[Required] 0 Never, 1 Mouse Over, 2 Always
$Steps: 6 //[Optional] Steps to go for each navigation request, default value is 1
}
},
$ArrowNavigatorOptions: {
$Class: $JssorArrowNavigator$,
$ChanceToShow: 2
},
$CaptionSliderOptions: {//[Optional] Options which specifies how to animate caption
$Class: $JssorCaptionSlider$, //[Required] Class to create instance to animate caption
$CaptionTransitions: _CaptionTransitions, //[Required] An array of caption transitions to play caption, see caption transition section at jssor slideshow transition builder
$PlayInMode: 0, //[Optional] 0 None (no play), 1 Chain (goes after main slide), 3 Chain Flatten (goes after main slide and flatten all caption animations), default value is 1
$PlayOutMode: 0 //[Optional] 0 None (no play), 1 Chain (goes before main slide), 3 Chain Flatten (goes before main slide and flatten all caption animations), default value is 1
}
};
jssor_slider_image = new $JssorSlider$('jssor_image_gallery', options);
//responsive code begin
//you can remove responsive code if you don't want the slider scales while window resizes
function ScaleSlider() {
/* var windowWidth = $(window).width();
if (windowWidth) {
var windowHeight = $(window).height();
var originalWidth = jssor_slider_image.$OriginalWidth();
var originalHeight = jssor_slider_image.$OriginalHeight();
var scaleWidth = windowWidth;
if (originalWidth / windowWidth > originalHeight / windowHeight) {
scaleWidth = Math.ceil(windowHeight / originalHeight * originalWidth);
alert(scaleWidth);
}
jssor_slider_image.$ScaleWidth(scaleWidth);
}
else
window.setTimeout(ScaleSlider, 30);
var bodyWidth = document.body.clientWidth;
alert(bodyWidth);
if (bodyWidth)
jssor_slider_image.$ScaleWidth(Math.min(bodyWidth-150, 1920));
else
window.setTimeout(ScaleSlider, 30); */
var parentWidth = jssor_slider_image.$Elmt.parentNode.clientWidth;
//alert(parentWidth);
if (parentWidth)
jssor_slider_image.$ScaleWidth(Math.min(parentWidth, 720));
else
window.setTimeout(ScaleSlider, 30);
}
ScaleSlider();
$(window).bind("load", ScaleSlider);
$(window).bind("resize", ScaleSlider);
$(window).bind("orientationchange", ScaleSlider);
//responsive code end
}
imageJssor();
$(document).on('click', '#one li', function() {
var imageStartFrom = $(this).index();
$('#image_gallery').hide();
$('#jssor_image_gallery').show();
jssor_slider_image.$PlayTo(imageStartFrom);
jssor_slider_image.$Pause();
jssorResolutionAdjustor('jssor_image_gallery');
$(window).resize(function() {
jssorResolutionAdjustor('jssor_image_gallery');
});
});
Updated (2):
Here in both images (web & mobile) the default scale ratio and my calculated values or looking same but as shown below image its working properly in website in desktop browser but not in mobile. Here I attached that image too for reference.
Here in the above image on left side the deer image get scaled to high with compare to right side image which is took from desktop browser.
Updated (3):
Please see below image's alert to verify the parentWidth both represents the same value only
Also I attach my html dom structure with id which is used in jssor is highlighted in blue background.
I found the solution that if -webkit-transform was set means instead emptying the transform css property have to check browser (gecko, webkit, etc) engine also have transform. If it exist the priority will goes to transform while rendering the dom compared to -webkit-transform.
FROM:
if ('WebkitTransform' in document.body.style)
{
transformCss = {'-webkit-transform': 'scale(' + scaleXValue + ',' + scaleYValue + ')',
'transform': ''};
}
TO:
if ('WebkitTransform' in document.body.style)
{
transformCss = {'-webkit-transform': 'scale(' + scaleXValue + ',' + scaleYValue + ')'};
if ('transform' in document.body.style)
{
transformCss = {'tansform': 'scale(' + scaleXValue + ',' + scaleYValue + ')'};
}
}

Trying to make use of Jcrop and serverside image resizing with scala Scrimage lib

I'm trying to combine jcrop and scrimage but I'm having trouble in understanding
the documentation of scrimage.
The user uploads an image. When the upload is done the user is able choose a fixed
area to crop with Jcrop:
upload.js
$(function () {
$('#fileupload').fileupload({
dataType: 'json',
progress: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$("#progress").find(".progress-bar").css(
"width",
progress + "%"
);
},
done: function (e, data) {
$("#cropArea").empty();
var cropWidth = 210;
var cropHeight = 144;
if(data.result.status == 200) {
var myImage = $("<img></img>", {
src: data.result.link
}).appendTo('#cropArea');
var c = myImage.Jcrop({
allowResize: false,
allowSelect: false,
setSelect:[0,0,cropWidth,cropHeight],
onSelect: showCoords
});
}
}
});
});
Example:
When the user is satisfied the coordinates will be posted to the server and there is where the magic should happen.
Controller:
def uploadFile = Action(multipartFormDataAsBytes) { request =>
val result = request.body.files.map {
case FilePart(key, filename, contentType, bytes) => {
val coords = request.body.dataParts.get("coords")
val bais = new ByteArrayInputStream(bytes)
Image(bais).resize(magic stuff with coords)
Ok("works")
}
}
result(0)
}
If i read the docs for scrimage and resize:
Resizes the canvas to the given dimensions. This does not scale the
image but simply changes the dimensions of the canvas on which the
image is sitting. Specifying a larger size will pad the image with a
background color and specifying a smaller size will crop the image.
This is the operation most people want when they think of crop.
But when trying to implement resize with an inputstream Image(is).resize() I'm not sure I how should do this. Resize takes a scaleFactor, position and color... I guess I should
populate the position with the coords I get from jcrop??, and what do I do with the scaleFactor? Anybody got a good example of how to do this this?
Thank you for two great libs!
Subimage is what you want. That lets you specify coordinates rather than offsets.
So simply,
val image = // original
val resized = image.subimage(x,y,w,h) // you'll get these from jcrop somehow