I have a problem when I use drawImage function to draw an image inside an html5 canvas ;used with a code Sencha Touch 2 images look blu and they don't have height quality this is the code:
//We've added a third and final item to our tab panel - scroll down to see it
var index=0;
Ext.application({
name: 'Sencha',
launch: function() {
var panel = Ext.create("Ext.Panel", {
fullscreen: true,
items: [
{
title: 'Home',
iconCls: 'home',
cls: 'home',
width: '533px',
listeners: {
painted: function() {
var a={Source:'images/2.tiff',Titre:'T1',Description:'D1'};
var b={Source:'images/Im2.jpg',Titre:'T1',Description:'D1'};
var c={Source:'images/Im3.jpg',Titre:'T1',Description:'D1'};
var d={Source:'images/Im4.jpg',Titre:'T1',Description:'D1'};
var e={Source:'images/Im5.jpg',Titre:'T1',Description:'D1'};
var f={Source:'images/Im6.jpg',Titre:'T1',Description:'D1'};
var img = new Image();
var img1 = new Image();
var img2 = new Image();
img.src = "images/Im1.jpg";
img1.src = "images/Im2.jpg";
img2.src = "images/Im3.jpg";
var ImageP = new Image();
//********************
var x,y,Dim_Image,espacement;
Dim_Image=50;
espacement=30;
var Presentation=new Array();
Presentation[0]=a;
Presentation[1]=b;
Presentation[2]=c;
Presentation[3]=d;
Presentation[4]=e;
Presentation[5]=f;
//********************
//°°°°°°°°°°°°°°°°°°°°°°
/* Ici on teste le tableau*/
var testImage = new Array();
//cw-(i*espacement),i*espacement,Dim_Image,Dim_Image);
var j=0;
for(i=index;i<index+3;i++)
{
testImage[i]= new Image();
testImage[i].src=Presentation[i].Source;
testImage[i].onload = function()
{
context.drawImage(testImage[j],cw-80-(j*espacement),20+j*espacement,Dim_Image,Dim_Image);
j++;
}
}index = index +1;
var img = new Image();
var canvas = document.getElementById('mycanvas');
var context = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
//Event================================================================
canvas.addEventListener("mousedown" ,function(event){
testImage = new Array();
context.clearRect(0,0,300,300); // clear canvas
var j=0;var inf =index;var ss;
for(i=index;i<index+3;i++)
{
testImage[i-index]= new Image();
testImage[i-index].src=Presentation[i].Source;
if( i == index+2)
{alert("index +3");
testImage[i-index].onload = function()
{context.globalAlpha=1;
context.drawImage(testImage[j],cw-80-(j*espacement),20+j*espacement,Dim_Image,Dim_Image);
j++;
}
}
else{
testImage[i-index].onload = function()
{context.globalAlpha=0.5;
context.drawImage(testImage[j],cw-80-(j*espacement),20+j*espacement,Dim_Image,Dim_Image);
j++;
}
}
}
index=index+1;
context.stroke();
},false);
context.strokeStyle = 'black';
context.stroke();
//};
},
scope: this
},
html: [
' <canvas id="mycanvas" style="background-color:grey; width:100%; height:100%;">no canvas support</canvas>'
]
} //this is the new item
]
});
}
});
What exactly you are trying to achieve?
Perhaps the problem is related to the drawImage method type you are using
Have a look at this link on the usage how to use, and what exactly the parameters that you added means.
Problem may be aspect ratio , width , height calculation from your side.
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage
Related
i have created one canvas by using canvg plugin.
Then i want to put another background image below canvas using ctx.drawimage() [created by canvg].
I tried .
Please suggest.
var svgString = new XMLSerializer().serializeToString(document.querySelector('svg'));
var canvas = document.getElementById("canvas");
var DOMURL = self.URL || self.webkitURL || self;
ctx = canvas.getContext("2d");
canvg(canvas, svgString, { ignoreMouse: true, ignoreAnimation: true});
var img1 = new Image();
img1.onload = function() {
ctx.drawImage(img1, 136, 136);
var png = canvas.toDataURL("image/png");
document.querySelector('#chart').innerHTML = '<img src="'+png+'"/>';
DOMURL.revokeObjectURL(png);
};
img1.src= "chart.png";
This is working. Used ctx.drawSvg(svgString,0,0,500,500); instead of drawImage
var svgString = new XMLSerializer().serializeToString(document.querySelector('svg'));
var canvas = document.getElementById("canvas");
var DOMURL = self.URL || self.webkitURL || self;
var ctx = canvas.getContext("2d");
var DOMURL = self.URL || self.webkitURL || self;
var img = new Image();
//var svg = new Blob([svgString], {type: "image/svg+xml;charset=utf-8"});
var svg = new Blob([svgString], {type: "image/svg+xml"});
var url = DOMURL.createObjectURL(svg);
var png = '';
var img1 = new Image();
img1.onload = function(){
ctx.drawImage(img1, 136, 136);
ctx.drawSvg(svgString,0,0,500,500);
var png = canvas.toDataURL("image/png");
document.querySelector('#chart').innerHTML = '<img src="'+png+'"/>';
DOMURL.revokeObjectURL(png);
};
img1.src = 'chart.png';
I am trying to invert the color of an image. Now the image loads ok, but when I try to call getImageData and putImageData back onto the canvas. The canvas is simply blank. Then I printed out all imageData, it appears like that it is always 0 for some reason. I am seriously troubled by this. Please help and thx in advance!
window.onload = function() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var img = new Image();
img.src = "hand.jpg";
img.onload = function() {
ctx.drawImage(img, 10, 10,50,50);
}
var imgData = ctx.getImageData(10,10,50,50);
console.log(imgData.data.toString()); //return 0's
for (var i=0;i<imgData.data.length;i+=4)
{
imgData.data[i]=255-imgData.data[i];
imgData.data[i+1]=255-imgData.data[i+1];
imgData.data[i+2]=255-imgData.data[i+2];
imgData.data[i+3]=255;
}
ctx.putImageData(imgData,100,100);
}
You need to wait for the image to load
window.onload = function() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var img = new Image();
img.src = "hand.jpg";
//================================================================
// this event will only get called after you have returned from this function
img.onload = function() {
ctx.drawImage(img, 10, 10,50,50);
}
//================================================================
// The image has not loaded at this point
// the following code will always be working on an empty canvas
var imgData = ctx.getImageData(10,10,50,50);
console.log(imgData.data.toString()); //return 0's
for (var i=0;i<imgData.data.length;i+=4)
{
imgData.data[i]=255-imgData.data[i];
imgData.data[i+1]=255-imgData.data[i+1];
imgData.data[i+2]=255-imgData.data[i+2];
imgData.data[i+3]=255;
}
ctx.putImageData(imgData,100,100);
//================================================================
// onload will fire after this point
}
To fix
window.onload = function() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var img = new Image();
img.src = "hand.jpg";
img.onload = function() {
ctx.drawImage(img, 10, 10,50,50);
var imgData = ctx.getImageData(10,10,50,50);
for (var i=0;i<imgData.data.length;i+=4){
imgData.data[i]=255-imgData.data[i];
imgData.data[i+1]=255-imgData.data[i+1];
imgData.data[i+2]=255-imgData.data[i+2];
imgData.data[i+3]=255;
}
ctx.putImageData(imgData,100,100);
}
}
BTW you can invert the image colours with
ctx.globalCompositeOperation = "difference";
ctx.fillStyle = "white"
ctx.fillRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.globalCompositeOperation = "source-over"; // restore default
I am a new user and cannot comment on this post: dragging and resizing an image on html5 canvas regarding drag and drop/resize image with anchors...
could someone please clarify how to apply the resize/drag/anchors to an uploaded image rather than a pre-loaded image please?
I have had a go but its killing me..
uploader html:
<input type="file" id="imageLoader" name="imageLoader" />
uploader js:
var imageLoader = document.getElementById('imageLoader');
imageLoader.addEventListener('change', handleImage, false);
function handleImage(e) {
var reader = new FileReader();
reader.onload = function (event) {
var img = new Image();
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, 200, 140);
}
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
fiddle
your code is written to handle the global var img.
When you load a new image, a new local img var is created, which you only draw on the context.
What you need is to have the new image replace the old one.
So just change, in your file loader :
function handleImage(e) {
var reader = new FileReader();
reader.onload = function (event) {
img = new Image(); // not 'var img=...'
img.onload = function () {
draw(true,true); // just update your app
}
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
it workd, as you can see here :
http://jsfiddle.net/LAS8L/108/
I found this script.
It allows to create a info window with google api. I modified it to fit my needs but I can't forbid it to open all infowindows automatically when I load the page (I only want a single info window appears when the costumers click on the marker).
Someone can help me?
<script type="text/javascript"
src="http://maps.googleapis.com/maps/api/js?sensor=true">
</script>
<script type="text/javascript">
var browserSupportFlag = new Boolean();
/* An InfoBox is like an info window, but it displays
* under the marker, opens quicker, and has flexible styling.
* #param {GLatLng} latlng Point to place bar at
* #param {Map} map The map on which to display this InfoBox.
* #param {Object} opts Passes configuration options - content,
* offsetVertical, offsetHorizontal, className, height, width
*/
function InfoBox(opts) {
google.maps.OverlayView.call(this);
this.latlng_ = opts.latlng;
this.map_ = opts.map;
this.offsetVertical_ = -195;
this.offsetHorizontal_ = 0;
this.height_ = 165;
this.width_ = 266;
var me = this;
this.boundsChangedListener_ =
google.maps.event.addListener(this.map_, "bounds_changed", function() {
return me.panMap.apply(me);
});
// Once the properties of this OverlayView are initialized, set its map so
// that we can display it. This will trigger calls to panes_changed and
// draw.
this.setMap(this.map_);
}
/* InfoBox extends GOverlay class from the Google Maps API
*/
InfoBox.prototype = new google.maps.OverlayView();
/* Creates the DIV representing this InfoBox
*/
InfoBox.prototype.remove = function() {
if (this.div_) {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
}
};
/* Redraw the Bar based on the current projection and zoom level
*/
InfoBox.prototype.draw = function() {
// Creates the element if it doesn't exist already.
this.createElement();
if (!this.div_) return;
// Calculate the DIV coordinates of two opposite corners of our bounds to
// get the size and position of our Bar
var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
if (!pixPosition) return;
// Now position our DIV based on the DIV coordinates of our bounds
this.div_.style.width = "389px";
this.div_.style.left = (pixPosition.x + this.offsetHorizontal_) + "px";
this.div_.style.height = "135px";
this.div_.style.top = (pixPosition.y + this.offsetVertical_) + "px";
this.div_.style.display = 'block';
};
/* Creates the DIV representing this InfoBox in the floatPane. If the panes
* object, retrieved by calling getPanes, is null, remove the element from the
* DOM. If the div exists, but its parent is not the floatPane, move the div
* to the new pane.
* Called from within draw. Alternatively, this can be called specifically on
* a panes_changed event.
*/
InfoBox.prototype.createElement = function() {
var panes = this.getPanes();
var div = this.div_;
if (!div) {
// This does not handle changing panes. You can set the map to be null and
// then reset the map to move the div.
div = this.div_ = document.createElement("div");
div.style.border = "1px solid #CCC";
div.style.position = "absolute";
div.style.background = "url('img/proj_box.png')"; //389 × 135
div.style.width = "389px";
div.style.height = "135px";
var contentDiv = document.createElement("div");
contentDiv.style.padding = "30px"
contentDiv.innerHTML = "<b>Hello World!</b>";
var topDiv = document.createElement("div");
topDiv.style.textAlign = "right";
var closeImg = document.createElement("img");
closeImg.style.width = "32px";
closeImg.style.height = "32px";
closeImg.style.cursor = "pointer";
closeImg.src = "http://gmaps-samples.googlecode.com/svn/trunk/images/closebigger.gif";
topDiv.appendChild(closeImg);
function removeInfoBox(ib) {
return function() {
ib.setMap(null);
};
}
google.maps.event.addDomListener(closeImg, 'click', removeInfoBox(this));
div.appendChild(topDiv);
div.appendChild(contentDiv);
div.style.display = 'none';
panes.floatPane.appendChild(div);
this.panMap();
} else if (div.parentNode != panes.floatPane) {
// The panes have changed. Move the div.
div.parentNode.removeChild(div);
panes.floatPane.appendChild(div);
} else {
// The panes have not changed, so no need to create or move the div.
}
}
/* Pan the map to fit the InfoBox.
*/
InfoBox.prototype.panMap = function() {
// if we go beyond map, pan map
var map = this.map_;
var bounds = map.getBounds();
if (!bounds) return;
// The position of the infowindow
var position = this.latlng_;
// The dimension of the infowindow
var iwWidth = this.width_;
var iwHeight = this.height_;
// The offset position of the infowindow
var iwOffsetX = this.offsetHorizontal_;
var iwOffsetY = this.offsetVertical_;
// Padding on the infowindow
var padX = 40;
var padY = 40;
// The degrees per pixel
var mapDiv = map.getDiv();
var mapWidth = mapDiv.offsetWidth;
var mapHeight = mapDiv.offsetHeight;
var boundsSpan = bounds.toSpan();
var longSpan = boundsSpan.lng();
var latSpan = boundsSpan.lat();
var degPixelX = longSpan / mapWidth;
var degPixelY = latSpan / mapHeight;
// The bounds of the map
var mapWestLng = bounds.getSouthWest().lng();
var mapEastLng = bounds.getNorthEast().lng();
var mapNorthLat = bounds.getNorthEast().lat();
var mapSouthLat = bounds.getSouthWest().lat();
// Remove the listener after panning is complete.
google.maps.event.removeListener(this.boundsChangedListener_);
this.boundsChangedListener_ = null;
};
function initialize() {
var myOptions = {
zoom: 11,
//scrollwheel: false,
//navigationControl: false,
//mapTypeControl: false,
//scaleControl: false,
//draggable: false,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
// Try W3C Geolocation (Preferred)
if(navigator.geolocation) {
browserSupportFlag = true;
navigator.geolocation.getCurrentPosition(function(position) {
initialLocation = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
map.setCenter(initialLocation);
}
, function() {
handleNoGeolocation(browserSupportFlag);
});
// Try Google Gears Geolocation
//AJOUT MARKERS
// Create a base icon for all of our markers that specifies the
var myLatlng = new google.maps.LatLng(48,2);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title:"Hello World!"
});
google.maps.event.addListener(marker, "click", function(e) {
var infoBox = new InfoBox({latlng: marker.getPosition(), map: map});
});
google.maps.event.trigger(marker, "click");
var myLatlng2 = new google.maps.LatLng(48.8,2);
var marker2 = new google.maps.Marker({
position: myLatlng2,
map: map,
title:"Hello World!"
});
google.maps.event.addListener(marker2, "click", function(e) {
var infoBox2 = new InfoBox({latlng: marker2.getPosition(), map: map});
});
google.maps.event.trigger(marker2, "click");
}
}
</script>
Remove these lines from your initialize function:
google.maps.event.trigger(marker, "click");
google.maps.event.trigger(marker2, "click");
I'm trying to create an HTML5 canvas as an OverlayView the size of a map, position it to top:0; left:0;, draw some stuff on it, and add it to the map. Whenever the map zooms or pans I want to remove the old canvas from the map and create a new canvas draw on it position it to 0,0 and add it to the map. However the map never reposition to top:0; left:0. Can someone help?
function CustomLayer(map){
this.latlngs = new Array();
this.map_ = map;
this.addMarker = function(position){
this.latlngs.push(position);
}
this.drawCanvas = function(){
this.setMap(this.map_);
//google.maps.event.addListener(this.map_, 'bounds_changed',this.reDraw());
}
}
function defineOverlay() {
CustomLayer.prototype = new google.maps.OverlayView();
CustomLayer.prototype.onAdd = function() {
console.log("onAdd()");
if(this.canvas){
var panes = this.getPanes();
panes.overlayLayer.appendChild(this.canvas);
}
}
CustomLayer.prototype.remove = function() {
console.log("onRemove()");
if(this.canvas)
this.canvas.parentNode.removeChild(this.canvas);
}
CustomLayer.prototype.draw = function() {
console.log("draw()");
this.remove();
this.canvas = document.createElement("canvas");
this.canvas.setAttribute('width', '800px');
this.canvas.setAttribute('height', '480px');
this.canvas.setAttribute('top', '30px');
this.canvas.setAttribute('left', '30px');
this.canvas.setAttribute('position', 'absolute');
this.canvas.setAttribute('border', '1px solid red');
this.canvas.style.border = '1px solid red';
//using this way for some reason scale up the images and mess up the positions of the markers
/*this.canvas.style.position = 'absolute';
this.canvas.style.top = '0px';
this.canvas.style.left = '0px';
this.canvas.style.width = '800px';
this.canvas.style.height = '480px';
this.canvas.style.border = '1px solid red';*/
//get the projection from this overlay
overlayProjection = this.getProjection();
//var mapproj = this.map_.getProjection();
if(this.canvas.getContext) {
var context = this.canvas.getContext('2d');
context.clearRect(0,0,800,480);
for(i=0; i<this.latlngs.length; i++){
p = overlayProjection.fromLatLngToDivPixel(this.latlngs[i]);
//p = mapproj.fromLatLngToPoint(this.latlngs[i]);
img = new Image();
img.src = "standardtick.png";
console.log(Math.floor(p.x)+","+Math.floor(p.y));
context.drawImage(img,p.x,p.y);
}
}
this.onAdd();
console.log("canvas width:"+this.canvas.width+" canvas height: "+this.canvas.height);
console.log("canvas top:"+this.canvas.getAttribute("top")+" left: "+this.canvas.getAttribute("left"));
}
}
In this example - I think it is important to draw attention to the difference between projection.fromLatLngToDivPixel and projection.fromLatLngToContainerPixel. In this context, DivPixel is used to keep the position of the canvas centered over the map view - while ContainerPixel is used to find the positions of the shapes you are drawing to the canvas.
What follows is a complete working example I worked out while playing around with this problem myself.
Required CSS Properties for the Overlay:
.GMAPS_OVERLAY
{
border-width: 0px;
border: none;
position:absolute;
padding:0px 0px 0px 0px;
margin:0px 0px 0px 0px;
}
Initialize the Map and Create a Test based on Google Markers
var mapsize = { width: 500, height: 500 };
var mapElement = document.getElementById("MAP");
mapElement.style.height = mapsize.width + "px";
mapElement.style.width = mapsize.width + "px";
var map = new google.maps.Map(document.getElementById("MAP"), {
mapTypeId: google.maps.MapTypeId.TERRAIN,
center: new google.maps.LatLng(0, 0),
zoom: 2
});
// Render G-Markers to Test Proper Canvas-Grid Alignment
for (var lng = -180; lng < 180; lng += 10)
{
var marker = new google.maps.Marker({
position: new google.maps.LatLng(0, lng),
map: map
});
}
Define the Custom Overlay
var CanvasOverlay = function(map) {
this.canvas = document.createElement("CANVAS");
this.canvas.className = "GMAPS_OVERLAY";
this.canvas.height = mapsize.height;
this.canvas.width = mapsize.width;
this.ctx = null;
this.map = map;
this.setMap(map);
};
CanvasOverlay.prototype = new google.maps.OverlayView();
CanvasOverlay.prototype.onAdd = function() {
this.getPanes().overlayLayer.appendChild(this.canvas);
this.ctx = this.canvas.getContext("2d");
this.draw();
};
CanvasOverlay.prototype.drawLine = function(p1, p2) {
this.ctx.beginPath();
this.ctx.moveTo( p1.x, p1.y );
this.ctx.lineTo( p2.x, p2.y );
this.ctx.closePath();
this.ctx.stroke();
};
CanvasOverlay.prototype.draw = function() {
var projection = this.getProjection();
// Shift the Canvas
var centerPoint = projection.fromLatLngToDivPixel(this.map.getCenter());
this.canvas.style.left = (centerPoint.x - mapsize.width / 2) + "px";
this.canvas.style.top = (centerPoint.y - mapsize.height / 2) + "px";
// Clear the Canvas
this.ctx.clearRect(0, 0, mapsize.width, mapsize.height);
// Draw Grid with Canvas
this.ctx.strokeStyle = "#000000";
for (var lng = -180; lng < 180; lng += 10)
{
this.drawLine(
projection.fromLatLngToContainerPixel(new google.maps.LatLng(-90, lng)),
projection.fromLatLngToContainerPixel(new google.maps.LatLng( 90, lng))
);
}
};
Initializing the Canvas
I find that I like to add an additional call to draw on the "dragend" event - but test it out to see what you think on your needs.
var customMapCanvas = new CanvasOverlay(map);
google.maps.event.addListener(map, "drawend", function() {
customMapCanvas.draw();
};
In cases where Canvas Drawing is Slowing Down Map
On the applications I work with, I find that the Map Framework calls the 'draw' method far too often on canvas's which are drawing something that takes a second or so to complete. In this case I define the 'draw' prototype function to be simply an empty function while naming my real draw function as 'canvasDraw' - then add event listeners for "zoomend" and "dragend". What you get here is a canvas that updates only after a user changes the zoom level or at the end of a map drag action.
CanvasOverlay.prototype.draw = function() { };
...
google.maps.event.addListener(map, "dragend", function() {
customMapCanvas.canvasDraw();
});
google.maps.event.addListener(map, "zoom_changed", function() {
customMapCanvas.canvasDraw();
});
Live Demo: Complete Example - All Inline Source
Once your map moves, the drawing context needs to know it has moved.
CustomOverlayView.prototype.alignDrawingPane = function(force) {
window.mapProjection = this.getProjection();
var center = window.mapProjection.fromLatLngToDivPixel(map.getCenter());
//My drawing container is dragged along with the map when panning
//this.drawPane refers to any node in MapPanes retrieved via this.getPanes()
this.drawPane.css({left:center.x - (mapWidth/2), top:center.y-(mapHeight/2)});
};
Call this in your draw() method. Make sure your draw gets called when you're done dragging:
google.maps.event.addListener(map, 'dragend', function() {
myCustomOverlay.draw();
});