Now that SwiftUI can use SVG images directly, I have tried to use a set of SVG files as icons for a TabBar. Using typical TabBar code:
TabView(selection: $lastTab){
VendorView()
.tabItem {
Image ("store")
.renderingMode(.template)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 25.0, height: 25.0)
Text("Vendor")
}
.tag(0)
...
Unfortunately this does not seem to work as the SVG image is never resized to the requested 25x25 size.
Has anyone else experienced this and if so, any workarounds?
The best way to handle the issue of SVGs in the TabView as an Image() is to do the following steps:
resize your SVG in Sketch/Figma or other program to 22x22 / 24x24...
Bring said resized SVG to assets and in your Inspector select:
Render as: Template Image
Resizing: Preserve vector data
Scales: Single Scale
No need to use .resizable() nor .frame()
I have learnt new tips and original answer by: Mark Moeykens
https://stackoverflow.com/a/37627080/15382735
Related
The program I'm using is this
var canvas = this.__canvas = new fabric.Canvas('c');
canvas.setHeight(300);
canvas.setWidth(500);
function AddCircle() {
canvas.add(new fabric.Circle({
left: 230/canvas.getZoom(),
top: 140/canvas.getZoom(),
radius: 75/canvas.getZoom(),
fill: 'green',
}));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<button onclick="AddCircle()">Add Circles</button>
<br>
<br>
<button onclick="Saveas()">Save as</button>
<button onclick="Openfile()">Open file</button>
<div class="box">
<canvas id="c"></canvas>
So now. I want to save the canvas (all the content/all the circles or objects) as a file. At this point I have seen that there are a few ways to save, for example, as png. But The problem is that I don't want to loose quality of the work inside of canvas.
I have seen libraries like jason. But I really don't know to implement them.
Also I have seen that working with svg for saving as files is easier since it can be saved/open as .xhml file without loosing quality.
My other question is:
Is there a easy way to convert the canvas to xhml, so when you click save button, you save the file as xhml, once saved back to use it by clicking "open file button" to open the .xhml file and conver it to canvas again (to show the content in the workspace)?
This are just my thinkings, any suggestions, libraries you recommend more or demo snippets for solving this would be very appreciated.
My last is. What do you recommend more, working with canvas libraries or svg libraries?. Im planning to make a very basic app like Prezi.com is (create objects) Online saving files and so... (also I plan to insert svg and maybe animations to the work space)
As you see, now I'm using canvas libraries ( in particular fabric.js). But since I'm starting it'd be easier for me to change if I'm not using the best alternative.
I am not sure that is possible,
HTML Canvas it's a Bitmap, that you draw in with Javascript.
SVG embedded in an HTML document, It's just like a subtree of the DOM, that still has a valid XML representation that any (not sure if any but most), SVG editors and viewers will understand.
You can "emulate" a canvas with SVG, easily by setting a svg or div + svg and then appending all the childs to this svg and because the geometric ideas of drawing in canvas and doing vector graphics are not that different, you could "migrate" to it.
The tip here is to define a viewbox on the SVG as you would define the canvas dimensions, and then, you can preserve your units. (just be careful with the numbers)
Plus it would be easier to attach events to the SVG elements.
To be honest the w3schools tutorial on SVG it's comprehensive enough, the rest from that it's just a good use case and use their building blocks (with javascript)
This is how you would create an SVG element for the DOM.
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.setAttributeNS(null, 'x', 5);
circle.setAttributeNS(null, 'y', 15);
# more code...
I think saving the image as a png file should be just fine. Png compression is lossless and supports transparent images, so drawing a previously saved png file to the canvas should perfectly restore the content without any changes.
Also, I'm not sure if storing it as a svg file would work that well, since svg is a vector graphics format and the canvas is a bitmap. I know it is possible to embed bitmap images in an svg file, but that requires it to be stored in a bitmap format in the first place.
I'm using fabricjs 1.7.17 and have seen this issue below on IE Edge, Chrome and Firefox.
where the canvas is being set with a width and height in HTML of 768px.
Within my fabricjs canvas init I've got:
editor.canvas = new fabric.Canvas('editor')
editor.canvas.setDimensions({
width: 1080,
height: 1080,
allowTouchScrolling: false,
backgroundColor: 'rgba(55, 55, 55, .33)',
rotationCursor: 'url(/static/img/rotate.cur) 10 10, crosshair'
}, {backstoreOnly: true})
The problem is when you call the editor.canvas.toDataURL() method the size of the goes from 768px to 1080px
If you call the browser's native canvas.toDataURL() method there isn't a jump in size.
Anyone bump into this and have a possible fix?
Here's a simplified jsfiddle:
https://jsfiddle.net/m8dhmbtu/23/
Click on the "Native Canvas.toDataURL()" and you'll get the results to console.log and there will be no change to the displayed canvas in the preview window.
Click on the "Fabricjs canvas.toDataURL()" and you'll also get the results (the same) to console.log however; you'll also get a jump in the size of the in the preview window...this is what I'm trying to prevent.
I think the problem is actually a bug.
You set the canvas to 1080 for backstore dimension only, meaning that the canvas will be sized but the css will be left untouched.
A dataurl will reset the canvas after the process to fix it back in case the export to data url had a multiplier.
while this can be fixed at least for the non multiplied situations, a proper fix is needed.
The proper fix consist in setting backstore only during export so that the css does not get touched.
A better fix would be to do not touch the original canvas and create one on the fly just for exporting.
please go on official fabricjs repository and open an issue for this.
Having a strange issue while using SVGs in TornadoFX. I have a few SVGs strings stored in an enum I'm using as background images in my program. When I view the exact same SVG path in an online viewer, there is no distortion and it appears correctly:
but when I use the same path in TornadoFX as a svgpath node content, it appears like so:
Note the strange thinning of the lines in the top and bottom middle sections.
It's easier to see with the second svg:
Online viewer:
TornadoFX program:
I'm not quite sure what could be causing this. In everything else I view the SVGs in (web, illustrator) they appear fine, but as soon as I load them as a string in a svgpath node, they appear distorted.
I'm initializing them like this:
class mView : View() {
override val root = stackpane {
svgpath("M910.7,329.8a446.43,446.43,0,1,0,35,173.23A443.52,443.52.. etc") {
addClass(SvgStyle)
}
//..
}
Any ideas what would be causing this strange distortion? I'm pullin my hair out here.
edit: a fiddle of the curvy SVGs
TornadoFX doesn't affect the SVG rendering in any way, so I can't see any other explanation that this being a bug in the SVG rendering capabilities of JavaFX. Perhaps you're using a path expression not supported by JavaFX?
For the sphere, can you try setting the stroke on the SVGPath object as in the following example?
stackpane {
svgpath("M107 380c40,-101 80,-102 120,-1m-1 -4c39,101 79,102 120,1m-1 4c39,-101 79,-101 120,-1m-1 -2c39,100 79,101 120,1", FillRule.EVEN_ODD) {
fill = Color.WHITE
stroke = Color.BLACK
strokeWidth = 16.0;
}
}
In the curves part of the question, can you post the full SVG path? I suspect there's something in the path source telling JavaFX to render the thinner segments.
I defined CSS transition rules in my svg. It's something like:
#mark #bg {
transition: fill 200ms;
fill: #245575;
}
#mark:hover #bg {
fill: #ff5c26;
}
When I drag it into browser's blank page and test it, the transition works fine. But if I embed the svg into my website using <img src="images/mark.svg" alt="">, the transition doesn't work.
Did I miss something?
Images either via <img> tags of via the CSS background-image image property cannot be interactive and have other restrictions in order to maintain user's privacy and security.
If you ask yourself "could I do this if the image was a .png or a .gif?" then you'll be on the right lines. Browsers have deliberately chosen to keep to the same mental model for SVG files so that the capability of images is easy to understand.
If you want transitions to work you'll need to use an <object> or <iframe> tag or embed the SVG inline in the html document.
I have a function that adds an imageOverlay and a semitransparent Rectangle on top of that image (so as to tint the image, and draw a keyline around it).
activeUserImage = new L.imageOverlay(imageUrl, imageBounds).addTo(map);
activeUserTile = new L.rectangle(imageBounds, {stroke: true, color: "#ffffff", opacity:1, weight: 1, fillColor: "#003572", fillOpacity: 0.7, clickable:true}).addTo(map);
this works great, but then I want to remove the image and rectangle with:
map.removeLayer(activeUserImage);
map.removeLayer(activeUserTile);
This seems to work well...
However when I try and add a second Image & Rectangle (using the same function) the rectangle SVG is being rendered underneath the image, so I don't see the colored overlay.
This seems to be because the element is being left behind from the first creation, and then when the image is being added a second time it appears in front of the SVG.
Q:
Is this a bug? Should the SVG element not be cleared too?
Can I adjust z-index of the image or SVG on creation?
should i be containing to rectangle in a different layer to the images? How?
Many Thanks
OK, so the Leaflet bringToFront() method didn't work, but instead I have used a bit of JQuery to force the same approach.
svgObj = $('.leaflet-overlay-pane svg');
svgObj.css('z-index', 9999);
This works, but still feels like a hack... however if (?) there is a bug in LEaflet, then maybe this will have to do???
Any better ideas?
The bringToFront() function alows you to bring layer to the top.
Search it in the docs.