my problem today is that I have 12 elements with size 60px x 60px and I'd like to increase the size with 0.2 everytime the screen size increase of 10px, with javascript. For example: screensize 600px and element size 60.2 x 60.2, screensize 610px and element size 60.4 x 60.4 and so on. It would give something like this to increase :
var circle_data={
container: document.querySelector(".container"),
classname: "astro-item",
nb_elem: 12,
elem_size: 60,
};
var screenSize = window.innerWidth;
circle_data.elem_size += 0.2;
The thing is that I don't know how to increase everytime the screen size increase by 10px
Thanks for your help !!
So with your answers here's the code I tried but it doesn't work, maybe because I already have a function that set elements size up, here's the full script:
function circle_container(objdata) {
var circle_dim=objdata.container.getBoundingClientRect();
var rayon=Math.round(circle_dim.width/2 - objdata.elem_size/2);
var center_x=rayon;
var center_y=rayon;
if (objdata.rayon) rayon*=objdata.rayon/100;
for(var i=0;i<objdata.nb_elem;i++) {
var new_elem=objdata.container.querySelector("."+objdata.classname+i);
if (!new_elem) {
var new_elem=document.createElement("button");
new_elem.className="astro-item"+" "+objdata.classname+i;
var new_img=document.createElement("img");
new_img.src = astroList[i].icon;
}
new_elem.style.position="absolute";
new_elem.style.width=objdata.elem_size+"px";
new_elem.style.height=objdata.elem_size+"px";
new_elem.style.top=Math.round( (center_y - rayon * Math.cos(i*(2*Math.PI)/objdata.nb_elem)))+"px";
new_elem.style.left=Math.round( (center_x + rayon * Math.sin(i*(2*Math.PI)/objdata.nb_elem)))+"px";
objdata.container.appendChild(new_elem);
new_elem.appendChild(new_img);
}
}
var circle_data={
container: document.querySelector(".container"),
classname: "astro-item",
nb_elem: 12,
elem_size: 60,
};
function onResize(e) {
var screenSize = e.target.outerWidth;
var width = (screenSize - (screenSize % 100) + (((screenSize + 10) % 100)/10 *2))/10;
var items = document.querySelectorAll('.astro-item');
for(var i = 0; i < items.length; i++) {
items[i].innerHTML = 'width: ' + screenSize + ' size: ' + width ;
}
}
circle_container(circle_data);
addEvent(window,"resize",function() {
circle_container(circle_data);
onresize();
});
The purpose of this function is to create 12 buttons aligned in circle (just like a wheel) and fully responsive, that's why I need them to get bigger when the screen gets larger. Thank you so much !
With pure javascript bind an event onresize and set size based on window width. The size increase 0.2 everytime the screen size increase of 10px:
window.addEventListener("resize", onresize);
var onresize = function(e) {
var width = e.target.outerWidth;
circle_data.elem_size = (width - (width % 100) + (((width + 10) %
100)/10 *2))/10;
}
Working example:
(open in full screen)
*Edited for max min limitations
var min = 500; //min width in pixel
var max= 700; //max width in pixel
window.addEventListener("resize", onresize);
var onresize = function(e) {
var width = e.target.outerWidth;
var s = (width - (width % 100) + (((width + 10) % 100)/10 *2))/10
if(width <=max && width >=min){
//change size here
document.getElementById('s').innerHTML = 'width: ' + width + ' size: ' + s ;
}
}
<span id='s'> </span>
THE PROBLEM
I'm having a minor problem dragging elements onto a scalable div container.
Once the element is actually in the container, the elements drag fine and work the way they are supposed to.
Larger elements that are dragged onto the scalable container don't have too much of an issue.
But when smaller elements are dragged, you can see that the mouse is no longer attached to said element and when it is dropped, it drops a little off where it is supposed to drop.
I'm trying to find a solution that my mouse stays on the element and it drops where it is supposed to drop.
I've solved problems bit by bit and you can see below but this is the last piece of the puzzle that's driving me mad. If anyone has the time to lend a hand, it would be greatly appreciated.
Here is a codepen - click and drag the two blue elements onto the white container to try it out
Codepen
Full Screen View
Short GIF in Action
This wil help making sure that the droppable area works with a scaled container.
$.ui.ddmanager.prepareOffsets = function(t, event) {
var i, j, m = $.ui.ddmanager.droppables[t.options.scope] || [],
type = event ? event.type : null,
list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack();
droppablesLoop: for (i = 0; i < m.length; i++) {
if (m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0], (t.currentItem || t.element)))) {
continue;
}
for (j = 0; j < list.length; j++) {
if (list[j] === m[i].element[0]) {
m[i].proportions().height = 0;
continue droppablesLoop;
}
}
m[i].visible = m[i].element.css("display") !== "none";
if (!m[i].visible) {
continue;
}
if (type === "mousedown") {
m[i]._activate.call(m[i], event);
}
m[i].offset = m[i].element.offset();
m[i].proportions({
width: m[i].element[0].offsetWidth * percent,
height: m[i].element[0].offsetHeight * percent
});
}
};
Enable the element to be resizable on a scaled container
function resizeFix(event, ui) {
var changeWidth = ui.size.width - ui.originalSize.width,
newWidth = ui.originalSize.width + changeWidth / percent,
changeHeight = ui.size.height - ui.originalSize.height,
newHeight = ui.originalSize.height + changeHeight / percent;
ui.size.width = newWidth;
ui.size.height = newHeight;
}
Makes it so drag works on a scaled container
function dragFix(event, ui) {
var containmentArea = $("#documentPage_"+ui.helper.parent().parent().attr('id').replace(/^(\w+)_/, "")),
contWidth = containmentArea.width(), contHeight = containmentArea.height();
ui.position.left = Math.max(0, Math.min(ui.position.left / percent , contWidth - ui.helper.width()));
ui.position.top = Math.max(0, Math.min(ui.position.top / percent, contHeight- ui.helper.height()));
}
Creating a draggable element that I can drag onto the box.
.directive('draggableTypes', function() {
return {
restrict:'A',
link: function(scope, element, attrs) {
element.draggable({
zIndex:3000,
appendTo: 'body',
helper: function(e, ui){
var formBox = angular.element($("#formBox"));
percent = formBox.width() / scope.templateData.pdf_width;
if(element.attr('id') == 'textbox_item')
return $('<div class="text" style="text-align:left;font-size:14px;width:200px;height:20px;line-height:20px;">New Text Box.</div>').css({ 'transform': 'scale(' + percent + ')', '-moz-transform': 'scale(' + percent + ')', '-webkit-transform': 'scale(' + percent + ')', '-ms-transform': 'scale(' + percent + ')'});
if(element.attr('id') == 'sm_textbox_item')
return $('<div class="text" style="text-align:left;font-size:14px;width:5px;height:5px;line-height:20px;"></div>').css({ 'transform': 'scale(' + percent + ')', '-moz-transform': 'scale(' + percent + ')', '-webkit-transform': 'scale(' + percent + ')', '-ms-transform': 'scale(' + percent + ')'});
}
});
}
};
})
Create draggable/resizable elements that may already be in the box and applying the drag/resize fix to these
.directive('textboxDraggable', function() {
return {
restrict:'A',
link: function(scope, element, attrs) {
element.draggable({
cursor: "move",
drag: dragFix,
start: function(event, ui) {
var activeId = element.attr('id');
scope.activeElement.id = activeId;
scope.activeElement.name = scope.templateItems[activeId].info.name;
scope.$apply();
}
});
element.resizable({
minWidth: 25,
minHeight: 25,
resize: resizeFix,
stop: function( event, ui ) {
var activeId = element.attr('id');
scope.activeElement.duplicateName = false;
scope.activeElement.id = activeId;
scope.activeElement.name = scope.templateItems[activeId].info.name;
scope.templateItems[activeId]['style']['width'] = element.css('width');
scope.templateItems[activeId]['style']['height'] = element.css('height');
scope.$apply();
}
})
}
};
})
What happens when an item is dropped
.directive('droppable', function($compile) {
return {
restrict: 'A',
link: function(scope,element,attrs){
element.droppable({
drop:function(event,ui) {
var draggable = angular.element(ui.draggable),
draggable_parent = draggable.parent().parent(),
drag_type = draggable.attr('id'),
documentBg = element,
x = ui.offset.left,
y = ui.offset.top,
element_top = (y - documentBg.offset().top - draggable.height() * (percent - 1) / 2) / percent,
element_left = (x - documentBg.offset().left - draggable.width() * (percent - 1) / 2) / percent,
timestamp = new Date().getTime();
//just get the document page of where the mouse is if its a new element
if(draggable_parent.attr('id') == 'template_builder_box_container' || draggable_parent.attr('id') == 'template_builder_container')
var documentPage = documentBg.parent().parent().attr('id').replace(/^(\w+)_/, "");
//if you are dragging an element that was already on the page, get parent of draggable and not parent of where mouse is
else var documentPage = draggable_parent.parent().parent().attr('id').replace(/^(\w+)_/, "");
if(drag_type == "textbox_item")
{
scope.activeElement.id = scope.templateItems.push({
info: {'page': documentPage,'name': 'textbox_'+timestamp, 'type': 'text'},
style: {'text-align':'left','font-size':'14px','top':element_top+'px','left':element_left+'px', 'width':'200px', 'height':'20px'}
}) - 1;
scope.activeElement.name = 'textbox_'+timestamp;
}
else if(drag_type == "sm_textbox_item")
{
scope.activeElement.id = scope.templateItems.push({
info: {'page': documentPage,'name': '', 'type': 'text'},
style: {'text-align':'left','font-size':'14px','top':element_top+'px','left':element_left+'px', 'width':'5px', 'height':'5px'}
}) - 1;
scope.activeElement.name = 'textbox_'+timestamp;
}
else {
scope.templateItems[scope.activeElement.id]['style']['top'] = draggable.css('top');
scope.templateItems[scope.activeElement.id]['style']['left'] = draggable.css('left');
}
scope.$apply();
}
});
}
};
})
last but not least, my controller
.controller('testing', function($scope, $rootScope, $state, $stateParams) {
$scope.templateItems = [];
$scope.activeElement = { id: undefined, name: undefined };
$scope.templateData = {"id":"12345", "max_pages":1,"pdf_width":385,"pdf_height":800};
$scope.clickElement = function(index) { $scope.activeElement = { id: index, name: $scope.templateItems[index].info.name } }
});
Here is the basis of my html
<div id="formBox" ng-style="formbox(templateData.pdf_width)" zoom>
<div class="trimSpace" ng-style="trimSpace(templateData.pdf_width)" zoom>
<div id="formScale" ng-style="formScale(templateData.pdf_width)" zoom>
<form action="#" id="{{ templateData.id }}_form">
<div ng-repeat="key in [] | range:templateData.max_pages">
<div class="formContainer" id="{{ templateData.id + '_' + (key+1) }}" ng-style="{width: templateData.pdf_width+'px', height: templateData.pdf_height+'px'}">
<div class="formContent">
<div class="formBackground" id="documentPage_{{ (key+1) }}" droppable>
<div ng-hide="preview" ng-repeat="item in templateItems">
<div ng-if="item.info.page == (key+1) && item.info.type == 'text'" id="{{ $index }}" data-type="{{ item.info.type }}" ng-click="clickElement($index)" class="text" ng-style="item.style" textbox-draggable>{{ item.info.name }}</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
For the cursor position while dragging, see this answer : Make Cursor position in center for ui.helper in jquery-ui draggable method
Basically, you can control the cursor position of the instance, allowing to have something more dynamic that cursorAt. Like this:
start: function(event, ui){
$(this).draggable('instance').offset.click = {
left: Math.floor(ui.helper.width() / 2),
top: Math.floor(ui.helper.height() / 2)
}
},
Then on the drop, you need to take into account the transform, but you can simplify by using the helper coordinates instead of the draggable. Like this:
element_top = (ui.helper.offset().top / percent) - (documentBg.offset().top / percent);
element_left = (ui.helper.offset().left / percent) - (documentBg.offset().left / percent);
Result: https://codepen.io/anon/pen/jamLBq
It looks like what is causing this to look strange is the following:
First, the small div is styled as display: block. This means that even though it looks like the div is small, that element actually stretches out to it's whole container.
Second, once you show the dragged square on the left screen, the relation between the mouse cursor and the element whole is technically centered, but you are cutting the size of the original element to a smaller one, and when the width and height get diminished, the result is rendered with the new width and height starting from the upper left corner of the original div. (If you style the small button to be display: inline, you can see what I mean. Try grabbing it from the upper left corner and the try the lower right one. You will see that the former looks fine but the latter is off).
So my suggestions are:
Make the draggabble elements display: inline
Make the dragged element on the left screen the exact height and width of the original element on the right screen.
Hope that helps!
I've forked your codepen and played around with it.
Take a look at it HERE, and see if it helps you find the "bug".
For your draggable script, I changed the code to this, adding margin-left and margin-right:
if(element.attr('id') == 'sm_textbox_item') { /* the small draggable box */
var el = {
pos: element.offset(), // position of the small box
height: element.outerHeight() + 20,
left: 0
}
var deduct = $('#formBox').innerWidth() - 20; // width of the element that's left of small box's container
el.left = el.pos.left - deduct;
return $('<div class="text" style="text-align:left; font-size:14px; width:5px; height:5px; line-height:20px;"></div>')
.css({
'margin-left': el.left + 'px',
'margin-top': el.pos.top - el.height + 'px',
'transform': 'scale(' + percent + ')',
'-moz-transform': 'scale(' + percent + ')',
'-webkit-transform': 'scale(' + percent + ')',
'-ms-transform': 'scale(' + percent + ')'
});
}
Then, for your droppable script, I changed the formula for element_top and element_left:
// old formula
element_top = (y - documentBg.offset().top - draggable.height() * (percent - 1) / 2) / percent
element_left = (x - documentBg.offset().left - draggable.width() * (percent - 1) / 2) / percent
// new formula
element_top = (y - documentBg.offset().top) / (percent * 0.915)
element_left = (x - documentBg.offset().left) / (percent * 0.915)
It gives an "almost" accurate result, but you may be able to tweak it further to polish it. Hope this helps.
For attaching elements with cursor during dragging you just need to use
cursorAt: { top: 6, left: -100 }
And a little change in top and left parameters of "sm_textbox_item".
top: (y - documentBg.offset().top) / (percent) + "px",
left: (x - documentBg.offset().left) / (percent) + "px",
For the large box again some tweak in top and left element is required (pen updated).
top: element_top-3,
left: element_left+6.49,
I forked your pen and did some changes. I know that this is not a perfect solution, i am also trying to solve this bit by bit. You can check it here
#ITWitch is right, there have to be some bug in draggable().
Style margin: 0 auto; in #sm_textbox_item is the source of problem.
Try to add this to draggable options in your draggableType directive to correct the position:
cursorAt: {left: -parseInt(window.getComputedStyle(element[0],null,null)['margin-left'])},
This problem occurs when you add a transform to a element's style, then make it draggable. You'll have to make do without transform to have a perfect result. I spent 2 days debugging till I found it out, and I didn't want someone else to go through that pain.
I have an Angular application that loads multiple images on to the page at random locations by utilizing the following code:
HTML:
<div ng-repeat="s in selectedImages" class="container">
<img ng-src="{{s.img}}" class="sImage" ng-style="s.pos"/>
</div>
CSS:
.wordImage {
position:absolute;
width:100px;
}
JS Controller:
function loadImages() {
$scope.myImages = ['img1.png', 'img2.png', 'img3.png', 'img4.png', 'img5.png']
$scope.selectedImages = [];
for (i in $scope.myImages) {
$scope.selectedImages.push(addRandomLocationToImage($scope.myImages[i]));
}
}
function addRandomLocationToImage(image) {
image.pos = {};
var preTop = getRandomHeight(); // get Height for this image
var preLeft = getRandomWidth(); // get Width for this image
image.pos = {top:preTop,
left:preLeft};
return image; // returns the same image object but contains pos{} for ng-style
}
function getRandomHeight() {
var imgHeight = 100;
var winHeight = $(window).height();
var randomH = Math.random() * (winHeight - 100); // subtract 100 for the header. and also footer padding
if (randomH < 150) {
randomH += 150; // add to keep it out of the header
}
if(winHeight - randomH < 100) { // if image will be on bottom edge of page
randomW -= imgHeight; // subtract 100 because that is the height of the images, this will prevent them from being partially off the page
}
return randomH;
}
function getRandomWidth() {
var imgWidth = 100;
var winWidth = $(window).width();
var randomW = Math.random() * winWidth;
if (randomW < 0) { // make sure it is not less than zero, then assign new number until it is greater than zero
while (randomW < 0) {
randomW = Math.random() * winWidth;
}
}
if (winWidth - randomW < 100) { // if image will be on right edge of page
randomW -= imgWidth; // subtract 100 because that is the width of the images, this will prevent them from being partially off the page
}
return randomW;
}
loadImages();
This definitely generates random images on a page...but they overlap very easily. My question is, how can I prevent them from overlapping? Here is some code that I have been working on.
var newLeft = currentImage.pos.left;
var newTop = currentImage.pos.top;
for (i in $scope.selectedImages) {
var originalLeft = $scope.selectedImages[i].pos.left;
var originalTop = $scope.selectedImages[i].pos.top;
if ((originalLeft - newLeft < 100 && originalLeft - newLeft > -100) && // could overlap horizontally
(originalTop - newTop < 100 && originalTop - newTop > -100)) { // could overlap vertically
//do something to select a new random location.
}
}
Basically you have to check a image position with every other image. You can use Array.some for this:
Considering that you store the image position in the image object as
x and y properties
function checkCollision(testImage) {
return $scope.myImages.some(function(img) {
if (img == testImage)
return false;
if (!img.x || !img.y) // Image has no position yet
return false;
return
testImage.x < img.x + imgWidth &&
testImage.x + imgWidth > img.x &&
testImage.y < img.y + imgHeight &&
testImage.y + imgHeight > img.y;
});
}
You have to be aware that depending of the available space and image sizes there might be a situation where is not possible to find a suitable position for a image.
I made a functional example.
I have a box, which I am trying to size perfectly to fit within the browser viewport if the image is not larger then it. So the image would appear to be centered within the window.
Currently I don' think my method of seeking the browser height is working. And for some reason there is a lot of extra space
Example (src)
here is where I define the page sizes
if ( style['img-width'] > screenwidth ) {
style['body-width'] = style['img-width'] + ( style['img-padding'] * 2 );
} else {
style['body-width'] = screenwidth;
}
style['body-height'] = ( style['img-height'] > screenheight ) ?
( style['img-height'] +
( style['img-padding'] * 2 ) +
style['header-height']
) :
screenheight;
$('body').css({ 'width': style['body-width']+'px' });
theater.css({
'width': style['body-width']+'px',
'height': style['body-height']+'px',
});
theaterheadcon.css('width', style['body-width']+'px');
theaterheader.css('width', style['body-width']+'px');
How I am defining screen width/height
screenwidth = isNaN(window.outerWidth) ? window.clientWidth : window.outerWidth,
screenheight = isNaN(window.outerHeight) ? window.clientHeight : window.outerHeight;
Here is the basic of centering items to a content with javascript and css:
/*css*/
#myImage
{
position:absolute;
}
And in java:
/*javascript*/
var img=$('#myImage');
var winWidth=$(window).width();
var winHeight=$(window).height();
if(img.height()>winHeight)
{
img.css('height', winHeight + "px");
}
img.css('left',(winWidth/2) + "px");
img.css('top',(winHeight/2) + "px");
img.css('margin-left',(-(img.width()/2)) + "px");
img.css('margin-top',(-(img.height()/2)) + "px");
The margin approach guaranties that the image will stay at the center even on page resize
I tried here in DIVs in your case code will detect your image size itself
$(document).ready(function(){
var windowheight = $(window).height();
var windowwidth = $(window).width();
var boxheight = $('#box').outerHeight();
var boxwidth = $('#box').outerWidth();
var imgheight = $('.img').outerHeight();
var imgwidth = $('.img').outerWidth();
if(imgheight > boxheight || imgwidth > boxwidth){
$('#box').css('height', windowheight).css('width', windowwidth);
$('.img').css('margin-left',((windowwidth - imgwidth)/2)+'px');
$('.img').css('margin-top',((windowheight - imgheight)/2)+'px');
}
});
DEMO
change your img width in css to see the action
if you want your div to not going outside the window after margin the image to center use that code
$(document).ready(function(){
var windowheight = $(window).height();
var windowwidth = $(window).width();
var boxheight = $('#box').outerHeight();
var boxwidth = $('#box').outerWidth();
var imgheight = $('.img').outerHeight();
var imgwidth = $('.img').outerWidth();
if(imgheight > boxheight || imgwidth > boxwidth){
$('#box').css('position','absolute').css('width', 'auto').css('height', 'auto').css('left', '0').css('top', '0').css('right', '0').css('bottom', '0');
$('.img').css('margin-left',((windowwidth - imgwidth)/2)+'px');
$('.img').css('margin-top',((windowheight - imgheight)/2)+'px');
}
});
DEMO
I´m working on this website
I´m doing the resize of vertical images using this script:
function Gallery(selector) {
this.add_module = function (type, image) {
var portrait_text = image.next('.portrait_text');
var container = $('<div />', {
'class': 'gallery_container'
}).append(image).append(portrait_text);
if (type == 'horizontal') {
var h_ar = image.attr('height') / image.attr('width');
var c_width = selector.width();
var c_height = selector.width() * h_ar
container.css({
'width': c_width,
'height': c_height
})
}
if (type == 'vertical') {
var c_width = v_width;
var c_height = v_height
container.css({
'width': Math.floor(v_width),
'height': v_height
})
}
container.css({
'float': 'left',
})
container.find('img').attr({
'width': '100%',
'height': '100%'
})
container.attr('ar', c_height / c_width)
container.appendTo(selector);
//container.children('img').fitToBox();
}
this.resized = function () {
//console.log(sel)
$('.gallery_container').each(function () {
if ($(this).attr('ar') >= 1) { // vertical
$(this).css({
'width': sel.width() / 2,
'height': sel.width() / 2 * $(this).attr('ar')
})
} else { // horizontal
$(this).css({
'width': sel.width(),
'height': sel.width() * $(this).attr('ar')
})
}
})
}
var _this = this;
var gutter = 0;
// start vars for counting on vertical images
var v_counter = 0;
var w_pxls = 0;
var h_pxls = 0;
var v_ar;
// iterates through images looking for verticals
selector.children('img').each(function () {
if (parseInt($(this).attr('width')) < parseInt($(this).attr('height'))) {
v_counter++;
h_pxls += $(this).attr('height');
w_pxls += $(this).attr('width');
v_ar = $(this).attr('height') / $(this).attr('width')
}
})
// calculates average ar for vertical images (anything outside from aspect ratio will be croped)
var h_avrg = Math.floor(h_pxls / v_counter);
var w_avrg = Math.floor(w_pxls / v_counter);
var v_width = Math.floor((selector.width()) / 2);
var v_height = v_width * v_ar;
var sel = selector;
selector.children('img').each(function () {
if (parseInt($(this).attr('width')) > parseInt($(this).attr('height'))) {
_this.add_module('horizontal', $(this));
} else {
_this.add_module('vertical', $(this));
}
})
$(window).bind('resize', _this.resized);
}
var gallery = new Gallery($('#gallery_images_inner'));
http://jsfiddle.net/mZ2Ks/
The problem I have is that the script makes all the container the same of height (depending on the last image on the page I think), so for example first images resizes in a bad way. If you look at the example, all 2 image rows have a height of 613px.
Is there any way how can I control each two images container to calculate it´s own height based on its images, it looks like right now it calculates the last image resize height and apply it to all other containers
Applying height: auto instead of 100% won´t work cause it will not make the images fit the height of the vertical container.
How can I fix the script?
yes, there is a easy way. but frist: your gallery-script calculates a average aspect ratio for all images inside. there is no simple way to change this behavior.
But you can do this simple workaround: put echt two images in their own gallery!
var gallery1 = new Gallery($('#gallery_images_inner1'));
var gallery2 = new Gallery($('#gallery_images_inner2'));
var gallery3 = new Gallery($('#gallery_images_inner3'));
See http://jsfiddle.net/mZ2Ks/2/ - i had to clean up your html code a little bit - you copied the "javascript affected" html code from (i assume) firebug, but you should have copied the plain html from source code direct (CTRL + U in firefox).