I am using PaperJS and I need to use an existing set of icons that I can receive as a base64 string (that's a given I can't change). I have no problem rendering the rasters.
However when I set them a position like so:
const myRaster = new Raster(<someBase64>);
myRaster.position = new Point(receivedX, recievdY);
myRaster.onClick = () => console.log('raster click');
The onClick event would only work if I click exactly on [x,y] point assigned to the position property.
The X and Y are received form a data base and are in accordance to other visible elements.
I played around in the PaeprJS website, and without using a new Point position the onClick works all around the image.
My solution for now is creating an invisible polygon (new Path.RegularPolygon) and to attach to onClick event to it and it works.
However, there's must be a simpler solution and would love to understand what I am missing here.
Thanks!
Apparently, the SVG was partially created programmaticly and had a lot of whitespace around it.
Testing with base64 encoded SVGs from various different sources worked as expected
Related
I've read various examples on how to use the Highcharts.SVGRenderer to create custom SVG text etc.
However, I'm wondering what is the correct practices to create and clean them up?
Currently I make them at the events.redraw hook (because I want to update the SVG text based on the dynamic data), however it looks like the redraw hook is being called at various occasions multiple times (it looks like it'd redraw on add series and data being added) and then the SVG does not get cleaned up... so I ended up having multiple copies of the same SVG elements in the chart. Any subsequence redraw would obviously keep adding more SVGElements into the chart.
Questions:
Do i need to keep track of all the generated SVGElements myself and call destroy() manually every time I redraw them?
Is there any internal trackers in Highcharts that tracks the created SVG using SVGRenderer? (so that I could maybe use the internal ref to call destroy myself)
If I am not supposed to draw them in redraw event, what is the recommended hook to draw my SVG elements where I need dynamic update on those generated SVG elements.
Do I absolutely need to keep track of my own references on the SVG elements? Seems a bit too much of the overhead/hassle to do that.
Yes, you need to keep track of all the generated SVG elements, which you want to update, but better than destroying them is to update their attributes.
No, there is no such trackers.
You can draw the elements in the load event and redraw them when you need to (for example when you change your data).
No, you have to keep track only those elements that you need update. Maybe some of your problems will be resolved by by annotations? https://www.highcharts.com/docs/advanced-chart-features/annotations-module
events: {
render: function() {
var chart = this,
series = chart.series[0],
x = series.points[2].plotX,
y = series.points[2].plotY - 50;
if (!chart.customElement) {
chart.customElement = chart.renderer.text().add();
}
chart.customElement.attr({
text: 'some text ' + Math.random(),
x,
y
});
}
}
Live demo: http://jsfiddle.net/BlackLabel/t250crx1/
API Reference: https://api.highcharts.com/class-reference/Highcharts.SVGElement#attr
Here is my issue; I am trying to display "markers" and on mouse over/out/click give some actions.
The problem is that no event gets fired on over at all and when on click (down) in the console I get some feedback, but not of the element per say (target == undefined).
My different shapes are groups in a group called "marker".
And I group everything with the following:
marker.add(plateShape, plateLabel, line, indicator);
When using
marker.addWithUpdate(plateShape, plateLabel, line, indicator);
I get some feedback (over being finicky at best) but the layout get completely messed up.
You can comment/uncomment Line 86 to check the behaviour in the following fiddle.
https://jsfiddle.net/u7x7az1j/5/
Thank you for your help! :)
The problem comes from your use of add.
Replace add with addWithUpdate and be aware that addWithUpdate takes one parameter at time.
marker.addWithUpdate(plateShape);
marker.addWithUpdate(plateLabel);
marker.addWithUpdate(line);
marker.addWithUpdate(indicator);
i tried on your fiddle and it works.
Consider replacing rect + triangle + line with a simple parametric fabric.Path you can easily build.
Hiho,
I prepared a snippet.
As in my example I'm using the drawImage function to draw images to a game, because I don't want to include them all in HTML ... However, my problem is, I can't find any possibility to give those "own created" images an onclick function. I thought the object "Image" (var someImage = new Image();) was comparable to the HTML <img> or <input type="image">, but no matter how hard I try, I can't make it.
Can anyone help me?
You've given the click event to the canvas context and not the canvas, change it to:
myCanvas.onclick = function()
As for making the individual images clickable (if you draw more than one), you can always keep an array of the clickable areas and the links they should go to that correspond to the images, then add a loop to the canvas click to check that the mouse co-ords match up to on of the areas in the array.
Example : JSFiddle Code
Is there a way to just generate an svg and get it as a string without actually drawing it? I thought about render svg to a hidden div and then reading the inner html, but is there a cleaner way?
I would think you could do this:
var svg = d3.select("body").append("svg")
svg = d3.select(svg).remove()
Append the svg to the body, but immediately remove it. This will, of course, give you the 'd3 selection' object, not a string.
You can create a whole other DOM tree in javascript using createDocumentFragment(). This is commonly used to create a complex section of the document and then add it all to the page in one step, so the browser only has to re-calculate layout once.
I haven't tested it, but you should also be able to use .innerHTML() to extract everything you've created as a string that can be saved to file. Answers to this SO Question suggest that you can't call innerHTML() directly on the document fragment itself, so you would have to add a body element to the fragment, add your SVG to it, and then get the inner HTML from the body node.
One way to approach this problem is by checking how it would be done on the server side -- where there is no DOM.
As it turns out, the way to do this on the server side involves more or less the same "hack" used in the question. This is because d3 expects to work on a DOM; writing that DOM to HTML is really the only way to render it to a string.
Brief example:
var svg = window.d3.select('body')
.append('div').attr('class','container')
.append('svg'); // and lots of other stuff
//etc etc
svg.selectAll('.arc').doSomething('blah blah');
var svgAsString = d3.select('.container').html();
I'm trying to do something simple to practice my Javascript (which I learned some recently) and I'm trying to do a game on it (pacman to be precise).
I am trying to build that game board on the browser by creating images dynamically. I've done an array like this:
var images= new Array(25);
for(i=0;i<25;i++)
images[i]= new Array(25);
And, for the game board I used a matrix done with 0 and 1's with 25x25 size (not going to post it here cause is too big and would make my text hard to read) called board.
For the images that I am using right now I have something like this:
var image_empty = new Image();
image_empty.src="Images/empty.jpg";
var image_wall = new Image();
image_wall.src="Images/wall.jpg";
For the initialization function I have something like this:
function drawField()
{
for(i=0;i<board.length;i++)
{
for(j=0;j<board[i].length;j++)
{
if(board[i][j] == 0)
draw(i,j,image_empty);
else if(board[i][j] == 1)
draw(i,j,image_wall);
}
}
}
And for drawing the images themselves I am using this:
function draw(x,y,img)
{
images[x][y] = new Image(22,22);
images[x][y].src = img.src;
images[x][y].style.position = 'absolute';
images[x][y].style.left = 40+x*22;
images[x][y].style.top = 40+y*22;
}
Every time I run this code nothing appears on the screen. I've tried several times use a load of things but nothing happens. I am saving the pictures (at least I think I am) and still nothing.
Can someone give me some pointers of what could be wrong?
PS: Some people pointed me out using the appendChild method would solve the problem, still, since pacman will be moving around I can't use it to store my images (and I was planning to use the draw function to draw anything).
And btw nor Web Developer plugin or firebug point out errors (the code is correct from their perspective).
Creating an Image in the method you describe doesn't actually display the image. Even putting attributes and styling to make it appear a certain way doesn't add it to the DOM. The advice about append child is correct. For example, if you had:
<div id="main"></div>
and you called
document.getElementById("main").appendChild(images[x][y]);
this would insert the image inside the div. You could do this repeatedly to generate the equivalent of...
<div id="main">
<img src... />
<img src... />
...and so on
</div>
Then, your CSS styling and positioning would work.
There's nothing wrong with your script, but Firebug does display a rendered version of the DOM. As you run the script, you will actually see the HTML tab of Firebug changing with the images you've added to the page.
Also, keep in mind that the DOM must complete loading before you are able to run this. You can accomplish this by doing a simple:
<body onload="drawImages()">
UPDATE: Once you've actually added the 25x25 images, the array still references the elements - they're just now part of the DOM. So, you can change their source via:
images[x][y].src = "newImage.jpg";
If you, for some reason, wanted to remove an image from the board, leaving a gap, you can remove it from the DOM
document.getElementById("main").removeChild(images[x][y]);
or just hide it via CSS.