HTML5 Drag-Drop: SetDragImage not working - javascript

I'm new to front-end programming and experimenting with HTML5 drag-drop. The object to drag is a bootstrap div.panel which does its job pretty well. However, whilst the object is being dragged, I want to show a custom image using SetDragImage function. I've used this function precisely as described in the Mozilla Developer Network, but still its not working - the default blank rectangle is shown when the object is dragged.
Below is the JavaScript for the drag/drop events, and here is the JSFiddle.
<script type="text/javascript">
function drag(ev){
//var style = window.getComputedStyle(ev.target, null);
var ss = (parseInt($(ev.target).position().left,10) - ev.clientX) + ',' + (parseInt($(ev.target).position().top,10) - ev.clientY);
ev.dataTransfer.setData("text/plain", ss);
ev.dataTransfer.setDragImage(document.getElementById("draggit"), 0, 0);
console.log("drag:target", $(ev.target).position().left + "," + $(ev.target).position().top);
console.log("drag:offset", ss);
}
function drop(ev) {
//console.log("drop:" + $(ev.target).position().left + "," + $(ev.target).position().top);
//console.log("drop:" + ev.clientX + "," + ev.clientY);
var offset = ev.dataTransfer.getData("text/plain");
var npos = offset.split(",");
console.log("drop_clientpos:" + ev.clientX + "," + ev.clientY);
console.log("drop_newpos:" + (ev.clientX + parseInt(npos[0])) + "," + (ev.clientY + parseInt(npos[1])));
document.getElementById("dragme").style.left = (ev.clientX + parseInt(npos[0])) + "px";
document.getElementById("dragme").style.top = (ev.clientY + parseInt(npos[1])) + "px";
ev.preventDefault();
return false;
}
function dragOver(ev) {
ev.preventDefault();
return false;
}
</script>

Related

Add a Class to some items depending on inner html

I'm working on a leaflet js map atm.
There are some items that I want to apply a class to, depending on their inner text. Seems as though two circles at a certain size just overlap. Adding some CSS in that case so they're no longer overlapping.
//function searches for all <text> elements within svg tags for the queryText
// and then appends them with the appendText
function addClasserino() {
let elements = document.querySelectorAll('map-marker marker-bg-condition'); // get all circle elements as a NodeList
elements.forEach(el => { // go through each text element
if (el.innerText < 10) { // if the innerHTML matches the query HTML then
elements.addClass('updated'); // add the class
}
})
}
document.addEventListener("DOMContentLoaded", function(){
//pass in the search text and the appending text as arguments
addClasserino();
});
This is what I got so far. Doesn't seem to be working.
.map-marker.marker-bg-condition needs to be moved across a bit. Got the CSS here:
.map-marker.marker-bg-condition.updated{
margin-top: -19px;
margin-left: -19px;
}
With Leaflet JS, the zoom level changes and items are updated accordingly. This of my map showing all details at the world view, and then breaking down to state as you zoom in.
The unexpected behavior is that the css isn't applying and where bubbles are overlapping is because of this. This is the original code but I can't change it and get it to work even with an if statement.
getMarkerHtml: function(count, color) {
var size = this.getMarkerSize(count);
var hsize = (size / 2) - 6;
var font = count < 1000 ? Math.ceil(size / 3) : Math.ceil(size / 4);
if(count < 100) {
font = font + 3;
}
var cluster_classes = [
'map-marker',
'marker-bg-' + (Filters.colors.profile === color ? 'profile' : 'condition')
];
if(this.zoomLevel !== 'zip') {
size = size * 1.5;
if(petMapFilters.colors.profile !== color) {
hsize = size / 2;
}
}
if(this.zoomLevel === 'zip') {
var cluster_styles = [
'margin-left: -' + hsize + 80 + 'px;', NOTE: I tried this to offset on zip zoom bit it's not working END OF NOTE
'margin-top: -' + hsize + 80 +'px;',
'width: ' + size + 'px;',
'height: ' + size + 'px;',
'font-size: ' + font + 'px;'
];
} else {
var cluster_styles = [
'margin-left: -' + hsize + 'px;',
'margin-top: -' + hsize + 'px;',
'width: ' + size + 'px;',
'height: ' + size + 'px;',
'font-size: ' + font + 'px;'
];};
var div_style = [
'line-height: ' + (size - (size * 0.3)) + 'px;'
];
count = this.formatCount(count);
return '<div class="' + cluster_classes.join(' ') + '" tabindex="0" style="' + cluster_styles.join(' ') + '"><div style="' + div_style.join(' ') + '">' + count + '</div></div>';
},
Please let me know what I am doing wrong here as I am not able to identify this myself.
The issue at hand:
Thanks.

Play a sequence of images with JS, using $timeout to schedule frames

I'm using AngularJS to prefetch images in cache client and then I want to animate those prefetched images.
My code for the prefetching:
$scope.prefetch=function(limit) {
for (var i=0; i<limit; i++) {
var date = new Date($scope.dt);
if ($scope.fileFlag == false) {
if ($scope.viewmodel.timeResolution == 'yearly')
date = new Date(date.setFullYear(date.getFullYear() + i));
else if ($scope.viewmodel.timeResolution == 'monthly')
date = new Date(date.setMonth(date.getMonth() + i));
else if ($scope.viewmodel.timeResolution == 'daily') {
date = new Date(date.setDate(date.getDate() + i));
}
} else {
date = $scope.files[$scope.files.indexOf($scope.idSelectedVote) + i];
}
console.log( $http.get(site_url + "mwf/" + $scope.viewmodel.dataSet + "/" + $scope.viewmodel.varName + "/" + $scope.viewmodel.region + "/" + date + "/map/?vMin=" + $scope.VMin + "&vMax=" + $scope.VMax + "&type=" + $scope.viewmodel.type + "&cmap=" + $scope.viewmodel.colorMap, {'cache': true}));
}
};
then i do something like this to play those images
$scope.play=function(limit) {
for (var i=0; i<limit; i++) {
$scope.map.src= site_url + "mwf/" + $scope.viewmodel.dataSet + "/" + $scope.viewmodel.varName + "/" + $scope.viewmodel.region + "/" + parseInt(date)+i + "/map/?vMin=" + $scope.VMin + "&vMax=" + $scope.VMax + "&type=" + $scope.viewmodel.type + "&cmap=" + $scope.viewmodel.colorMap;
$scope.sleepFor(500);
}
};
$scope.sleepFor = function( sleepDuration ) {
var now = new Date().getTime();
while(new Date().getTime() < now + sleepDuration){ /* do nothing */ }
}
My problem is when I call play(4) it displays only the first and the last images and not an animation. Any idea on how can I improve this code or a different approach so I can do this?
Your sleepFor is an idle loop: you spin and do nothing, but you prevent any other work from being done. This is not the way in Javascript to delay work for a set period of time, or schedule a function to be run at a later time. In Javascript we use window.setTimeout -- and in Angular we have the convenient $timeout service to provide that:
$scope.play = function(limit) {
for (var i=0; i < limit; i++) {
$scope.map.src = site_url + "mwf/" + $scope.viewmodel.dataSet + "/" + $scope.viewmodel.varName + "/" + $scope.viewmodel.region + "/" + parseInt(date)+i + "/map/?vMin=" + $scope.VMin + "&vMax=" + $scope.VMax + "&type=" + $scope.viewmodel.type + "&cmap=" + $scope.viewmodel.colorMap;
var nextFrameMs = 500;
$timeout($scope.play, nextFrameMs);
}
};
In your example, wherever your $scope is provided to you -- assuming this is in a controller, you will have some line like module.controller($scope, ...) -- you will have to inject the $timeout service to be able to use it.
Additional resources:
Angular's documentation on $timeout
MDN documentation of window.setTimeout
You have to use intervals otherwise your code will block the execution of other code
Using Angular's built in $interval service is the solution:
var playInterval;
$scope.play = function(limit) {
var interval = 1000 / 20; //20 frames per second
var i = 0;
$interval.cancel(playInterval); //stop previous animations if any
if(i < limit) {
$scope.map.src = getSrc(i++);
var cache = $interval(function() {
if(i >= limit) {
return $interval.cancel(playInterval); //or you can replace with `i = 0;` to loop the animation
}
$scope.map.src = getSrc(i++);
}, interval);
}
};
function getSrc(i) {
return site_url + "mwf/" + $scope.viewmodel.dataSet + "/" + $scope.viewmodel.varName + "/" + $scope.viewmodel.region + "/" + parseInt(date)+i + "/map/?vMin=" + $scope.VMin + "&vMax=" + $scope.VMax + "&type=" + $scope.viewmodel.type + "&cmap=" + $scope.viewmodel.colorMap;
}

Scale Background CSS with Slider

I am working with some CSS Backgrounds (http://css3pie.com/demos/gradient-patterns/) in an application and want to be able to scale the design with a slider. Here's a JSFiddle. I was able to scale X & Y separately on some like the Stripes and Picnic designs where I just had to play with background-size:50px 50px; like this:
//setup the variables based off the css which was set using dropdown
gridItems = $(document.activeElement).val().split("; ");
for (i = 0; i < gridItems.length -1; i++) {
gridSettings = gridItems[i].split(":");
if (gridSettings[0]=="background-size"){
gridSize = gridSettings[1].split(" ");
gridX = gridSize[0];
gridY = gridSize[1]
}
//on the action of the slide - update value
$('#gridXY-'+key).on("slide", function(slideEvt) {
gridXY = slideEvt.value;
$('.draggable-' + currentLayer).css("background-size", "calc("+ gridX +" * "+ gridXY +") calc("+ gridY +" * "+ gridXY +")");
});
Which can be set either numerically or using but when it gets to something like the Blue Print it has a lot more settings background-size:100px 100px, 100px 100px, 20px 20px, 20px 20px;
I am trying to do this right so that it can take a variable number of those, and can write something that could work, but the method I have in mind is really messy, hoping for some help scaling this that might be a little cleaner than what I would do.
I did find this:http://codepen.io/Erik/pen/JGnsB but he is using LESS to declare variables, if possible I would like to stay away from that.
UPDATE:
Here is a JSFiddle of it: http://jsfiddle.net/4L3d9qh2/
I added a function that should have let me update it, but for some reason the calc() function doesn't seem to be working to update the div style. After processing, it looks like this:
$('.draggable-0').css("background-size", calc(100px - 4) calc(100px - 4), calc(100px - 4) calc(100px - 4), calc(20px - 4) calc(20px - 4), calc(20px - 4) calc(20px - 4));
$.each(gridSizeArray, function( k, v ){
if (gridIncrement==1)
{
gridXY = "calc(" + v +" - " + value + ") ";
}else{
if(isOdd(gridIncrement)){
gridXY = gridXY + "calc(" + v +" - " + value + ") ";
}else{
gridXY = gridXY + "calc(" + v +" - " + value + "), ";
}
}
gridIncrement++
})
Here was the final code that works. Using .each() loop through and if it is even, add a comma, then remove the last comma at the end.
gridItems = $(document.activeElement).val().split("; ");
for (i = 0; i < gridItems.length -1; i++) {
gridSettings = gridItems[i].split(":");
if (gridSettings[0]=="background-size"){
gridSizeString = gridSettings[1].replace(/,/gi, '');
gridSizeArray = gridSizeString.split(" ");
}
$('[data-type="sliderLayer"][data-layer="'+currentLayer+'"][data-slide="'+currentSlide+'"]').css(gridSettings[0], gridSettings[1]);
}
$.each(gridSizeArray, function( k, v ){
if (gridIncrement==1)
{
gridXY = "calc(" + v +" + " + value + "px) ";
}else{
if(isOdd(gridIncrement)){
gridXY = gridXY + " calc(" + v +" + " + value + "px) ";
}else{
gridXY = gridXY + "calc(" + v +" + " + value + "px),";
}
}
gridIncrement++
})
if (isOdd(gridIncrement))
{
gridXY = gridXY.substring(0, gridXY.length - 1);
}

Change width/height depending on class with data-attribute

I have the following JS code that changes the width depending on value of the data-percentage HTML attribute:
var addRule = (function (sheet) {
if(!sheet) return;
return function (selector, styles) {
if (sheet.insertRule) return sheet.insertRule(selector + " {" + styles + "}", sheet.cssRules.length);
if (sheet.addRule) return sheet.addRule(selector, styles);
}
}(document.styleSheets[document.styleSheets.length - 1]));
var i = 101;
while (i--) {
addRule("[data-percentage='" + i + "%']", "width:" + i + "%");
}
See the demo: http://jsfiddle.net/YYF35/
Instead of width, for some elements I want to change their height.
How can I change the code so that depending on class of the div I change the height or width of element (depending on the data-percentage attribute number of course)?
I don’t want to create a different HTML attribute for it, like so:
while (i--) {
addRule("[data-percentage-width='" + i + "%']", "width:" + i + "%");
addRule("[data-percentage-height='" + i + "%']", "height:" + i + "%");
}
jQuery can be used as well. Any ideas?
Your code is adding rules. If you really want to be doing that, just add more rules:
var i = 101;
while (i--) {
addRule("[data-percentage='" + i + "%'].change-width", "width:" + i + "%");
addRule("[data-percentage='" + i + "%'].change-height", "height:" + i + "%");
}
Now, elements with the change-width class will have their width modified, and elements with the change-height class will have their height modified (and you can use both if you like).
Try this:
$("div[data-percentage]").each(function(){
$(this).css({
width: $(this).attr('data-percentage')
//height: $(this).attr('data-percentage')
});
});
http://jsfiddle.net/YYF35/1/

How to combine two Javascript functions on the same object

I'm stuck trying to get random colour overlay on the pictures on this site.
http://www.reportageborsen.se/reportageborsen/wordpress
The Javascript I'm trying to combine are:
$(function() {
$('.media-box .mask').each(function() {
var hue = 'rgb(' + (Math.floor((256 - 199) * Math.random()) + 200) + ',' + (Math.floor((256 - 199) * Math.random()) + 200) + ',' + (Math.floor((256 - 199) * Math.random()) + 200) + ')';
$(this).css("background-color", hue);
});
});
///and///
$('.media-box').hover(function() {
$(this).find('.mask').stop(true, true).fadeIn();
}, function() {
$(this).find('.mask').stop(true, true).fadeOut();
});​
Is it possible to just get them together in some way?
Best Regards
Fortes
if you are looking to combine two functions in one, you may try this:
var getRandomInRange = function(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
$('.media-box').each(function() {
var mediaBox = $(this);
var mask = mediaBox.find('.mask');
var hue = 'rgb(' + getRandomInRange(200, 255) + ',' + getRandomInRange(200, 255) + ',' + getRandomInRange(200, 255) + ')';
mask.css("background-color", hue);
mediaBox.hover(function() {
mask.stop(true, true).fadeIn();
}, function() {
mask.stop(true, true).fadeOut();
});
});
Note, that I also moved random number generator to separate function, just for clarity. Let me know if this worked.

Categories

Resources