We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date
close icon

How to restrict the SfDiagram size to it's background image?

Hello,

We work on an UWP app that:
- will sync data with a web app 
- must allow user to drag & drop shapes on a photo: for this, we use SfDiagram
- then the result of the photo and shapes is used in some views of the app

So, the photo could be:
- taken by the user' camera directly on the tablet app (in this case we know the image's "ratio",  as we force the save in 1920*1080)
- added by a user of the web app  (in this case the ratio can vary, as there are no size restrictions)

Syncfusion helps us to create this view, allowing users to easily drag & drop shapes on the photo and edit the color of these shapes:
App screenshot

But there is problem to export the result. As Syncfusion has not yet developed the feature "Export UWP Diagram into Image", we have used the solution given by Martin Kurek here (ExportDiagramAsImage):
protected async Task<IRandomAccessStream> GenerateImage(UIElement diagram)
{           
	// Render to an image at the current system scale and retrieve pixel contents
	var renderTargetBitmap = new RenderTargetBitmap();

	// unselect all nodes
	ObservableCollection<TraNode> nodes = ((diagram as SfDiagram).Nodes as ObservableCollection<TraNode>);
	if(nodes != null && nodes.Count > 0)
	{
		foreach (var node in nodes)
		{
			node.IsSelected = false;
		}
	}

	await renderTargetBitmap.RenderAsync(diagram);
	var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();

	var pixelBytes = new byte[pixelBuffer.Length];
	using (var reader = DataReader.FromBuffer(pixelBuffer))
	{
		reader.ReadBytes(pixelBytes);
	}
			   
	IRandomAccessStream stream = new InMemoryRandomAccessStream();
	var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);

	encoder.SetPixelData(
		BitmapPixelFormat.Bgra8,
		BitmapAlphaMode.Straight,
		(uint)renderTargetBitmap.PixelWidth,
		(uint)renderTargetBitmap.PixelHeight,
		DisplayInformation.GetForCurrentView().LogicalDpi,
		DisplayInformation.GetForCurrentView().LogicalDpi,
		pixelBytes);

	await encoder.FlushAsync();
   
	return stream;
}
This works fine, but there is a limit: the entire surface of the SfDiagram in the Window is exported. That means that there canbe black or white stripes below or next the original image.

For example:
Result

I search so the better way to manage the background image and the export of the result.

I initially tried to use the background image through a Node of the SfDiagram:
<DataTemplate x:Key="nodeImageTemplate">
    <Border Background="White">
        <Image Source="{Binding Path=CustomImage}" Stretch="Fill" />
    </Border>
</DataTemplate>  

<syncfusion:SfDiagram.Nodes>
	<syncfusion:NodeCollection>
		<syncfusion:NodeViewModel ContentTemplate="{StaticResource nodeImageTemplate}" 
					  Pivot="0,0" />
	</syncfusion:NodeCollection>
</syncfusion:SfDiagram.Nodes>

=> This works, but I didn't found the way to increase the size of the background image automatically. In add, as we pass through a Node, we can't click on the background image to "deselect" dropped shape.

Then I tried to use the background image through the Background of the SfDiagram:
<syncfusion:SfDiagram.Background>
	<ImageBrush ImageSource="/Assets/BackgroundImage.jpg" Stretch="Uniform"
				AlignmentX="Left" AlignmentY="Top" 
	/>
</syncfusion:SfDiagram.Background>
=> This works fine and the background image automatically takes all the available space. But there are still problem at export, as I mentioned above.

Finally Syncufsion has suggested me to use PageSettings and PageBackground:
<!--#Add the Below code into the Page.Resources--> 
<!--#Image Brush --> 
<ImageBrush x:Key="bgimage" ImageSource="/Assets/BackgroundImage.jpg" Stretch="Fill"/> 
<!--# PageSettings --> 
<syncfusion:PageSettings x:Key="diagrampage" PageWidth="1000" PageHeight="1000" PageBorderBrush="Red"PageBackground="{StaticResource bgimage}" /> 
 
<!--# Initializes Diagram and Bind the PageSettings properties--> 
<syncfusion:SfDiagram x:Name="diagram" PageSettings="{StaticResource diagrampage}"> 
=>But it didn't work at all: I wasn't able to show the background image in the SfDiagram...

So which of these solutions is the better for us, allowing to:
- maximize the size of the background image
- export the result keeping the original ratio, without black or white stripes, for each resolutions


I attach your the sample use for the screenshots.

Regards,



Attachment: 127065__Stencil_73ed3ef3.7z

13 Replies

KR Keerthivasan Ramamoorthy Syncfusion Team December 9, 2016 09:59 AM UTC

Hi Pierre, 
 
Requirement: Need to set image as Diagram Background.  
  
We have a support to achieve your requirement by using PageBackground property of the PageSettings to change the appearance of the Diagram Page.  In the previous sample, we have set the image as Background property of the Diagram. Instead of that, please set the image as PageBackground property of the PageSettings to the Diagram. And also, please adjust the PageWidth and PageHeight as per the requirement.  
 
We have provided modified sample and screenshot to represent this. Please refer to the sample and screenshot as below. 
 
 
Screenshot: 
 
 
Regards, 
Keerthivasan R. 



PD Pierre-Christophe DUS December 13, 2016 04:20 PM UTC

Thanks for your feedback, but I'm not sure to understand when you say:
"And also, please adjust the PageWidth and PageHeight as per the requirement. "
How can I do this?
I need to know:
- the image resolution, to determinate and keep the original ratio
- the "available space" in the view, to maximize the size of the image in the diagram
But I don't see how I could do this...

It was easier for me to set the image through the Background of the SfDiagram, as this ensures me to maximize the size of the image in the diagram.



KR Keerthivasan Ramamoorthy Syncfusion Team December 14, 2016 10:38 AM UTC

Hi Pierre, 
 
Requirement 1: 
We assumed that your requirement is “Need to extend the image size when Scroll (Horizontal/Vertical) to the Diagram or show the image in Viewable area”, please use PageSettings Property. We used PageSettings property, please to set the PageWidth and PageHeight as per the Diagram viewable spaces in your application. We have provided a code example (PageSettings Code Example) and screenshot to represent this. Please refer the code example and screenshot as below. 
 
Requirement 2: 
We assumed that your requirement is “Need to set the image as Diagram viewable area”, please use Background Property of the Diagram. We used Background property, please use below code example (Diagram Background Code Example) in your application. We have provided a screenshot to represent this. Please refer the code example and screenshot as below. 
 
Diagram Background Code Example: 
<!--#region set the image as Diagram Background--> 
<syncfusion:SfDiagram.Background> 
<ImageBrush ImageSource="/Assets/BackgroundImage.jpg" Stretch="Fill" 
AlignmentX="Left" AlignmentY="Top" 
/> 
</syncfusion:SfDiagram.Background> 
 
//InitializeDiagram Method. 
private void InitializeDiagram() 
{ 
diagram.ScrollSettings.ScrollLimit = ScrollLimit.Diagram; 
diagram.PageSettings.PageBorderBrush = new SolidColorBrush(Windows.UI.Colors.Transparent); 
diagram.PageSettings.PageBackground = new SolidColorBrush(Windows.UI.Colors.Transparent); 
} 
 
PageSettings Code Example: 
<!--#Add the Below code into the Page.Resources--> 
<ImageBrush x:Key="bgimage" ImageSource="/Assets/BackgroundImage.jpg" Stretch="Fill"/> 
 
<syncfusion:PageSettings x:Key="diagrampage" PageWidth="1120" PageHeight="680" PageBorderBrush="Red" PageBackground="{StaticResource bgimage}" /> 
 
<!--#region Initializes Diagram--> 
<syncfusion:SfDiagram x:Name="diagram" PageSettings="{StaticResource diagrampage}"> 
 
//InitializeDiagram Method. 
private void InitializeDiagram() 
{ 
diagram.ScrollSettings.ScrollLimit = ScrollLimit.Diagram; 
} 
 
 
 
 
Diagram Background and PageSettings screenshot: 
 
 
 
 
Regards, 
Keerthivasan R. 



PD Pierre-Christophe DUS January 12, 2017 10:12 AM UTC

Hello,
I encounter a new problem: the customer would like that each added item directly apply the selected color.

I initially tried to do this through this:
private void MainWindow_ItemAdded(object sender, ItemAddedEventArgs args)
{
if (args.ItemSource == ItemSource.Stencil)
{
var dropedItem = args.Item as NodeViewModel;

if (dropedItem != null)
{
Thickness = DefaultThickness;
if (dropedItem.Key.ToString().ToLower().Contains("arrow"))
{
Fill = DefaultFill;
Stroke = DefaultStroke;
dropedItem.ShapeStyle = GetDefaultStyle();
}
else
{
Fill = DefaultFill;
Stroke = null;
dropedItem.ShapeStyle = GetDefaultStyle();
}
}
}
}
=> it didn't work at all

Then I tried to update the properties of each items:
private void MainWindow_ItemAdded(object sender, ItemAddedEventArgs args)
{
if (args.ItemSource == ItemSource.Stencil)
{
var dropedItem = args.Item as NodeViewModel;
}
if (diagram.Nodes != null)
{
foreach (NodeViewModel node in diagram.Nodes as DiagramCollection<NodeViewModel>)
{
if (node.Key != null)
{
if (thick != 0)
Thickness = DefaultThickness;
if (node.Key.ToString().ToLower().Contains("arrow"))
{
Fill = DefaultFill;
Stroke = DefaultStroke;
node.ShapeStyle = GetDefaultStyle();
}
else
{
Stroke = DefaultStroke;
Fill = null;
node.ShapeStyle = GetDefaultStyle();
}
}
}
}
}
=> It's only working for the items that has been previously added, but not for the new item...

This is the GetDefaultStyle() method:
private Style GetDefaultStyle()
{
Style s = new Style();
s.TargetType = typeof(Windows.UI.Xaml.Shapes.Path);
if (Fill != null)
{
s.Setters.Add(new Setter(Windows.UI.Xaml.Shapes.Path.FillProperty, DefaultFill));

}
if (!double.IsNaN(Thickness) && !double.IsInfinity(Thickness))
{
s.Setters.Add(new Setter(Windows.UI.Xaml.Shapes.Path.StrokeThicknessProperty, DefaultThickness));
}
if (Stroke != null)
{
s.Setters.Add(new Setter(Windows.UI.Xaml.Shapes.Path.StrokeProperty, DefaultStroke));
}
s.Setters.Add(new Setter(Windows.UI.Xaml.Shapes.Path.StretchProperty, Stretch.Fill));

return s;
}

=> Would you have any idea?


KR Keerthivasan Ramamoorthy Syncfusion Team January 13, 2017 09:48 AM UTC

Hi Pierre, 
Requirement:” Need to set Selected Color directly to the Dragging Nodes from Stencil” 
We have analyzed and provided a solution to achieve your requirement. Please use DragEnter Event instead of using ItemAdded Event. We have provided a code example and Video to represent your requirement. Please refer the code example and video link as below. 
 
Code Example: 
//DragEnterEvent 
(diagram.Info as IGraphInfo).DragEnter += MainPage_DragEnter; 
 
private void MainPage_DragEnter(object sender, ItemDropEventArgs args) 
{ 
  if (args.ItemSource == Cause.Stencil) 
   { 
     var dropedItem = args.Source as Node; 
 
     if (dropedItem != null) 
     { 
       dropedItem.ShapeStyle = GetCustomStyle(); 
     } 
   } 
} 
 
Here, diagram is instance of SfDiagram. 
 
 
 
Regards, 
Keerthivasan R. 
 



PD Pierre-Christophe DUS January 24, 2017 01:40 PM UTC

Thank you it works fine.
Regards,



SS Suresh Shanmugam Syncfusion Team January 25, 2017 10:24 AM UTC

Hi Pierre, 
Thanks for your update. Please let us know, if you need further assistance. 
 
Regards, 
Suresh Shanmugam 



PD Pierre-Christophe DUS February 7, 2017 06:11 PM UTC

Hello, I need help again about the use of SfDiagram.

The component answers to my needs, and everything works well now, but I have a small  "performance" problem: the view takes a "long" time to be loaded and displayed.

On my dev computer, the loading time is correct (less than 1/2 second):
06.30.16.372063 : FirstPage - Button_Click()  - start
06.30.16.379065 : MainPage - MainPage()  - start
06.30.16.724063 : MainPage - InitializeDiagram()  - start
06.30.16.727065 : MainPage - InitializeDiagram()  - end
06.30.16.742063 : MainPage - MainPage()  - end
06.30.16.748567 : FirstPage - Button_Click()  - end
But on the tablet where app must be used, the loading time is more important (more than 1 second):
07.00.09.540502 : FirstPage - Button_Click()  - start
07.00.09.556127 : MainPage - MainPage()  - start
07.00.10.540569 : MainPage - InitializeDiagram()  - start
07.00.10.556196 : MainPage - InitializeDiagram()  - end
07.00.10.603076 : MainPage - MainPage()  - end
07.00.10.618700 : FirstPage - Button_Click()  - end
The tablet is based on a Intel Atom processor (x5-Z8550), has 4 Go of RAM (LPDDR3 - 1600 Mhz) and a SSD drive. All the users would use a similar configuration.

Is it possible to optimize the opening of the page?

I've attached you the sample on which I'm based for my logs: it's close to context of the "real" app.

Regards,



Attachment: 127065__Stencil__Req1_b32cac2d.7z


PD Pierre-Christophe DUS February 10, 2017 11:20 AM UTC

Hello, 

I comme back to you again cause I meet another problem: the generated image doesn't keep the original ratio of the picture.
It seems that all the available space on the screen is exported, which can affect the rendering of the images in the app.

However, the Background of the SfDiagram is defined like this:
<syncfusion:SfDiagram.Background>
<ImageBrush x:Name="photo"
ImageSource="/Assets/image.jpeg" 
Stretch="Uniform" AlignmentX="Left" AlignmentY="Top" 
/>
</syncfusion:SfDiagram.Background>
So, I thought that only this background of the Diagram would be impacted by the image generation:
protected async Task<IRandomAccessStream> GenerateImage(UIElement diagram)
{
var renderTargetBitmap = new RenderTargetBitmap();
DiagramCollection<NodeViewModel> nodes = (diagram as SfDiagram).Nodes as DiagramCollection<NodeViewModel>;
if (nodes != null && nodes.Count > 0)
{
foreach (var node in nodes)
{
node.IsSelected = false;
}
}
await renderTargetBitmap.RenderAsync(diagram);
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
var pixelBytes = new byte[pixelBuffer.Length];
using (var reader = DataReader.FromBuffer(pixelBuffer))
{
reader.ReadBytes(pixelBytes);
}
IRandomAccessStream stream = new InMemoryRandomAccessStream();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegXREncoderId, stream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Straight,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
pixelBytes);
await encoder.FlushAsync();
return stream;
}
But this doesn't work as expected, as you can see on the following screenshots. For each case ;
- the first screenshot is the view with the SfDiagram editor
- the second screenshot is the export's result view, where the result image is compared to the original image

- first case:
Editor
Result

- the second case is more clear, as I'v added a shape "under" the image:
Editor
Export result

So is there a way to force the Export to take into account only the Background image of the SfDiagram?
If the user wasn't longer allowed to add shapes out of the image, this wouldn't be a problem for me.
This would allowing me to keeping the original ratio and to display the images correctly in my app...

I've attached you the last sources of my sample.

Regards,








Attachment: 127065__Stencil__Req1_7fca4beb.7z


PD Pierre-Christophe DUS February 10, 2017 02:40 PM UTC

Hello, it's me again!
I finally found a solution that works more or less, but which mustn't be the cleaner way to do it.
I've added some code in GenerateImage() method, which resize the diagram Height and Width based on the Image properties:
protected async Task<IRandomAccessStream> GenerateImage()
{
var renderTargetBitmap = new RenderTargetBitmap();
DiagramCollection<NodeViewModel> nodes = (diagram as SfDiagram).Nodes as DiagramCollection<NodeViewModel>;
if (nodes != null && nodes.Count > 0)
{
foreach (var node in nodes)
{
node.IsSelected = false;
}
}

// debug
int newDiagWidth = 0;
int newDiagHeight = 0;
var imgWidth = (double)((BitmapSource)((ImageBrush)(diagram).Background).ImageSource).PixelWidth;
var imgHeight = (double)((BitmapSource)((ImageBrush)(diagram).Background).ImageSource).PixelHeight;
var widthRatio = imgWidth / this.diagram.ActualWidth;
var heightRatio = imgHeight / this.diagram.ActualHeight;
if (widthRatio > heightRatio)
{
newDiagWidth = (int)this.diagram.ActualWidth;
newDiagHeight = (int)((this.diagram.ActualWidth / imgWidth) * imgHeight);
}
else
{
newDiagWidth = (int)((this.diagram.ActualHeight / imgHeight) * imgWidth);
newDiagHeight = (int)(this.diagram.ActualHeight);
}
diagram.Width = newDiagWidth;
diagram.Height = newDiagHeight;
diagram.ScrollViewerRenderMode = ScrollViewerRenderMode.Hidden;
// end debug

await renderTargetBitmap.RenderAsync(diagram);
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
var pixelBytes = new byte[pixelBuffer.Length];
using (var reader = DataReader.FromBuffer(pixelBuffer))
{
reader.ReadBytes(pixelBytes);
}

IRandomAccessStream stream = new InMemoryRandomAccessStream();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegXREncoderId, stream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Straight,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
DisplayInformation.GetForCurrentView().LogicalDpi,
DisplayInformation.GetForCurrentView().LogicalDpi,
pixelBytes);

await encoder.FlushAsync();
return stream;
}
As I explain you, it works in some cases:
After
After - Export

But if there are some shapes out of the Image, the horizontal and vertical scrollbars are visibles and exported:
After - scrollbars
After - scrollbars - export

Is there a way to hide them?
In the WPF doc (WPF - Diagram View), there are references to "HorizontalScrollbarVisibility" and "VerticalalScrollbarVisibility", but I didn't found how to use them on UWP...

Regards,



KR Keerthivasan Ramamoorthy Syncfusion Team February 11, 2017 12:32 PM UTC

Hi Pierre, 
Please find the responses to your query as below. 
S.no 
Query 
Response 
1 
is there a way to hide them?
In the WPF doc (
WPF - Diagram View), there are references to "HorizontalScrollbarVisibility" and "VerticalalScrollbarVisibility", but I didn't found how to use them on UWP... 
Requirement: Need to hide the ScrollBar(horizontal/Vertical). 
 
To achieve your requirement, please follow the below suggestion. 
 
Suggestion 1: 
In the sample, please set the scrolllimit which is in the ScrollSettings as Diagram. It helps to achieve your requirement. We have provided a code example to represent this. Please refer the code example as below. 
Code example: 
diagram.ScrollSettings.ScrollLimit = ScrollLimit.Diagram; 
 
here diagram is instance of SfDiagram 
 
Suggestion 2: 
In the sample, please set the ScrollViewerRenderMode of the Diagram as Hidden. It helps to achieve your requirement. We have provided a code example to represent this. Please refer the code example as below 
diagram.ScrollViewerRenderMode = ScrollViewerRenderMode.Hidden; 
 
here diagram is instance of SfDiagram 
 
Note: 
If the provided information not meet your requirement. Please provide sample to achieve your requirement at the earliest.  
2 
Is it possible to optimize the opening of the page? 
Currently, we are checking the optimize way of opening the diagram in Tablet. We will get back to you once we found the solution. 
 
Regards, 
Keerthivasan R. 
 



CG Chris g replied to Keerthivasan Ramamoorthy April 5, 2018 06:25 AM UTC

Hi Pierre, 
Requirement:” Need to set Selected Color directly to the Dragging Nodes from Stencil” 
We have analyzed and provided a solution to achieve your requirement. Please use DragEnter Event instead of using ItemAdded Event. We have provided a code example and Video to represent your requirement. Please refer the code example and video link as below. 
 
Code Example: 
//DragEnterEvent 
(diagram.Info as IGraphInfo).DragEnter += MainPage_DragEnter; 
 
private void MainPage_DragEnter(object sender, ItemDropEventArgs args) 
{ 
  if (args.ItemSource == Cause.Stencil) 
   { 
     var dropedItem = args.Source as Node; 
 
     if (dropedItem != null) 
     { 
       dropedItem.ShapeStyle = GetCustomStyle(); 
     } 
   } 
} 
 
Here, diagram is instance of SfDiagram. 
 
 
 
Regards, 
Keerthivasan R. 
 


.


KR Karkuvel Rajan Shanmugavel Syncfusion Team April 6, 2018 04:29 AM UTC

Hi Chris, 
 
please let us know whether you need any assistance.  
 
Regards, 
Karkuvel Rajan.S 


Loader.
Live Chat Icon For mobile
Up arrow icon