Leaflet divIcon doesn't appear when drawn - javascript

I have a sprite sheet with a bunch images of aircraft in various rotations. I'm trying to set my icon to the sprite based on heading. My heading rounding calculation is working and I'm writing the correct class but nothing appears when I draw it. My previous iteration without sprites and just a bunch of separate images and a regular icons worked fine so the drawing portion of the code should be fine. I simply changed the icon type. Any ideas? This is my new marker function
iconClass = '757_' + (Math.round(HDG/15)) * 15
var nIcon = L.divIcon({className: iconClass});
marker[i].setIcon(nIcon)
marker[i].setLatLng(coords);
marker[i].bindTooltip(CALL);
mymap.addLayer(marker[i]);
my style sheet looks like
.757_120{top:0px;left:0px;
width:36px;height:27px;background: url("images/sprites.png") no-repeat -116px -651px;}
.757_135{top:0px;left:0px;
width:33px;height:33px;background: url("images/sprites.png") no-repeat -292px -465px;}
loaded like
<link rel="stylesheet" href="images/sprites.css">
and
console.log(document.styleSheets)
seems to show that the style sheet is loaded

Turns out part of my issue was that class names cannot start with a number.

Related

How to hide the display of background HDR map, but save hdri's work for lighting in three.js?

I repeat this example in my code:
https://threejs.org/examples/?q=RGBELoader#webgl_loader_gltf
Source:
https://github.com/mrdoob/three.js/blob/master/examples/webgl_loader_gltf.html#L53
HDRI lighting works great. But i cant hide hdr map from background. Is there way to do this? To leave this hdri lightning and set a custom color for background.
Using the example you provided, and assuming you want to keep the reflections of the photo on the helmet but remove the photo from the background, all you have to do is remove (or comment out) the following line:
scene.background = cubeGenerator.renderTarget;
This will remove the photo from the background which will then display as the default color (black), as you can see from this screenshot:

Circular canvas corners clickable in Chrome

I have two canvases. I have made them circular using border-radius. The 2nd is positioned inside the first one (using absolute position).
I have click events on both circles. If you click on inside canvas, the color at the point of the click is loaded in the outside canvas with opacity varying from white to the picked color and finally to black. If you click on outer canvas the exact color value at that point is loaded in the text-box at the bottom
I am unable to click in red zones (as shown in figure below) of the outer canvas when using chrome. I tried z-idex, arcs but nothing is helping me. But In Firefox everything is working fine.
Note: You can drag the picker object in the outer circle. But if you leave it in red zones, you would not be able to click it again in Chrome. Clicking in green zone will get you its control again
Code in this JSFiddle
Edit
I excluded all irrelevant code to make it easy. Now there is only a container having two canvas.
Filled simply with two distinct colors. Open following fiddle link in both chrome and firefox. Click on both cirles in different zones and see difference in chrome and firefox. I want them to behave in chrome as they do in firefox
Note I will ultimately draw an image in inner canvas.
Updated Fiddle Link
-
Your problem is because canvases currently are always rectangular, even if they don't look rectangular. Border radius makes the edges except the circle transparent, but it still doesn't stop events in Chrome on the corner areas. This is why you cannot click the bottom circle in those areas
I even tried putting it inside of a container that had a border-radius instead but the click event still goes through
With that being said, you have two options. You could either change your code to only use one canvas with the same type of layout, just drawing the background circle before the other each time. Essentially you'd draw a circle, draw your black to color to white gradient, use the xor operation to combine the two into one circle, then do the same with the rainbox gradient. You must draw the background circle first because canvas paints over the old layers every time
or
You could use javascript to only detect clicks in the circular area which takes just a little bit of math (: This solution is featured in edit below
In the future, CSS Shapes may allow canvases to be non-rectangular elements to be used, I'm actually not sure, but we don't have that capability yet at least
Edit
Alright, so after going through your code a bit it seems there are some things I should cover before I offer a solution
Setup all your finite variables outside of the functions that run every time. This means you don't put them (like radiuses, offsets, etc.) in the click function or something that runs often since they don't change
Your "radius"es are actually "diameter"s. The format of .rect goes .rect(x, y, width (diameter of circle), height (diameter of circle))
Almost always when overlaying canvases like you are you want to make them equal dimensions and starting position to prevent calculation error. In the end it makes it easier, doing all relative positioning with javascript instead of mixing it with CSS. In this case, however, since you're using border-radius instead of arc to make a circle, keep it like it is but position it using javascript ....
jQuery isn't needed for something this simple. If you're worried about any load speed I'd recommend doing it in vanilla javascript, essentially just changing the .click() functions into .onclick functions, but I left jQuery for now
You can declare multiple variables in a row without declaring var each time by using the following format:
var name1 = value1,
name2 = value2;
Variables with the same value you can declare like so:
var name1 = name2 = sameValue;
When children have position:absolute and you want it to be positioned relative to the parent, the parent can have position:relative, position:fixed, or position:absolute. I would think you'd want position:relative in this case
When you don't declare var for a variable it becomes global (unlessed chained with a comma like above). For more on that read this question
Now, onto the solution.
After talking with a friend I realized I could sort do the math calculation a lot easier than I originally thought. We can just calculate the center of the circles and use their radiuses and some if statements to make sure the clicks are in the bounds.
Here's the demo
After everything is set up correctly, you can use the following to detect whether or not it's in the bounds of each
function clickHandler(e, r) {
var ex = e.pageX,
ey = e.pageY,
// Distance from click to center
l = Math.sqrt(Math.pow(cx - ex, 2) + Math.pow(cy - ey, 2));
if(l > r) { // If the distance is greater than the radius
if(r === LARGE_RADIUS) { // Outside of the large
// Do nothing
} else { // The corner area you were having a problem with
clickHandler(e, LARGE_RADIUS);
}
} else {
if(r === LARGE_RADIUS) { // Inside the large cirle
alert('Outer canvas clicked x:' + ex + ',y:' + ey);
} else { // Inside the small circle
alert('Inner canvas clicked x:' + ex + ',y:' + ey);
}
}
}
// Just call the function with the appropriate radius on click
$(img_canvas).click(function(e) { clickHandler(e, SMALL_RADIUS); });
$(wheel_canvas).click(function(e) { clickHandler(e, LARGE_RADIUS); });
Hopefully the comments above and code make enough sense, I tried to clean it up as best as I could. If you have any questions don't hesitate to ask!

Reloading an image after zooming in KineticJS

I have a group, inside of which is an image. I've got code working so you can zoom with the mouse wheel. When the zooming stops, I reload the image, in a larger size. I add the new image to the group ( the old image is still part of the group ) and then I do this:
img.remove();
img.destroy();
imgNew.moveToTop();
imgNew.offsetX = offset.x;
imgNew.offsetY = offset.y;
At the end of this code, my old image disappears and the new one is not visible. It has a position that is sane, and it is the child of my group. It has exactly the size I expect it to have ( it's absolute position is 0,0 and it's size is bigger than my canvas ). I've turned off clipping, so if it was visible anywhere, I'd see it. I've changed the position in the debugger, and called draw() on the canvas, the layer and the group. I have dragging code and I've dragged the drag control ( which is still there ) every where I can. I've also changed my code to just add the new image to the top level layer instead of the lower down group.
I should mention in case it's relevant, the image is coming from a WebAPI RESTful service, and the size is passed in, so the image URLs are different for the two images.
I simply cannot find my image !!! What should I do next ?
This:
KineticJS - How to Change Image src on Button Click
answered my question. Short version: there's a setImage method so you can load a new image, call setImage() and it gets replaced.

Is it possible to place size and number limitations in Leaflet.Draw?

This question is directed to Leaflet users (and those who use the Leaflet.draw plugin)...
I'm using Leaflet and would like to allow my user to draw 1--and only 1--single polygon over any area of the map. I would also like to limit the size of that polygon in some way (such as limiting the length of the side for a square or the area covered it covers--preferably specified in degrees so that the set size limits would translate regardless of the zoom level).
My end goal is simply to extract the coordinates of the 4 square vertices or the coordinates covered by the polygon area.
That said, I found the Leaflet.Draw plugin. It is fantastic, however, I need to limit its functionality to my requirements (only 1 polygon drawn at a time and, in particular, the size cannot be drawn too large). Is this possible to do? If so, how?
Regardless of if it is or is not possible, is there a better way to go about doing this?
Can I propose another solution to this issue?
I would limit the number of polygons to one by doing the following:
map.on('draw:created', function (e) {
var layer = e.layer;
if(drawnItems && drawnItems.getLayers().length!==0){
drawnItems.clearLayers();
}
drawnItems.addLayer(layer);
});
I am listening to the draw:created event and determine if there is already a marker. If there is, I remove that marker and place my new one in the desired location. Therefore, one less click for user as they no longer need to delete the previous and one marker rule is always enforced.
If you wanted to allow more than one marker you could do a FIFO delete of the oldest layer.
If you do not want to automatically delete a layer, you could either prompt the user or ignore the request.
That said, I found the Leaflet.Draw plugin. It is fantastic, however, I need to limit its functionality to my requirements (only 1 polygon drawn at a time and, in particular, the size cannot be drawn too large). Is this possible to do? If so, how?
I think you'll need to code it yourself.
I see two possibities:
hacking the draw plugin (writing your own code inside the plugin)
extending the L.Draw.Polygon class from the draw plugin (see the docs about OOP in Leaflet) to create a costum one
1 is faster, 2 is cleaner. You'll have to choose depending on the size of your project.
I did it without hacking the Leaflet Draw source.
After the controls are added to the map, I place a hidden div inside the controls. Then when a polygon is created I display that div. I used CSS to absolute position it over the controls so the buttons are then "disabled" and CSS to make the buttons look faded. If the polygon is deleted then I hide that div.
Not the best solution, but I works without having to edit the source.
After drawControl is added, I add the hidden div:
$('.leaflet-draw-section:first').append('<div class="leaflet-draw-inner-toolbar" title="Polygon already added"></div>');
Here's the JS to toggle them:
map.on('draw:created', function (e) {
var type = e.layerType,
layer = e.layer;
// keep the polygon on the map
drawnItems.addLayer(layer);
// disable the create polygon tools
$('.leaflet-draw-inner-toolbar').show();
});
map.on('draw:deleted', function(e) {
// enable the create polygon tools
$('.leaflet-draw-inner-toolbar').hide();
});
Here's the CSS:
.leaflet-draw-inner-toolbar {
background: none repeat scroll 0 0 rgba(255, 255, 255, 0.6);
bottom: 0;
display: none;
left: 0;
position: absolute;
right: 0;
top: 0;
}

Plotting image icon on top of a static image

To better understand my question, please refer to the following image.
http://i.imgur.com/yL0nD4h.jpg
I have two images. The map image and the blue circle image. Please note that the map image is only an image and I am not using the Google Maps API to display it. As it will always be the same view. What I am trying to accomplish is trying to move the blue circle along the black line and I want it to be able to move the circle dynamically with a simple incremental int number
So if my int push = 5
The circle on the map will move up by a certain distance and int push = -5 will bring it back.
Currently I have a simple html background with the map image and have places the blue circle on top with a image tag as follows
<div style="background-image:url('http://i.imgur.com/ZZHnuaf.png'); width:517px;height:374px;">
<img width="30px" height="30px"src="http://i.imgur.com/MUlVIyg.png" />
</div>
http://jsfiddle.net/rayshinn/9VqQ7/
Any help on how I can get started would be greatly appreciated! Also thank you very much for taking your time to read this.
So the main idea is having a function f(v) which returns an object with a x and y coordinate. Then you position the marker image relatively inside the map and change the left and top style attributes to move it around.
Here's an example http://jsfiddle.net/9VqQ7/2/

Categories