Size of Icon feature is calculated wrong - openlayers-3

I am currently writing an implementation where the user is able to upload a blueprint and place it on the map.
Problem is that the icon feature is registered as a sub-extent of the actual image-extent.
When full image is shown all is good:
https://s24.postimg.org/lj3xmgsj9/image.png
When I move the map to the left, the image disappears as soon as the tie-fighter starts to leave the view:
https://s23.postimg.org/4p2tu0c5n/image.png
This is a problem since my users will have to be able to zoom in at the corners of their uploaded blueprint.
The following URL shows a working implementation is OL2:
http://gis.ibbeck.de/ginfo/apps/OLExamples/OL27/examples/ExternalGraphicOverlay/ExternalGraphicOverlay.asp
Here everything works great.
Is this a bug in OL3 or am I doing something wrong?
Switching to OL2 is not an option as we already have a lot of OL3 code.
The following code was used:
(drag, rotate, scale was removed to make a minimum working example)
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
new ol.layer.Vector({
source: new ol.source.Vector({
features: [
new ol.Feature(new ol.geom.Point([1389519.3624186157, 7496787.364362017]))
]
}),
style: new ol.style.Style({
image: new ol.style.Icon({
src: 'https://lumiere-a.akamaihd.net/v1/images/millennium-falcon-4_9c006047.jpeg',
scale: 0.75
})
})
})
],
target: 'map',
view: new ol.View({
center: [1389519.3624186157, 7496787.364362017],
zoom: 18
})
});
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<script src="https://openlayers.org/en/v3.20.1/build/ol.js"></script>
</head>
<body>
<div id="map" class="map"></div>
</body>
</html>

If you have larger icons, you will have to set the renderBuffer property of ol.layer.Vector (default: 100px), so that OpenLayers includes the feature even though the actual geometry is outside the view extent.
new ol.layer.Vector({
renderBuffer: 600,
...
})
https://jsfiddle.net/nptq3hjy/

Related

How to position an image in OpenLayers 3 map?

I have a png image of other map that I know the original bounding box and the original projection. This image is 400x400 large but I have control over its width and height and can generate any size I want.
How can I position this image over my OL map in the correct location?
Both have same SRID.
Sorry guys. I need to learn to search a little more before ask.
var imageLayer = new ol.layer.Image({
source: new ol.source.ImageStatic({
url: 'http://localhost:8080/mclm/img/export.png',
projection: 'EPSG:4326',
imageExtent: [-44,-23,-42,-21]
})
});

Image feature is not fully clickable in openlayers 3

I have a feature with an Image, it shows well on the map.
var style = new ol.style.Style({
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ ({
src: imagesource,
})),
});
But when I add a select control on the layer
var selectcontrol = new ol.interaction.Select({
});
Only part of the image is clickable if the image is larger. Is there any settings to set here so that the whole image is clickable.
Here is a fiddle for the issue, you can see the cursor changes as you move to the center of the image, but the feature is not detected at the corners of the image
http://jsfiddle.net/c88keve7/2/
You can set the renderBuffer property when creating your vector layer. See ol.layer.Vector:
renderBuffer: The buffer around the viewport extent used by the renderer when getting features from the vector source for the rendering or hit-detection. Recommended value: the size of the largest symbol, line width or label. Default is 100 pixels.

Images along on a line

I am wondering how to place images on a line. For example, instead of a dotted or dashed line, I could include a symbol of a ship or a character (e.g. |) repeated along the line.
My current code:
line = new ol.geom.LineString([[0, 0], [100, 100]]);
lineStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'black',
width: 5,
lineDash: [10, 10]
}),
});
lineFeature = new ol.Feature({
geometry: line,
});
lineFeature.setStyle(lineStyle);
. . .
map = new ol.Map({
layers: [
new ol.layer.Vector({
source: new ol.source.Vector({
features: [
lineFeature,
],
}),
})
],
. . .
EDIT 2:
Here is what my line looks like:
(See image)
Here is what it should look like:
(See image)
It could be like this, or pictures of anchors.
EDIT:
New style code (not working):
lineStyle = new ol.style.Style({
radius: 10,
images: './icon.png',
stroke: new ol.style.Stroke({
color: 'black',
width: 5,
lineDash: lineDash,
}),
});
Am I doing anything wrong?
EDIT 3:
I have figured out how to do this:
Using Blender, add a mesh and add vertices on where the vertices are on your line.
Convert the mesh to a curve (Alt-C).
Add a plane and add your image to it as a texture.
Scale the plane to the appropriate size relative to the line (S).
Add an Array modifier to the plane with the image and choose Fit Curve for Fit Type.
Set the Curve: to the name of the curve you created from the mesh.
Set the Relative Offset’s first box to the space between the dots (relative to the size of the dots)
Add a Curve modifier to the plane and choose the curve you created as the Object:.
Note: This may result in the images being deformed. If this occurs, follow these steps:
Duplicate the plane (Alt-D)
Remove the Array and Curve modifiers from the duplicate.
Parent the duplicate plane to the original plane.
Select the duplicate plane, then the original plane.
Press Ctrl-P.
Select Object.
In the original plane, go to the Object buttons (orange cube) and select Faces under Duplication.
This will place a copy of the plane at the center of each face.
There is currently no support for this in OpenLayers 3, I am also trying to find a mechanism that would work well and scale with many features. The only thing currently available in OpenLayers 3 to acheive this would be to use this technique, but it would greatly affect performance: http://boundlessgeo.com/2015/04/geometry-based-styling-openlayers-3/
A live example is available here:
http://openlayers.org/en/master/examples/line-arrows.html
To acheive the kind of style you want, you would have to compute points along the line for the given resolution and assign a ol.style.Icon for those points.
I guess it could be possible to implement more advanced stroke styles in OpenLayers 3, the following page demonstrates multiple techniques to render strokes with Canvas: http://perfectionkills.com/exploring-canvas-drawing-techniques/
lineStyle = new ol.style.Style({
image: new ol.style.Icon(({
opacity: 1,
size:20,
src: './icon.png'
})),
stroke: new ol.style.Stroke({
color: 'black',
width: 5,
lineDash: lineDash,
})
});
Visit these links to find more about this.
http://openlayers.org/en/v3.8.1/apidoc/ol.style.Style.html
http://openlayers.org/en/v3.6.0/apidoc/ol.style.Icon.html

Highcharts width exceeds container div on first load

I'm using Highcharts with jQuery Mobile.
I have an area graph being drawn within a jQM data-role="content" container and within that container I have the following divs:
<div style="padding-top: 5px; padding-bottom: 10px; position: relative; width: 100%;">
<div id="hg_graph" style="width: 100%"></div>
</div>
My highcharts graph is a basic graph taken from one of their examples where I have not set the chart width property.
On the first load the graph exceeds the width of the containing divs, but when I resize the browser it snaps to the appropriate width.
How can I make it so that the width of it is right on first page load and not just on resize?
I've reviewed similar posts on stack overflow and none of the solutions seem to work.
UPDATES
I've identified the problem is that the dynamically generated <rect> tag by Highcharts is taking the full width of the browser window on page load and not taking it from the containiner div width at all. Here's the html generated when I inspect:
<rect rx="5" ry="5" fill="#FFFFFF" x="0" y="0" **width="1920"** height="200"></rect>
I tried to reproduce in JSFiddle, but it seems to work fine there, which really has me stumped. Here's my JSFiddle code: http://jsfiddle.net/meandnotyou/rMXnY
To call chart.reflow() helped me.
Docs: http://api.highcharts.com/highcharts#Chart.reflow
this works like magic
put in your css file following
.highcharts-container {
width:100% !important;
height:100% !important;
}
I have the same problem, in my case had a graph of highchart that it is shown after click a button. I put $(window).resize(); after show event and it solved the problem correctly. I hope you serve.
Set width of the chart. That's the only option that worked for me.
chart: {
type: 'line',
width: 835
},
Define the highcharts inside the document ready:
<div style="width:50%" id="charts">
and the script:
$(document).ready(function(){
$(#chart).highcharts(){
...
});
)};
Hope it works ;)
I had a similar issue with centering the highcharts graph it gave. It would center and size correctly for some resolutions but not all. When it didn't, I had the exact same symptoms you're describing here.
I fixed it by attaching/overriding additional css to the highcharts default.
so in a custom css file, adding
.highcharts-container{
/** Rules it should follow **/
}
should fix your issue. Assuming that your div "hg=graph" has nothing but highcharts.
For those using angular and custom-built components, remember to define a dimensioned display in css (such as block or flex) for the host element.
And when the chart container has padding, you might find this indispensable:
html
<chart (load)="saveInstance($event.context)">
...
</chart>
ts
saveInstance(chartInstance: any) {
this.chart = chartInstance;
setTimeout(() => {
this.chart.reflow();
}, 0);
}
Otherwise the chart will bleed past the container on load and get its correct width only at next browser reflow (eg. when you start to resize window).
The best way is to call chart.reflow in render event function documentation;
Highcharts.stockChart( 'chartContainer', {
chart: {
events: {
render: function() {
this.reflow();
}
},
zoomType: 'x',
...
},
and remember to set min-width to zero and overflow to hidden in chart container.
#chartContainter {
min-width: 0;
overflow: hidden;
}
I just ran into the same problem today - not on mobile, but with a window sized small on first page load. When the page loads, the chart is hidden, then after some selections on the page, we create the chart. We have set a min-width and max-width for the container in css, but not a width.
When the chart is being created, it needs to determine the dimensions to create the SVG . Since the chart is hidden, it cant get the dimensions properly so the code clones the chart container, positions it off-screen and appends it to the body so that it can determine the height/width.
Since the width is not set, the cloned div tries to take as much space as it can - up to the max-width that I had set. The SVG elements are created using that width, but added to the chart container div which currently is smaller (based on the size of the screen). The result is that the chart extends past the container div's boundaries.
After the chart has rendered the first time, the on-screen dimensions are known and the clone function is not called. This means that any window resizes, or reloading of the chart data cause the chart to size correctly.
I got around this initial-load problem by overriding the Highcharts function cloneRenderTo which clones the div to get dimensions:
(function (H) {
// encapsulated variables
var ABSOLUTE = 'absolute';
/**
* override cloneRenderTo to get the first chart display to fit in a smaller container based on the viewport size
*/
H.Chart.prototype.cloneRenderTo = function (revert) {
var clone = this.renderToClone,
container = this.container;
// Destroy the clone and bring the container back to the real renderTo div
if (revert) {
if (clone) {
this.renderTo.appendChild(container);
H.discardElement(clone);
delete this.renderToClone;
}
// Set up the clone
} else {
if (container && container.parentNode === this.renderTo) {
this.renderTo.removeChild(container); // do not clone this
}
this.renderToClone = clone = this.renderTo.cloneNode(0);
H.css(clone, {
position: ABSOLUTE,
top: '-9999px',
display: 'block' // #833
});
if (clone.style.setProperty) { // #2631
clone.style.setProperty('display', 'block', 'important');
}
doc.body.appendChild(clone);
//SA: constrain cloned element to width of parent element
if (clone.clientWidth > this.renderTo.parentElement.clientWidth){
clone.style.width = '' + this.renderTo.parentElement.clientWidth + 'px';
}
if (container) {
clone.appendChild(container);
}
}
}
})(Highcharts);
I saved this function in a separate script file that loads after the Highchart.js script has loaded.
try and encapsulate the highchart generation inside a pageshow event
$(document).on("pageshow", "#hg_graph", function() {...});
I resolved this problem (for my case) by ensuring that the containing UI elements render before the chart, allowing Highcharts to calculate the correct width.
For example:
Before:
var renderChart = function(){
...
};
renderChart();
After:
var renderChart = function(){
...
};
setTimeout(renderChart, 0);
I have been having this issue too, and the .highcharts-container css solution wasn't working for me. I managed to solve it for my case by splitting out an ng-class condition (which was setting different widths for the container div) into separate divs.
eg, this
<div ng-class="condition?'col-12':'col-6'">
<chart></chart>
</div>
into
<div ng-show="condition" class="col-12">
<chart></chart>
</div>
<div ng-show="!condition" class="col-6">
<chart></chart>
</div>
I couldn't really tell you why it worked though. I'm guessing the ng-class takes longer to calculate the container width and so highcharts renders first with an undefined width? Hopefully this helps someone anyway.
I also have the same issue in my app where i am using angular
and i also using ngCloak directive which i have removed as i don't need it
after doing this my problem is solved.
I have just seen that sometimes there are several issues going on at the same time.
If it happens the height exceed the expected heigh:
SCSS style:
.parent_container{
position:relative;
.highcharts-container{position: absolute; width:100% !important;height:100% !important;}
}
If the width exceeds the container (bigger than what's supposed to) or does not resize properly to smaller one:
let element = $("#"+id);
element.highcharts({...});
// For some reason it exceeds the div height.
// Trick done to reflow the graph.
setTimeout(()=>{
element.highcharts().reflow();
}, 100 );
The last one happened to me when destroying the chart and creating a new one... the new one was coming with width extra size.
I have been also bump into this issue. both affected in desktop and mobile view of the chart.
In my case i have a Chart that update the series color depending on min or max.After updating the points, the highcharts width exceeds container div on its first load.
To fix that, what i did is add chart.reflow(); after the update of points.
CODE:
//First declare the chart
var chart = $('#TopPlayer').highcharts();
//Set the min and max
var min = chart.series[0].dataMin; //Top Losser
var max = chart.series[0].dataMax; //Top Winner
for (var i = 0; i < chart.series[0].points.length; i++) {
if (chart.series[0].points[i].y === max) {
chart.series[0].points[i].update({
color: 'GREEN',
});
}
if (chart.series[0].points[i].y === min) {
chart.series[0].points[i].update({
color: 'RED',
});
}
}
// redraw the chart after updating the points
chart.reflow();
Hope this helps to those who has the same issue like me. :)
Here's a solution that worked for me ! The charts were working fine for a while and then after a feature they started exceeding their container. Turns out it was the defer attribute on the script in the head of my application.
Try removing defer on your javascript tags:
<script defer src="script.js"></script>
to
<script src="script.js"></script>
Or moving my stylesheet link higher in the head also seemed to fix it but it's a less reliable solution..
This may have been introduced since the OP in 2013, but you should be able to set height with chart.height (https://api.highcharts.com/highcharts/chart.height)
options: {
chart: {
type: 'bar',
height: window.innerHeight + 'px',
},
title: {
text: 'Top 10 Users',
},
subtitle: {
text: 'by scores',
},
This is a web based solution, but I would expect you could cater it to jQuery.mobile
None of the answers helped me. I dynamically change chart data and the top answer solution ruins the animations and causes a jump in the chart position.
The workaround that I finally came up with was to set some padding for the chart wrapper element (in my case some part of the chart to left was hidden, so I gave some left padding), and then set the chart main element overflow property to visible. It works and the animations are just fine. You may need some experimenting with padding value to get it perfectly displayed.
<div class="chart-wrapper">
<!-- high charts main element here -->
</div>
and the style
.chart-wrapper{
padding-left: 20px;
}
.chart-wrapper > div:first-child{
overflow: visible !important;
}
for me, I set chart width:
$('#container').highcharts({
chart: {
backgroundColor: 'white',
**width:3000**,
..... }
and in html set overflow:auto
<div id="container" style="**width:100%;overflow:auto**;" ></div>
I struggled with this for way too long, and found a solution that works for me. A little bit of background on my setup:
The highcharts chart was loading on a tab on my website that is not visible upon logging into the site.
When switching to that tab, the chart was well outside the div.
So, I attached a unique ID to that particular tab, we'll call it tab5, and then bound a click function that forced - and this is the important part - the <svg> element within the container div to 100% using jQuery:
$('#tab5').bind('click', function() {
$('#container_div svg').width('100%');
});
...and my sanity has been restored. For the moment.
Please add width:100% to chart container.
Hope this will resolve overflow:hidden related issue.
classname{min-height:450px;width: 100%;}

iPad "3" HTML5 Canvas Drawing Resolution

I've been toying around with iPad and HTML5 but since the display is retina, the text on my screen seems to be of low resolution. As do lines drawn with lineTo/moveTo/stroke. Note the text is drawn with context.fillText()
I suspect this is just because I haven't set up the canvas correctly to handle the retina pixel ratio, so hopefully someone here can figure out what exactly I'm doing wrong.
I have set up the canvas as follows:
<div id="container">
<canvas id="canvas"></canvas>
</div>
With CSS attributes:
#canvas {
width: 1024px;
height: 768px;
}
#container {
width: 1024px;
height: 768px;
}
and in JavaScript (as I have seen to do on the internet) I have specified:
canvas.width = 2048;
canvas.height = 1536;
Unfortunately this does not stop the pixelation as it has for some other users.
Am I missing something or have I specified something incorrectly?
Try adding this line to your page head:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
This tag makes sure that the page is shown in its original size, and remains in that size.

Resources