I have a phonejs project, created for web, using html and js. I need to have a page containing a project construction plan/highrsie building plan image. There are some numbers of lots in that image, lot 1-20 for example, that will having status AVAILABLE, SOLD, BOOKED etc. I want to make the user can tag in the image the status for the corresponding lot, maybe differentiate by colour, for example RED=SOLD, GREEN=AVAILABLE, etc, and the status can be save into database. Could anyone suggest me on what is the best way/method for accomplishing this? Thanks a lot in advance.
I have already tried by using canvas. The following is my code.
HTML
<div data-options="dxView : { name: 'status_tagging', title: 'status_tagging' } " >
<div data-options="dxContent : { targetPlaceholder: 'content' } " >
<h4>Drag the status to the corresponding lot.</h4>
<img id="available" width=32 height=32 src="images/available.png">
<img id="booked" width=32 height=32 src="images/booked.png">
<img id="hold" width=32 height=32 src="images/hold.png">
<img id="reserved" width=32 height=32 src="images/reserved.png">
<img id="sold" width=32 height=32 src="images/sold.png">
<img id="siteplan" src="images/siteplan.jpg">
<br>
<canvas id="myCanvas" width=300 height=300 style="border:1px solid #d3d3d3;"></canvas>
</div>
JavaScript
KioskAdminV2.status_tagging = function (params) {
var id = params.id;
var tb_prop_siteplan = new KioskAdminV2.tb_prop_siteplanViewModel();
var canvas=document.getElementById("myCanvas");
var ctx=canvas.getContext("2d");
var $canvas=$("#myCanvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var img=document.getElementById("siteplan");
ctx.drawImage(img,10,10);
var image1=new Image();
image1.src = "images/available.png";
var image2=new Image();
image2.src = "images/booked.png";
var $available=$("#available");
var $booked=$("#booked");
var $canvas=$("#myCanvas");
$available.draggable({
helper:'clone'
});
$booked.draggable({
helper:'clone'
});
// set the data payload
$available.data("image",image1); // key-value pair
$booked.data("image",image2);
$canvas.droppable({
drop:dragDrop
});
function dragDrop(e,ui){
var element=ui.draggable;
var data=element.data("url");
var x=parseInt(ui.offset.left-offsetX);
var y=parseInt(ui.offset.top-offsetY);
ctx.drawImage(element.data("image"),x-1,y);
}
return {
id:id,
tb_prop_siteplan: tb_prop_siteplan,
canvas:canvas,
ctx:ctx,
$canvas:$canvas,
canvasOffset:canvasOffset,
offsetX:offsetX,
offsetY:offsetY,
img:img,
image1:image1,
image2:image2,
$available:$available,
$booked: $booked,
dragDrop: dragDrop
};
};
But i got error "cannot read property of 'getContext' of null". Can anyone tell me why is this?
You could do your project in Canvas or SVG, but...
Since your building plan is fixed in shape, you don't need them to do your project.
Just use html+css -- simpler to learn + more html+css tutorials online.
Cut your building plan into lots and make an image of each lot.
Make both a green and red shaded version of each lot.
Listen for mouseclick events and determine which lot the use clicked in.
Toggle the image for that lot from red-to-yellow-to-green representing sold-booked-available.
Related
I'm new to js and html5 so here's what I'm doing : I'm working on a game that helps in teaching illustrator shortcuts, the firts level consist of 2 canvas one with an already existing image and the other blank and ready for user to draw on, on ctrl + s press(sure I disabled it's default action using jquery) I want to compare the content of those 2 canvas elements. I've found Image similarity api from deepai.org very useful and accurate, but it only accepts url or input="file" content, so I'm trying to find a way to upload (maybe) the drawn canvas as an image to a server and get the url like this : https://server.com/myaccount/images/img1.png and since i only upload one image I can pass that static url to the api in addition to the original image which will also have a static url so hopefully it compares.
I made a solution that works without a server. But I couldn't make it work in an online code repo like jsfiddle. So I put it on my own server for you to check. http://paulyro.com/paul/deepai/
For convenience I put everything in one file. Of course it would make sense to save the JS in a separate file. But I let that up to you.
For explanation: the red square in a black frame is the canvas. I generate two images and add them to the page. Then I send those images to the deepAI server when you press the button. You will only need one generated img, but for testing purpose I made 2.
Let me know if this is what you were looking for. Of course I expect you to adapt this solution to your exact needs ;)
This is the code:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>DeepAiDemo</title>
<script src="https://cdnjs.deepai.org/deepai.min.js"></script>
<style rel="stylesheet">
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="canvas1" width="200" height="200"></canvas>
<button name="button" onClick="load()">Press me</button>
<div style="position:absolute;left:400px; top:30px; height: 354px;" id="messages">Result will get here</div>
<script type="text/javascript">
(async function() {
var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
// create green canvas and make it an image
ctx.fillStyle = "green";
ctx.fillRect(75, 75, 50, 50);
var img = new Image();
img.src = can.toDataURL();
document.body.appendChild(img);
// create red canvas and make it an image
ctx.fillStyle = "red";
ctx.fillRect(75, 75, 50, 50);
var img2 = new Image();
img2.src = can.toDataURL();
document.body.appendChild(img2);
})()
const load = async () => {
document.getElementById('messages').innerHTML = "Waitng for response...";
deepai.setApiKey('xxxxxxxxxxxxxx');
var images = document.getElementsByTagName('img');
console.log("amount images: "+images.length);
console.log(images[0]);
console.log(images[1]);
var resp = await deepai.callStandardApi("image-similarity", {
image1: images[0],
image2: images[1],
});
console.log("response: ");
console.log(resp);
document.getElementById('messages').innerHTML = "Distance: " + resp.output.distance; //resp.output.distance contains the number from the server.
};
</script>
</body>
</html>
Cheers,
Paul
I have used chart.js to generate a report page that has multiple charts. I need to export this report to PDF. There are many solutions available via search, but I cannot find one which has multiple canvas elements.
The only available solution seems to be to loop through all the images, and recreate the report using the images, and then download that as a pdf.
Is there any simpler/more efficient way to accomplish this?
<body>
<h1> Chart 1 </h1>
<div style="width:800px; height:400px;">
<canvas id="chart_1" width="50" height="50"></canvas>
</div>
<h1> Chart 2 </h1>
<div style="width:800px; height:400px;">
<canvas id="chart_2" width="50" height="50"></canvas>
</div>
<h1> Chart 3 </h1>
<div style="width:800px; height:400px;">
<canvas id="chart_3" width="50" height="50"></canvas>
</div>
</body>
Honestly, it seems like the easiest approach would be to just provide a "download to PDF" link that pops up the browser's print page and instruct to user to select "print as pdf".
If that approach doesn't work for you (or your users), then here is a rough way to do it.
Basically, we create a new canvas element that is the size of your report page and incrementally paint the pixels from your existing chart.js canvas charts into the new canvas. Once that is done, then you can use jsPDF to add the new canvas to a pdf document as an image and download the file.
Here is an example implementation that does just that.
$('#downloadPdf').click(function(event) {
// get size of report page
var reportPageHeight = $('#reportPage').innerHeight();
var reportPageWidth = $('#reportPage').innerWidth();
// create a new canvas object that we will populate with all other canvas objects
var pdfCanvas = $('<canvas />').attr({
id: "canvaspdf",
width: reportPageWidth,
height: reportPageHeight
});
// keep track canvas position
var pdfctx = $(pdfCanvas)[0].getContext('2d');
var pdfctxX = 0;
var pdfctxY = 0;
var buffer = 100;
// for each chart.js chart
$("canvas").each(function(index) {
// get the chart height/width
var canvasHeight = $(this).innerHeight();
var canvasWidth = $(this).innerWidth();
// draw the chart into the new canvas
pdfctx.drawImage($(this)[0], pdfctxX, pdfctxY, canvasWidth, canvasHeight);
pdfctxX += canvasWidth + buffer;
// our report page is in a grid pattern so replicate that in the new canvas
if (index % 2 === 1) {
pdfctxX = 0;
pdfctxY += canvasHeight + buffer;
}
});
// create new pdf and add our new canvas as an image
var pdf = new jsPDF('l', 'pt', [reportPageWidth, reportPageHeight]);
pdf.addImage($(pdfCanvas)[0], 'PNG', 0, 0);
// download the pdf
pdf.save('filename.pdf');
});
You can see it in action at this codepen.
Now let's talk about some gotchas with this approach. First, you have to control the position of each chart.js canvas in the new canvas object. The only way to do that is to have an understanding of how your report page is structured and implement that same structure. In my example, my charts are in a 2x2 grid and the logic handles this accordingly. If you had a 3x2 grid or something different then you would have to change the positioning logic.
Lastly, the final pdf output file dimensions are much larger than the original chart page (from the web). I think the reason is because my chart "container" div stretches across the full page. Therefore, you probably want to use a different approach for setting the size of your new canvas.
So long story short, the above example is meant to demonstrate an approach and not be your final solution.
Good luck!
I have a working solution in vanilla javascript(although I used ts typing) and using the lib jsPdf, where you need a plot per pdf page:
let index = 1;
// create new pdf object
// if don't choose compress as true you will end up with a large pdf file
let pdf = new jsPDF({
orientation: 'landscape',
unit: 'px',
format: 'a4',
compress: true,
})
// search for the html element(s) you need
const canvas = document.querySelectorAll("canvas");
// here my size are in pixels since I configured that in the obj instance
let pageWidth = 400;
let pageHeight = 400;
let index = 1;
// traverse the array of canvas
canvas.forEach( (canva:HTMLCanvasElement) => {
// I added some options among others I added the type of the compression
// method: FAST
pdf.addImage(canva, 'PNG', 10, 10, pageWidth, pageHeight, `img${index}`, "FAST");
// so as to not end up with an extra pdf page at the end of the iteration
if (index < canvas.length) {
pdf.addPage();
}
index++;
});
// download the pdf
pdf.save('Reporte.pdf');
I have created a HTML based webpage consisting of a form, some texts and a canvas. I am trying to print this page that includes the canvas on a piece of paper. But the problem is - the canvas can't be printed. I also used toDataURL() method to convert the canvas to an image before printing, but it still didn't work. Could anyone give me some clues?
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillRect(0, 0, 150, 100);
var img = c.toDataURL("image/png");
document.write('<img src="'+img+'"/>');
function printData(){
var divToPrint=document.getElementById("printTable");
newWin= window.open("");
newWin.document.write(divToPrint.outerHTML);
newWin.print();
newWin.close();
}
$('#printButton').on('click',function(){
printData();
});
<canvas id="myCanvas"></canvas>
<table id="printTable">
<button type="button" id="printButton" class="btn btn-info"> Print </i></button>
<tr><td>Data1 : </td><td >HTML</td></tr>
<tr><td>Data2 : </td><td >CSS</td></tr>
<tr><td>Image : </td><td >Wanna print the image here.</td></tr>
what you could do is try some of the other good answered solutions on other asked pages which is quite similar to what you are trying to archieve.
Try checking here:
Capture HTML Canvas as gif/jpg/png/pdf?
I have a rather complex imagemap with several mapped areas.
Most of the mapped areas are just mapped for mouseovers and links. But some arease have a JS onClick() which results in an imageflip. The new, flipped image is basically the old image, with a few "new things" on it.
Two things need to happen which I cannot figure out:
The new image needs to stay there. What is happening no is that as soon as I move the mouse out of the mapped area, it flipps back to the old image.
I need the imagemap (of the "old" image) to work on the new image, which appears on the flip.
JAVASCRIPT
//PRELOAD IMAGES FOR CLICK AND MOUSEOVER
cuentaBoca = new Image(655, 338)
cuentaBoca.src = "imagenes_png/pag2/cuentame_bocadilla.png";
cuenta = new Image(655, 338)
cuenta.src = "imagenes_png/pag2/cuentame_h.png";
//JS FUNCTION FOR CLICK
function bocadillaC() {
document.getElementById('garfio').src = cuentaBoca.src;
}
//JS FUNCTION FOR MOUSEOVER
function cuentaH() {
document.getElementById('garfio').src = cuenta.src;
return true;
}
HTML
<!-- INSERT THE PICTURE -->
<img name="garfio" id="garfio" src="imagenes_png/pag2/base.png" width="655" height="338" border="0" usemap="#m_garfio" alt="" />
<!-- CREATE THE MAP -->
<map name="m_garfio" id="m_garfio">
<area shape="poly" id="bocadilla" coords="7,205,12,197,20,191,24,189,34,185,45,182,58,180,74,180,86,180,94,181,103,182,112,185,114,186,130,178,135,177,137,179,134,184,130,192,135,195,138,199,142,204,143,209,138,218,125,227,113,231,100,235,86,236,70,236,53,235,41,233,34,231,23,226,15,221,11,217,8,212,7,205"
onMouseOver="cuentaH()" onClick="bocadillaC(); return false" alt="" />
</map>
</div>
Here a Fiddel http://jsfiddle.net/emedrs9n/
Clicking on the "Cuentame" (balloon) has the onClick() effect
Try to redefine the original function on click. Example
function bocadillaC() {
cuentaH = original = bocadillaC;
// redefine other functions
leftH = function() {
document.getElementById('garfio').src = left_with_yellow_cloud.src;
};
rightH = function() {
document.getElementById('garfio').src = right_with_yellow_cloud.src;
};
cuentaH = function() {
document.getElementById('garfio').src = cuenta_with_yellow_cloud.src;
};
// ...
document.getElementById('garfio').src = cuentaBoca.src;
}
And you need to redefine other functions with images. But, for example, for this state there is no a similar image with yellow cloud.
But in fact you need to use power of HTML/CSS, don't draw image on each case and do it simpler without image map.
This does what you seem to ask. Two images are displayed. When I roll the mouse over the upper image, the lower image changes and does not change back. The images vane2.jpg and vane2.png are mirror images.
<html>
<head>
<script type="text/javascript">
function setimage () {
document.getElementById('hisArea').src = "vane2.png";
}
</script>
</head>
<body>
<img id="myArea" onMouseOver="setimage();" width="176" height="176" src="vane1.jpg">
<BR>
<img id="hisArea" width="176" height="176" src="vane2.jpg">
</body>
</html>
I create a test code below and you can manipulate it on Jsfiddle:
http://jsfiddle.net/Stallman41/57hvX/31/
HTML:
<canvas id="test_canvas" style="background-color : #FFFF00" ; width="500px"
; height="340px"></canvas>
<br>
<button id="test_put_btn">Put an image</button>
<br>
<button id="save_dataURL">Save to dataURL</button>
<br>
<button id="draw_back">Final step: draw 3 images back.</button>
<br>
<img id="first_img"; width="100px" ; height="100px" ;></img>
<img id="second_img"; width="100px" ; height="100px" ></img>
<img id="third_img"; width="100px" ; height="100px" ;></img>
Javascript:
var drawing_plate;
var context;
var dataURL_arr = new Array();
$(document).ready(function () {
drawing_plate = document.getElementById("test_canvas");
context = drawing_plate.getContext('2d');
$("#test_canvas").bind("mousedown", Touch_Start);
$("#test_canvas").bind("mousemove", Touch_Move);
$("#test_canvas").bind("mouseup", Touch_End);
}); //document ready.
function Touch_Start(event) {
event.preventDefault();
touch = event;
touch_x = touch.pageX;
touch_y = touch.pageY;
line_start_x = touch.pageX - 0;
line_start_y = touch.pageY - 0;
context.beginPath();
context.moveTo(line_start_x, line_start_y);
}
function Touch_Move(event) {
event.preventDefault();
touch = event; //mouse
line_end_x = touch.pageX - 0;
line_end_y = touch.pageY - 0;
context.lineTo(line_end_x, line_end_y);
context.stroke();
}
$("#test_put_btn").click(function () {
var test_img = new Image();
test_img.src = "http://careerscdn.sstatic.net/careers/gethired/img/careers2- ad-header-so-crop.png";
context.drawImage(test_img, 0, 0);
});
$("#save_dataURL").click(function () {
dataURL_arr.push(drawing_plate.toDataURL("image/png"));
});
$("#draw_back").click(function () {
var f_image= $("#first_img")[0];
var s_image= $("#second_img")[0];
var t_image= $("#third_img")[0];
f_image.onload= function()
{
f_image.src= dataURL_arr[0];
}
f_image.src= dataURL_arr[0];
s_image.onload= function()
{
s_image.src= dataURL_arr[0];
}
s_image.src= dataURL_arr[0];
t_image.onload= function()
{
t_image.src= dataURL_arr[0];
}
t_image.src= dataURL_arr[0];
});
I develop a drawing plate on Android system, saving the drawings to a dataURL string. They can draw something on the canvas and put images on the canvas. And I need to let the users see their drawings on small icons.
I use canvas.toDataURL("image/png") to save the base64 string. And I choose <img> as the small icon container. However, what I got is only the drawings can be shown on the icon, and usually, when I write img.src= canvas.toDataURL("image/png"); the image shows nothing!
I investigate the issue for long time.
1. I think the problem might be the dataURL string is too long?
2. The support of the OS: Android?
The code in Jsfiddle here shows a similar procedure on my Android PhoneGap development.
First , you just draw something on the canvas, and press Press an image, and then Save to dataURL. But you should do the process three times. In this condition, the string array contains the base64 string generated by the drawings and the image.
In the final, you press Final step: draw 3 images back., nothing will be shown on the image icon.
In conclusion:
In my experience, as I write img.src= canvas.toDataURL("image/png"); (no matter the img is an dom element or var img = new Image();). It can't always work: sometimes it works... but sometimes not...(I work on Android 4.0.1, phonegap 1.7.0)
Second, especially if I store lots of base64 strings to an array, assigning them to lots of image DOM element, it definitely fails.
Third, if the user only draw something on the canvas, it can always work.( Except the example code in the Jsfiddle, but it works on my Android system...)
But if he draw an image context.drawImage(~) the image wouldn't show the pic.
Too much confusions...
I need to let the user can view their drawings in small icon, any alternative?
Some References:
1
2
3
I just stumbled across this question.
Click Put an image, then click Save to dataURL, then check your JavaScript console for something like:
SecurityError: DOM Exception 18
It's a browser security feature. Because you've inserted an image from a different domain, it counts as a cross-origin request.
If you eliminate the security error, you can export the canvas to a data URL.
Another thing in your code.
The image you try to draw onto the canvas into your test_put_btn onclick event handler, your image will never show up (or it will sometimes work accidentally) because you don't wait for your image to be loaded to draw it onto the canvas.
You have to handle the "onload" event of your image and draw it into the handler to permit the drawing of your image.
Before your test_img.src statement, you have to put :
test_img.onload = function()
{
context.drawImage(test_img, 0, 0);
};
Plus, the image you try to access is not accessible --> For me it does not work