KineticJS mouse position of image - mouseevent

I have a image like this
var image = new Kinetic.Image({
x : x,
y : y,
width : 1000,
height :100,
image : image,
});
How do I get the mouse position based on the image.
according this example, I could get position Object{0, 0} ~ {100, 1000}
I only found an api stage.getPointerPosition()

If you want to get mouse position on click then you can do this:
image.on('click', function(){
var mousePos = youStage.getPointerPosition();
var p = { x: mousePos.x, y: mousePos.y }; // p is a clone of mousePos
var r = image.getAbsoluteTransform().copy().invert().point(mousePos);
});
Please find the working example below albeit it uses KonvaJS but the concept is same. And you should also start using Konva cause it's well maintained and documented.
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.rawgit.com/konvajs/konva/1.4.0/konva.min.js"></script>
<meta charset="utf-8">
<title>Konva Image Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #F0F0F0;
}
</style>
</head>
<body>
<div id="container"></div>
<script>
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
var layer = new Konva.Layer();
var imageObj = new Image();
imageObj.onload = function() {
var yoda = new Konva.Image({
x: 50,
y: 50,
image: imageObj,
width: 106,
height: 118
});
yoda.on('click', function() {
var mousePos = stage.getPointerPosition();
var p = {
x: mousePos.x,
y: mousePos.y
}; // p is a clone of mousePos
var r = yoda.getAbsoluteTransform().copy().invert().point(mousePos);
console.log(r);
});
// add the shape to the layer
layer.add(yoda);
// add the layer to the stage
stage.add(layer);
};
imageObj.src = 'https://upload.wikimedia.org/wikipedia/en/thumb/9/9b/Yoda_Empire_Strikes_Back.png/220px-Yoda_Empire_Strikes_Back.png';
</script>
</body>
</html>

Related

OpenLayers 6.5.0: Features disappear when zooming in

When zooming in, all features disappear. The features are on either side of the antimeridian. In order to be able to use modify interaction, the geographical lengths of some features exceed the value of 180 degrees.
Any help is welcome!
var coords = [
[32100000, -7900000],
[28900000, -9700000],
[26300000, -10000000],
[23800000, -9300000],
[20400000, -6500000]
];
var osmLayer = new ol.layer.Tile({
source: new ol.source.OSM()
});
var featuresLayer = new ol.layer.Vector({
source: new ol.source.Vector()
});
var map = new ol.Map({
layers: [osmLayer, featuresLayer],
target: document.getElementById("map")
});
var s = featuresLayer.getSource();
for (var i = 0; i < coords.length; i++) {
s.addFeature(new ol.Feature({
geometry: new ol.geom.Point(coords[i])
}));
}
map.setView(new ol.View({
center: coords[parseInt(coords.length / 2)],
zoom: 3,
maxZoom: 18,
minZoom: 3
}));
html,
body,
.map {
width: 100%;
height: 100%;
overflow: hidden;
}
<link href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.5.0/css/ol.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.5.0/build/ol.js"></script>
<div id="map" class="map"></div>
Per #Mike's comment, use new ol.source.Vector({wrapX: false}) if your coordinates exceed the normal world
var featuresLayer = new ol.layer.Vector({
source: new ol.source.Vector({wrapX: false})
});
updated code snippet:
var coords = [
[32100000, -7900000],
[28900000, -9700000],
[26300000, -10000000],
[23800000, -9300000],
[20400000, -6500000]
];
var osmLayer = new ol.layer.Tile({
source: new ol.source.OSM()
});
var featuresLayer = new ol.layer.Vector({
source: new ol.source.Vector({wrapX: false})
});
var map = new ol.Map({
layers: [osmLayer, featuresLayer],
target: document.getElementById("map")
});
var s = featuresLayer.getSource();
for (var i = 0; i < coords.length; i++) {
s.addFeature(new ol.Feature({
geometry: new ol.geom.Point(coords[i])
}));
}
map.setView(new ol.View({
center: coords[parseInt(coords.length / 2)],
zoom: 3,
maxZoom: 18,
minZoom: 3
}));
html,
body,
.map {
width: 100%;
height: 100%;
overflow: hidden;
}
<link href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.5.0/css/ol.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.5.0/build/ol.js"></script>
<div id="map" class="map"></div>

chart to pdf using echarts and jspdf

I’ve created a graph with echarts and want to include it to a pdf by using jspdf. I found that one way to do so might be to use canvas, transfer the graph to an image and finally include the image to the pdf. However, I fail to transfer the graph to an image. Here comes the code:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>Balken</title>
<script src="echarts.js"></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.4/jspdf.debug.js"></script>
<div id="body">
<div id="chart"></div>
</div>
<!-- prepare a DOM container with width and height -->
<div id="main" style="width: 750px; height: 500px"></div>
<script type="text/javascript">
// based on prepared DOM, initialize echarts instance
var myChart = echarts.init(document.getElementById('main'));
// specify chart configuration item and data
var option = {
color: ['#3398DB'],
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: 'Salami',
type: 'bar',
barWidth: '60%',
data: [10, 52, 200, 334, 390, 330, 220]
}
]
};
// use configuration item and data specified to show chart
myChart.setOption(option);
var canvas = document.getElementById('main');
var dataURL = canvas.toDataURL();
//console.log(dataURL);
$('#exportButton').click(function () {
var pdf = new jsPDF();
pdf.addImage(dataURL, 'JPEG', 0, 0);
pdf.save('download.pdf');
});
</script>
<button id="exportButton" type="button">Export as PDF</button>
</body>
</html>
Any suggestions?
I needed this as well for a commercial product, so I did not give up until I found the solution.
You cannot use the ID of the chart to get the URL for the image, instead you need to search for the canvas.
($('canvas')[0]).toDataURL("image/png");
Notice the "[0]" means it will give your the first canvas, if you have more charts just do:
($('canvas')[0]).toDataURL("image/png");
($('canvas')[1]).toDataURL("image/png");
($('canvas')[2]).toDataURL("image/png");
3 Hours of searching and testing well spent :)
Enjoy!
I would use the toolbox, save as image:
.....
toolbox: {
feature: {
saveAsImage : {show: true}
}
}
.....
This option, among all the existing ones, will show you an icon to save the graphic as an image.
Quedaria así:
enter image description here
For more options with toolbox: http://echarts.baidu.com/echarts2/doc/option-en.html#title~toolbox
I hope it helps you.
You have to import "html2canvas" in order to make this work.
Html2canvas library will get the snapshot and that image should be written to the pdf with jspdf.
I have created a pen for this.
$("#exportButton").click(function(){
html2canvas($("#main"), {
onrendered: function(canvas) {
var dataURL=canvas.toDataURL('image/jpeg');
var pdf = new jsPDF();
pdf.addImage(dataURL, 'JPEG', 0, 0);
pdf.save("download.pdf");
}
});
});
Echart code:
<ReactEcharts
ref={(e) => {
this.echarts_react = e;
}}
option={option}
notMerge
lazyUpdate
/>
Function:
saveAsImage = (uri, name = 'undefine.jpeg') => {
var link = document.createElement('a');
link.download = name;
link.href = uri;
document.body.appendChild(link);
link.click();
};
saveAsPDF = (uri, name = 'undefine.pdf') => {
let height = echartsInstance.getHeight();
let width = echartsInstance.getWidth();
var doc = '';
if (width > height) {
doc = new jsPDF('l', 'mm', [width, height]);
} else {
doc = new jsPDF('p', 'mm', [height, width]);
}
doc.addImage(echartsInstance.getDataURL({ backgroundColor: '#fff' }), 'JPEG', 10, 10);
doc.save(name);
};
function call:
<li className="nav-item inline dropdown">
<span className="nav-link" data-toggle="dropdown">
<i className="fa fa-download" />
</span>
<div className="dropdown-menu dropdown-menu-scale pull-right">
<span
className="dropdown-item"
onClick={() =>
this.saveAsImage(this.echarts_react.getEchartsInstance().getDataURL({ backgroundColor: '#fff' }))
}>
Save as Image
</span>
<span
className="dropdown-item"
onClick={() =>
this.saveAsPDF(this.echarts_react.getEchartsInstance().getDataURL({ backgroundColor: '#fff' }))
}>
Save as PDF
</span>
</div>
</li>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.5.0-beta1/html2canvas.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.5.0-beta1/html2canvas.svg.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/amstockchart/3.13.0/exporting/rgbcolor.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/canvg/1.5/canvg.min.js"></script>
<script type="text/javascript">
// $("#list1").on("click",function(){
$("#list1").click(function(){
$("#row").html(option);
var imgData;
var svgElements = $("#row").find('svg');
//replace all svgs with a temp canvas
svgElements.each(function() {
var canvas, xml;
// canvg doesn't cope very well with em font sizes so find the calculated size in pixels and replace it in the element.
$.each($(this).find('[style*=em]'), function(index, el) {
$(this).css('font-size', getStyle(el, 'font-size'));
});
canvas = document.createElement("canvas");
canvas.className = "screenShotTempCanvas";
//convert SVG into a XML string
xml = (new XMLSerializer()).serializeToString(this);
// Removing the name space as IE throws an error
xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '');
//draw the SVG onto a canvas
canvg(canvas, xml);
$(canvas).insertAfter(this);
//hide the SVG element
////this.className = "tempHide";
$(this).attr('class', 'tempHide');
$(this).hide();
});
/* html2canvas($("#row"), {
onrendered: function(canvas) {
var imgData = canvas.toDataURL(
'image/png');
var doc = new jsPDF('p', 'mm');
doc.addImage(imgData, 'PNG', 10, 10);
doc.save('sample-file.pdf');
}
});*/
var imgData;
html2canvas($("#row"), {
useCORS: true,
'allowTaint': true,
onrendered: function (canvas) {
imgData = canvas.toDataURL(
'image/jpeg', 1.0);
canvaswidth1=canvas.width/2;
canvasheight1=canvas.height/4;
currentHeight = $("#row").height();
currentHeight2=currentHeight/2;
var imgWidth = 200;
var pageHeight = 260;
var imgHeight = canvas.height * imgWidth / canvas.width;
var heightLeft = imgHeight;
var doc = new jsPDF('p', 'm`enter code here`m','a4');
var position = 35;
doc.setFillColor(52,73,94);
doc.rect(5, 5, 200, 25, "F");
doc.setFontSize(40);
doc.setTextColor(255, 255, 255);
doc.text(80, 23, "Fitview");
doc.addImage(imgData, 'JPEG', 5, position, imgWidth, imgHeight);
heightLeft -= pageHeight;
while (heightLeft >= 0) {
position = heightLeft - imgHeight;
doc.addPage();
doc.addImage(imgData, 'JPEG', 5, position, imgWidth, imgHeight);
heightLeft -= pageHeight;
}
doc.save('healthcheck_Rapportage.pdf');
location.reload();
}
});
$("#row").find('.screenShotTempCanvas').remove();
$("#row").find('.tempHide').show().removeClass('tempHide');
});
</script>

cytoscape js event when all elements rendered?

Is there an event emitted when cy.add(elements) is finished? It appears there's an event fired for each element added, but I don't see an event when all elements have been added and rendered.
ex:
var elements = [ { data: {id: 'n1'} }, { data: {id: 'n2'} }, { data: {id: 'n3'} }, ];
cy.add(elements);
cy.on('add',function(evt){
console.log('Element Added')
})
The log will run three times.
Update I refactored per your comment. This will allow you to detect and do something after each "batch" is added.
I started with an example from the cytoscape.js website and heavily edited it for this answer.
You will probably want to run the snippet full screen to see the canvas and the console at the same time.
// For generating new IDs
var ids = [];
function newId() {
if (!ids.length) {
ids.push('1');
} else {
var id = '' + (parseInt(ids[ids.length - 1]) + 1);
ids.push(id);
}
return ids[ids.length - 1];
}
// Draw for first time
var cy = cytoscape({
container: document.getElementById('cy'),
elements: [], // don't add elements initially
style: [{
selector: 'node',
style: {
'background-color': '#666',
'label': 'data(id)',
'width': 10,
'height': 10
}
}, {
selector: 'edge',
style: {
'width': 3,
'line-color': '#ccc',
'target-arrow-color': '#ccc',
'target-arrow-shape': 'triangle'
}
}],
layout: {
name: 'grid',
rows: 1
}
});
var batchTotal = 0;
var totalAdded = 0;
// Start listening to events
cy.on('add', function(evt) {
console.log('event heard: add');
if (totalAdded < batchTotal) {
totalAdded++;
}
console.log('totalAdded/batchTotal: ', totalAdded + '/' + batchTotal);
if (totalAdded == batchTotal) {
console.log('entire batch added');
// do whatever you want!
}
});
var xStart = 10;
var x = xStart;
var y = 40;
var xInc = 20;
var yInc = 30;
var max = 200;
var addTotal = 2;
// For adding new elements
function add() {
// let's build multiple elements to add at once
var elements = [];
var id;
var el;
for (var i = 0; i < addTotal; i++) {
id = newId();
el = {
data: {
id: id
},
position: {
x: x,
y: y
}
};
elements.push(el);
if (x <= max) {
x += xInc;
} else {
x = xStart;
y += yInc;
}
}
addElements(elements);
}
// wrap the cy.add() method
// so we can inject our total counter
function addElements (elements) {
if (!Array.isArray(elements)) elements = [elements]; // convert to array
// this would be useful in a more robust app where
// addTotal may change
batchTotal = elements.length;
// reset
totalAdded = 0;
cy.add(elements);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>CytoscapeJS Example</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/2.7.0/cytoscape.js"></script>
<style type="text/css">
#cy {
width: 300px;
height: 300px;
display: block;
}
</style>
</head>
<body>
<button onclick="add()">Add</button>
<p>Click add and watch the console. Look for the <strong>entire batch added</strong> message.</p>
<div id="cy"></div>
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>

Having Issue on Adding Point Graphic to The ArcGIS API for JS Map

Can you please take a look at this JSFiddle and let me know why I am not able to add the Market into the Map? I am getting this error
Uncaught TypeError: Cannot read property 'add' of null
Here is the ode I have
var map;
var graphicsArray = [];
require(["esri/map",
"esri/geometry/Geometry",
"esri/geometry/Point",
"esri/geometry/Polyline",
"esri/geometry/Polygon",
"esri/graphic",
"esri/symbols/SimpleMarkerSymbol",
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol",
"esri/Color",
"esri/InfoTemplate",
"dojo/domReady!",
"esri/geometry"], function (Map,
Geometry,
Point,
Polyline,
Polygon,
Graphic,
SimpleMarkerSymbol,
SimpleLineSymbol,
SimpleFillSymbol,
Color,
InfoTemplate) {
map = new Map("map", {
basemap: "topo",
center: [-106.61, 35.1107],
zoom: 13
});
var point = new Point(-106.61, 35.1107);
var pointSymbol = new SimpleMarkerSymbol();
var pointAttributes = { city: "Albuquerque", state: "New Mexico" };
var pointInfoTemplate = new InfoTemplate("Albuquerque");
var pointGraphic = new Graphic(point, pointSymbol, pointAttributes).setInfoTemplate(pointInfoTemplate);
graphicsArray.push(pointGraphic);
for (i = 0; i < graphicsArray.length; ++i) {
map.graphics.add(graphicsArray[i]);
}
});
html, body, #map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
body {
background-color: #FFF;
overflow: hidden;
font-family:"Trebuchet MS";
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="http://js.arcgis.com/3.14/esri/css/esri.css">
<script src="http://js.arcgis.com/3.14/"></script>
<div id="map"></div>
You are trying to add this point when the map isn't fully loaded.
So just wait for the map to be fully loaded and then add the point, by wrapping your loop inside this function:
map.on('load', function() {
console.log('load event called');
for (i = 0; i < graphicsArray.length; ++i) {
map.graphics.add(graphicsArray[i]);
}
});
ESRI has a small documentation on how to work with events here

Changing slider width from px to %

I've built a slider using css, javascript and html. I have a bit of javascript which controls the width and height of the div which contains the slider, as well as the slide speed. However, I want to make the width of the slider 100% of the screen, no matter what size screen. It is currently defined in pixels, but whenever i define it as % it simply disappears. Any ideas or suggestions?
Here is the code
<script type="text/javascript">
$(function() {
$('#one').ContentSlider({
width:1600,
heigth:400,
speed : 800,
easing : 'easeInOutBack'
});
});
</script>
HTML CODE
<title> </title>
<body>
<div id="one" class="contentslider">
<div class="cs_wrapper">
<div class="cs_slider">
<div class="cs_article">
Insert Images Here
</div><!-- End cs_article -->
</div><!-- End cs_slider -->
</div><!-- End cs_wrapper -->
</div><!-- End contentslider -->
<!-- Site JavaScript -->
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" src="ContentSlider.js"></script>
<script type="text/javascript" src="ContentSlider.js"></script>
<script type="text/javascript">
$(function() {
$('#one').ContentSlider({
width:1600,
heigth:600,
speed : 800,
easing : 'easeInOutBack'
});
});
</script>
<script src="ContentSlider.js" type="text/javascript"></script>
<script src="ContentSlider.js" type="text/javascript"></script>
</body>
CSS CODE
body {
font:80%/1.25em arial, sans-serif;
letter-spacing:.1em;
margin-top: 0px;
margin-right: 0px;
margin-bottom: 0px;
margin-left: 0px;
width:100%;
height:100%
}
h1, h2, p, pre {
display:block;
width:99%;
}
.contentslider {
padding:10px; /* This acts as a border for the content slider */
background:#333; /* This is the color of said border */
}
.contentslider {
position:relative;
display:block;
width:100%;
height:100%;
margin:0 auto;
overflow:hidden
}
.cs_wrapper {
position:relative;
display:block;
width:100%;
height:100%;
margin:0;
padding:0;
overflow:hidden;
}
.cs_slider {
position:absolute;
width:10000px;
height:100%;
margin:0;
padding:0;
}
JAVASCRIPT CODE
(function($) {
$.fn.ContentSlider = function(options)
{
var defaults = {
leftBtn : 'cs_leftImg.jpg',
rightBtn : 'cs_rightImg.jpg',
width : '900px',
height : '400px',
speed : 400,
easing : 'easeOutQuad',
textResize : false,
IE_h2 : '26px',
IE_p : '11px'
}
var defaultWidth = defaults.width;
var o = $.extend(defaults, options);
var w = parseInt(o.width);
var n = this.children('.cs_wrapper').children('.cs_slider').children('.cs_article').length;
var x = -1*w*n+w; // Minimum left value
var p = parseInt(o.width)/parseInt(defaultWidth);
var thisInstance = this.attr('id');
var inuse = false; // Prevents colliding animations
function moveSlider(d, b)
{
var l = parseInt(b.siblings('.cs_wrapper').children('.cs_slider').css('left'));
if(isNaN(l)) {
var l = 0;
}
var m = (d=='left') ? l-w : l+w;
if(m<=0&&m>=x) {
b
.siblings('.cs_wrapper')
.children('.cs_slider')
.animate({ 'left':m+'px' }, o.speed, o.easing, function() {
inuse=false;
});
if(b.attr('class')=='cs_leftBtn') {
var thisBtn = $('#'+thisInstance+' .cs_leftBtn');
var otherBtn = $('#'+thisInstance+' .cs_rightBtn');
} else {
var thisBtn = $('#'+thisInstance+' .cs_rightBtn');
var otherBtn = $('#'+thisInstance+' .cs_leftBtn');
}
if(m==0||m==x) {
thisBtn.animate({ 'opacity':'0' }, o.speed, o.easing, function() { thisBtn.hide(); });
}
if(otherBtn.css('opacity')=='0') {
otherBtn.show().animate({ 'opacity':'1' }, { duration:o.speed, easing:o.easing });
}
}
}
function vCenterBtns(b)
{
// Safari and IE don't seem to like the CSS used to vertically center
// the buttons, so we'll force it with this function
var mid = parseInt(o.height)/2;
b
.find('.cs_leftBtn img').css({ 'top':mid+'px', 'padding':0 }).end()
.find('.cs_rightBtn img').css({ 'top':mid+'px', 'padding':0 });
}
return this.each(function() {
$(this)
// Set the width and height of the div to the defined size
.css({
width:o.width,
height:o.height
})
// Add the buttons to move left and right
.prepend('<img src="'+o.leftBtn+'" />')
.append('<img src="'+o.rightBtn+'" />')
// Dig down to the article div elements
.find('.cs_article')
// Set the width and height of the div to the defined size
.css({
width:o.width,
height:o.height
})
.end()
.find('.cs_leftBtn')
.css('opacity','0')
.hide()
.end()
.find('.cs_rightBtn')
.hide()
.animate({ 'width':'show' });
if(o.textResize===true) {
var h2FontSize = $(this).find('h2').css('font-size');
var pFontSize = $(this).find('p').css('font-size');
$.each(jQuery.browser, function(i) {
if($.browser.msie) {
h2FontSize = o.IE_h2;
pFontSize = o.IE_p;
}
});
$(this).find('h2').css({ 'font-size' : parseFloat(h2FontSize)*p+'px', 'margin-left' : '66%' });
$(this).find('p').css({ 'font-size' : parseFloat(pFontSize)*p+'px', 'margin-left' : '66%' });
$(this).find('.readmore').css({ 'font-size' : parseFloat(pFontSize)*p+'px', 'margin-left' : '66%' });
}
var leftBtn = $(this).children('.cs_leftBtn');
leftBtn.bind('click', function() {
if(inuse===false) {
inuse = true;
moveSlider('right', leftBtn);
}
return false;
});
var rightBtn = $(this).children('.cs_rightBtn');
rightBtn.bind('click', function() {
if(inuse===false) {
inuse=true;
moveSlider('left', rightBtn);
}
return false;
});
vCenterBtns($(this));
});
}
})(jQuery)
You could change width to $(this).parent().innerWidth(), but that will only work on init, if the user resizes it will not change. This is because the plugin only sets a size on init
Might be a better idea to search for a fullwidth slider, these often fix some issues which arrise with fullwidths and resizing