I am exporting a diagram made using Jointjs library to pdf using jspdf and canvas:
Below is my javascript code::
var svg = document.querySelector('svg');
var serializer = new XMLSerializer();
var svgString = serializer.serializeToString(svg);
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.fillStyle = '#FFFF';
canvg(canvas, svgString);
var imgData = canvas.toDataURL('image/png');
// Generate PDF
doc.setFontSize(10);
doc.text(35, 25, "Google Cloud Craft");
doc.addImage(imgData, 'PNG', 10, 50);
doc.save('test.pdf');
the result i get after downloading and on canvas is:
What i want is those black arrow marks should not come as they are shown on mouseover events, it should be like below image for reference:
please let me know how can i achieve this.
Let me try to answer.
Add the below code to hide the mouse-over elements before serialising it
$(".marker-arrowhead").css("display", "none");
$(".tool-remove").css("display", "none");
$(".tool-options").css("display", "none");
$(".marker-vertices").css("display", "none");
Hope this helps you.
I found a solution sharing, so that if anyone faces this issue can get help.
this is the solution, who are familiar with jointjs will understand it.
link.attr({
'.marker-arrowheads': {
fill: 'none'
},
'.connection-wrap': {
fill: 'none'
},
'.marker-vertices': {
fill: 'none'
},
'.link-tools': {
fill: 'none'
}
});
Here my proposition :)
const classes = ['.marker-vertices', '.link-tools'];
const svg = this.paper.svg.cloneNode(true);
// remove tools
classes.forEach(c => {
const elements = svg.querySelectorAll(c);
elements.forEach(el => { el.style.display = 'none'; });
});
Related
EDIT: My codesandbox is working, but it's not perfect. In my actual project I've better utilized ts and am just making an if check for the charttype so the font doesn't paste on all the charts you have.
I still need to work on making the fontsize responsive and prettier, but I will try and update the codesandbox as much as I can!
If anyone would like to add to it please do! Also, post your link in the comments so anyone else having these issues can see them too!
I am attempting to make a doughnut chart that looks like this:
I've been trying to figure out how to get the code in this example using VueChartJS (VueChart3 is a TS safe rewrite of VueChartJS and works the same, just in composition API), but cannot figure out how to get the plugins to work properly.
vue-chartjs - Doughnut chart with text in the middle
Working Example from post
The example in the post above uses a textCenter() function and constantly access the context ctx variable. The first error I get however reads Property 'pluginService' does not exist on type 'typeof Chart' and also a Cannot read properties of undefined (reading 'register'). I think this has to do with the way VueChart3 and it's Chart.register(...registerables) line.
I've commented out all of the code that breaks the chart currently while I try and fix this issue.
I am really stumped on where to go with this now and could really use a bit guidance.
Cheers!
CodeSandbox Link
Chart2.vue
<template>
<div style="display: flex; justify-content: center; margin: 5rem">
<DoughnutChart :options="options" v-bind="doughnutChartProps" />
</div>
</template>
<script lang='ts'>
import { computed, ref, onMounted } from "vue";
import { DoughnutChart, useDoughnutChart } from "vue-chart-3";
import { Chart, ChartData, ChartOptions, registerables } from "chart.js";
Chart.register(...registerables, plugin);
var plugin = function (chart) {
var width = chart.chart.width;
var height = chart.chart.height;
var ctx = chart.chart.ctx;
ctx.restore();
var fontSize = (height / 114).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";
var text = 800;
var textX = Math.round((width - ctx.measureText(text).width) / 2);
var textY = height / 2;
ctx.fillText(text, textX, textY);
ctx.save();
};
export default {
name: "Home",
components: { DoughnutChart },
setup(props) {
const isResponsive = ref(true);
const getData = computed<ChartData<"doughnut">>(() => ({
labels: ["Success"],
datasets: [
{
data: [10, 90],
backgroundColor: ["#56cd92", "#f0f7ff"],
},
],
}));
onMounted(() => {
addPlugin({
id: "my-plugin",
beforeDraw: plugin,
});
// renderChart(chartdata, options);
// textCenter(1000);
});
const options = computed<ChartOptions<"doughnut">>(() => ({
plugins: {
legend: {
position: "bottom",
},
},
}));
const { doughnutChartProps } = useDoughnutChart({
options,
chartData: getData,
});
return {
isResponsive,
getData,
options,
doughnutChartProps,
};
},
};
</script>
This is because pluginService is V2 syntax, to register plugins globally in V3 you can do it the same way you did with the registerables like so:
Chart.register(plugin)
You can even do it in the same register call like so:
Chart.register(...registerables, plugin)
Edit:
Plugins also have to be objects so chart.js knows which hook to use as you did in the mounted so your plugin variable has to look like this (still V2 syntax, you will need to change this yourself) to work:
var plugin = {
id: 'idOfPlugin',
beforeDraw: function (chart) {
var width = chart.chart.width;
var height = chart.chart.height;
var ctx = chart.chart.ctx;
ctx.restore();
var fontSize = (height / 114).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";
var text = 800;
var textX = Math.round((width - ctx.measureText(text).width) / 2);
var textY = height / 2;
ctx.fillText(text, textX, textY);
ctx.save();
};
}
I'm trying to adjust the transparency of a PNG that I am overlaying on ArcGIS/ESRI API for Javascript.
I have tried to set an opacity option in the var but, am not having much luck.
map.on("load", function() {
// create and add the layer
var mil = new esri.layers.MapImageLayer({
});
// create an add the actual image
var mi = new esri.layers.MapImage({
'extent': { 'xmin': -125.0, 'ymin': 22.0, 'xmax': -66.5, 'ymax': 52.0},
'href': 'https://some.website/some.image.PNG',
'opacity': 0.75
});
What am I doing wrong?
I added opacity: 0.6 to
map.on("load", function() {
// create and add the layer
var mil = new esri.layers.MapImageLayer({
'opacity': 0.6,
});
Don't know if the question is well put, but here is my problem: I managed to export my chart to PDF format using jspdf.min.js through this piece of code:
$("#generate").on("click", function (e) {
html2canvas($("#placeholder").get(0), {
onrendered: function (canvas) {
var imgData = canvas.toDataURL('image/png');
console.log('Report Image URL: ' + imgData);
var doc = new jsPDF('portrait');
doc.addImage(imgData, 'PNG', 10, 10, 190, 95);
doc.text("TEST TEXT");//I tried to add a text in PDF file,but didn't work
doc.save('sample-file.pdf');
}
});
});
Is there a way to add a title of my chart in the PDF file?
Try this example. Is a trick which might help you. Don't forget to update your options:
var options = {
canvas: true,
grid: {
margin: {
top:50
},
}
};
I have an embedded Google Map using API V3 but I cannot get it default Zoom to anything other than 1.
My JS in the head is:
var map1;
var src1 = 'https://latitude.google.com/latitude/apps/badge/api?user=8963899225283336226&type=kml';
function initialize1() {
map1 = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 7,
mapTypeId: google.maps.MapTypeId.TERRAIN
});
loadKmlLayer1(src1, map1);
}
google.maps.event.addDomListener(window, 'load', initialize1);
function loadKmlLayer1(src1, map1) {
var kmlLayer1 = new google.maps.KmlLayer(src1, {
suppressInfoWindows: false,
clickable: true,
preserveViewport: false,
map: map1
});
}
The HTML is just the map-canvas div, nothing else. Looking at some of the threads on here it look like its something to do with detecting the viewport and resetting the bounds.
I found a thread that suggested adding something like:
google.maps.event.addListener(kmlLayer1, 'defaultviewport_changed', function() {
var bounds = kmlLayer1.getDefaultViewport();
map.setCenter(bounds.getCenter());
})
but it made no difference. I'm by no means a JS expert and whilst I mostly understand what is going on in most of the code above, I'm not advanced enough to improvise or even understand where it should be placed.
Thanks Molle.
I enhanced to this and it works:
google.maps.event.addListener(kmlLayer, 'status_changed', function () {
console.log('kml loaded:');
google.maps.event.addListenerOnce(map, 'zoom_changed', function () {
console.log('zoom_changed:');
map.setZoom(7);
map.setCenter(new google.maps.LatLng(0, 0));
});
});
The API will set the viewport to contain all KML-features, what will override the zoom-settings.
Reset the zoom once the zoom has changed(as it does when the KML-Layer has been loaded)
google.maps.event.addListenerOnce(map1, 'zoom_changed', function() {
this.setZoom(7);
})
I've been trying to find a way to use the 'Reverse Geocoding' service with the Latitude and Longitude co-ordinates coming from two text boxes on my HTML form, and I must admit I'm not really sure what I need to do.
I have managed to do this with the 'Geocode' service (see code below), but I just wondered whether someone may be able to point me in the right direction of how I could adapt the 'Geocode' javascript I have to the 'Reverse Geocoging' service.
(function Geocode() {
// This is defining the global variables
var map, geocoder, myMarker;
window.onload = function() {
//This is creating the map with the desired options
var myOptions = {
zoom: 5,
center: new google.maps.LatLng(55.378051,-3.435973),
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
position: google.maps.ControlPosition.BOTTOM
},
navigationControl: true,
navigationControlOptions: {
style: google.maps.NavigationControlStyle.ZOOM_PAN,
position: google.maps.ControlPosition.TOP_RIGHT
},
scaleControl: true,
scaleControlOptions: {
position: google.maps.ControlPosition.BOTTOM_LEFT
}
};
map = new google.maps.Map(document.getElementById('map'), myOptions);
// This is making the link with the 'Search For Location' HTML form
var form = document.getElementById('SearchForLocationForm');
// This is catching the forms submit event
form.onsubmit = function() {
// This is getting the Address from the HTML forms 'Address' text box
var address = document.getElementById('GeocodeAddress').value;
// This is making the Geocoder call
getCoordinates(address);
// This is preventing the form from doing a page submit
return false;
}
}
// This creates the function that will return the coordinates for the address
function getCoordinates(address) {
// This checks to see if there is already a geocoded object. If not, it creates one
if(!geocoder) {
geocoder = new google.maps.Geocoder();
}
// This is creating a GeocoderRequest object
var geocoderRequest = {
address: address
}
// This is making the Geocode request
geocoder.geocode(geocoderRequest, function(results, status) {
// This checks to see if the Status is 'OK 'before proceeding
if (status == google.maps.GeocoderStatus.OK) {
// This centres the map on the returned location
map.setCenter(results[0].geometry.location);
// This creates a new marker and adds it to the map
var myMarker = new google.maps.Marker({
map: map,
zoom: 12,
position: results[0].geometry.location,
draggable:true
});
//This fills out the 'Latitude' and 'Longitude' text boxes on the HTML form
document.getElementById('Latitude').value= results[0].geometry.location.lat();
document.getElementById('Longitude').value= results[0].geometry.location.lng();
//This allows the marker to be draggable and tells the 'Latitude' and 'Longitude' text boxes on the HTML form to update with the new co-ordinates as the marker is dragged
google.maps.event.addListener(
myMarker,
'dragend',
function() {
document.getElementById('Latitude').value = myMarker.position.lat();
document.getElementById('Longitude').value = myMarker.position.lng();
var point = myMarker.getPosition();
map.panTo(point);
}
);
}
}
)
}
})();
UPDATE
Firstly, many thanks for the code you kindly posted and the suggestion to go and have a look at the Google documentation.
From what you suggested, and from what I took from the additional documentation I came up with the following. However, when I click my submit button nothing happens, almost as if there is no command attached to it. I don't receive any error messages and I've checked to make sure that I've linked the code to the correct fieldnames and all seems ok. I just wondered whether it would be at all possible if you, or indeed anyone else, could take a look at it please to tell me where I've gone wrong.
Many thanks and kind regards
(function ReverseGeocode() {
var form, geocoderRequest, latlng, myMarker, point;
window.onload = function() {
//This is creating the map with the desired options
var myOptions = {
zoom: 5,
center: new google.maps.LatLng(55.378051,-3.435973),
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
position: google.maps.ControlPosition.BOTTOM
},
navigationControl: true,
navigationControlOptions: {
style: google.maps.NavigationControlStyle.ZOOM_PAN,
position: google.maps.ControlPosition.TOP_RIGHT
},
scaleControl: true,
scaleControlOptions: {
position: google.maps.ControlPosition.BOTTOM_LEFT
}
};
map = new google.maps.Map(document.getElementById('map'), myOptions);
var latlng = new google.maps.LatLng('Latitude', 'Longitude');
// This is making the Geocode request
geocoder.geocode({'LatLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
map.setZoom(11);
var myMarker = new google.maps.Marker({
position: results[0].geometry.location,
map: map
});
//This fills out the 'Address' text boxe on the HTML form
document.getElementById('Address').value= results[0].geometry.location.latlng();
var point = myMarker.getPosition();
map.panTo(point);
}
}
}
)}})
Once you have the latitude and longitude from your form, you do something like this (using your above code as a starting point, for the sake of clarity):
var latlng = new google.maps.LatLng(latitudeFromForm,longitudeFromForm);
// This is creating a GeocoderRequest object
var geocoderRequest = {
'latlng':latlng
}
// This is making the Geocode request
geocoder.geocode(geocoderRequest, function(results, status) {
// This checks to see if the Status is 'OK 'before proceeding
if (status == google.maps.GeocoderStatus.OK) {
// Do stuff with the result here
}
If you haven't read it yet, you may want to read the Reverse Geocoding section of http://code.google.com/apis/maps/documentation/javascript/services.html#ReverseGeocoding.