Diagram state is not updated after changing node text color

Hi,
I am using native type node, rendering svg inside it. I'm trying to change its text color dynamically then saving the diagram. but on again loading the diagram its changed state is not maintained. 
I have created a sample code for my requirement.
There are 4 buttons in sample app.
Change Text: It changes the text of node as i want.
Save Diagram; You can save changes made to diagram
Clear Content: its for removing current changes
Load Diagram: With this button you can load previous changes.

If you press all buttons in same sequence. You will see that its changing the text color. but on loading the previous changes text state is not maintained. 
http://jsplayground.syncfusion.com/1mea5s1m

I've also added this issue in incident below:
https://www.syncfusion.com/support/directtrac/incidents/194791

9 Replies

KU Kutraleeswaran Syncfusion Team February 12, 2018 07:26 AM UTC

Hi Ahman, 
 
You have been changing the text property dynamically  by accessing DOM elements. Hence the changes will not be retained while saving the diagram. 
 
You can achieve this by template binding using addInfo property in Nodes.    
 
Nodes addInfo property is used to maintain additional information of the nodes. 
 
You have to specify addInfo property with an attribute in an specific attribute of the element.  
 
Code Example: 
<text fill={{:addInfo.fill}} transform="matrix(1 0 0 1 136.6821 49.2686)" font-family="'GothamBold'" font-size="38">APPLY NOW</text> 
 
It can be binded by setting the addInfo property in specific node in collection of nodes. 
 
Code Example: 
var nodes = [ 
          { name: "Native", addInfo:{ fill: "black" }, scale:"stretch",width: 200, height: 150, offsetX: 300, offsetY: 200, fillColor: "black", borderColor: "black", type: ej.datavisualization.Diagram.Shapes.Native, templateId: "svgTemplate" }, 
        ] 
 
If you need to change the appearance of the node dynamically at run time, just need to find that node using client side method findNode and change the node's custom properties. Then you can use updateNode method to refresh the template. 
 
Code Example: 
  $("#TextChange").click(function(){ 
          var diagram = $("#diagram").ejDiagram("instance"); 
          var node = diagram.findNode("Native"); 
          node.addInfo.fill = "red"; 
          diagram.updateNode("Native", { templateId: "svgTemplate"  }); 
       }); 
And also we have provided sample for your requirement in below. 
 
Regards, 
S Kutraleeswaran 
 



AH ahman February 12, 2018 02:07 PM UTC

Thank you, its really helpful. But there is a small challenge, in a node there can be many texts, or other tags. I only want to change the property of that target element. How  can we differentiate it? or only change the property of clicked element, not others too.
I aslso want to change the font size of the elment, i tried to add addInfo property but i am unable to change the font family or font size of the element.


SG Shyam G Syncfusion Team February 13, 2018 05:04 AM UTC

Hi Ahman, 
 
  • Please use diagram client side click event and it triggers when you click on the diagram elements.
  • In this event, you can update the text fontSize and fontFamily. We have added fontSize, fontFamily in node’s addInfo property and binded it in script template.
  • If you need to change the appearance of the node dynamically at run time, change custom properties and call diagram updateNode  method to update at runtime. Please refer to the code example below
 
Code example: 
 
<script id="svgTemplate" type="text/x-jsrender">    
<text fill={{:addInfo.fill}} transform="matrix(1 0 0 1 136.6821 49.2686)" font-family={{:addInfo.fontfamily}} font-size={{:addInfo.fontsize}}>Text with Dom</text> 
 </script> 
 
  $("#diagram").ejDiagram({ 
                //define click event 
                click: diagramclick, 
            }); 
 
    function diagramclick(args) {              
            var diagram = $("#diagram").ejDiagram("instance"); 
            if (args.element) { 
                var node = args.element; 
                    if (node.addInfo) { 
                        //set custom properties 
                        node.addInfo.fill = "red"; 
                        node.addInfo.fontsize = "30"; 
                        //update node template at runtime 
                        diagram.updateNode(node.name, { templateId: "svgTemplate" }); 
                    } 
                } 
            } 
        } 
 
  • Also we have an option to set an multiple label for an node by defining label object and it can be customized with label properties. Please refer to the code example below in which we have rendered the native node with multiple labels and updated label properties at runtime using updateLabel method.
 
Code example: 
 
    <script id="svgTemplate1" type="text/x-jsrender"> 
<g> 
        <path d="M520.304,294.965H-0.305V0h520.609V294.965z M8.695,285.965h502.609V9H8.695V285.965z" /> 
</g> 
    </script> 
 
var nodes = [ 
  
              { name: "Native1", labels: [{ text: "Diagram Label", offset: { x: 0.5, y: 0.2 }, fontSize: 20, fontFamily: "Arial" }, { text: "Text with Diagram label", offset: { x: 0.5, y: 0.7 }, fontSize: 17, fontFamily: "Arial" }], scale: "stretch", width: 200, height: 150, offsetX: 500, offsetY: 200, fillColor: "black", borderColor: "black", type: ej.datavisualization.Diagram.Shapes.Native, templateId: "svgTemplate1" }, 
            ] 
 
            $("#diagram").ejDiagram({ 
                nodes: nodes, 
                //define click event 
                click: diagramclick, 
            }); 
 
  function diagramclick(args) {              
            var diagram = $("#diagram").ejDiagram("instance"); 
            if (args.element) { 
                var node = args.element; 
                if (node.labels.length > 0) { 
                    for (var i = 0; i < node.labels.length; i++) { 
                        var label = node.labels[i]; 
                        //update label at runtime 
                        diagram.updateLabel(node.name, label, { fontSize: 20, fontColor: "red" }); 
                    } 
                } 
             } 
           } 
         } 
 
Here is the playground link for further reference 
 
 
Please refer to the below help documentation which shows how to define click event and add multiple labels for an diagram element 
 
  
Regards, 
Shyam G 



AH ahman February 13, 2018 03:46 PM UTC

Thanks, it is helpful, there is another scenario. lets suppose, i have 2 nodes:
Node 1 has text 1, text 2, text 3, text 4 and so on...
Node 2 has text 1, text 2, text 3, text 4 and so on...
If i want only change style for text 2 of node 2 or text 2 of node 2 then it means i need to apply addInfo for each text differently? like AddInfo1, AddInfo2, AddInfo3, AddInfo4 and so on?
If yes, then if i have too many nodes, and each of them have too many elements. I have to create unique AddInfo for each of them?? 


KU Kutraleeswaran Syncfusion Team February 14, 2018 05:44 AM UTC

Hi Ahman. 
 
No need to create multipe addinfo for multiple texts in an single node  for an similar appearance. 
 
Code Example: 
 
Node Definition: 
{ name: "Native", addInfo:{ fill:"red" }, scale:"stretch",width: 200, height: 150, offsetX: 300, offsetY: 200, fillColor: "black", borderColor: "black", type: ej.datavisualization.Diagram.Shapes.Native, templateId: "svgTemplate" }, 
 
Element Definition: 
<text fill={{:addInfo.fill}} transform="matrix(1 0 0 1 156.6821 149.2686)" font-family="'GothamBold'" font-size="38">New Apply</text> 
<text fill={{:addInfo.fill}} transform="matrix(1 0 0 1 136.6821 49.2686)" font-family="'GothamBold'" font-size="38">APPLY NOW</text> 
 
Sample Link: 
 
If you need apply different text style appearance  for each text in an multiple texts in an single node. 
You can differentiate those properties like addInfo.fontsize1 and addInfo.fontsize2 of text 1 and text 2 elements. 
 
Code Example: 
 
Node Definition: 
{ name: "Native", addInfo:{ fill: “red”, fontSize1:30, fontSize2:60 }, scale:"stretch",width: 200, height: 150, offsetX: 300, offsetY: 200, fillColor: "black", borderColor: "black", type: ej.datavisualization.Diagram.Shapes.Native, templateId: "svgTemplate" }, 
 
Element Definition: 
<text fill={{:addInfo.fill}} transform="matrix(1 0 0 1 156.6821 149.2686)" font-family="'GothamBold'" font-size={{:addInfo.fontSize1}}>New Apply</text> 
<text fill={{:addInfo.fill}} transform="matrix(1 0 0 1 136.6821 49.2686)" font-family="'GothamBold'" font-size={{:addInfo.fontSize2}}>APPLY NOW</text> 
 
Sample Link:  
 
If you have too many nodes and multiple text elements and it gonna be a similar appearance. You can use model’s defaultSettings.node property to achieve your requirement. 
 
CodeExample: 
 
Model Definition: 
defaultSettings: { node: { addInfo:{fill:"red"}} }, 
 
Element Definition: 
<text fill={{:addInfo.fill}} transform="matrix(1 0 0 1 156.6821 149.2686)" font-family="'GothamBold'" font-size="38">New Apply</text> 
<text fill={{:addInfo.fill}} transform="matrix(1 0 0 1 136.6821 49.2686)" font-family="'GothamBold'" font-size="38">APPLY NOW</text> 
 
Sample Link: 
 
Regards, 
S Kutraleeswaran 



AH ahman February 14, 2018 11:12 AM UTC

If you need apply different text style appearance  for each text in an multiple texts in an single node. 
You can differentiate those properties like addInfo.fontsize1 and addInfo.fontsize2 of text 1 and text 2 elements. 
 
Code Example: 
 
Node Definition: 
{ name: "Native", addInfo:{ fill: “red”, fontSize1:30, fontSize2:60 }, scale:"stretch",width: 200, height: 150, offsetX: 300, offsetY: 200, fillColor: "black", borderColor: "black", type: ej.datavisualization.Diagram.Shapes.Native, templateId: "svgTemplate" }, 
 
Element Definition: 
{{:addInfo.fill}} transform="matrix(1 0 0 1 156.6821 149.2686)" font-family="'GothamBold'" font-size={{:addInfo.fontSize1}}>New Apply 
{{:addInfo.fill}} transform="matrix(1 0 0 1 136.6821 49.2686)" font-family="'GothamBold'" font-size={{:addInfo.fontSize2}}>APPLY NOW 
 
Sample Link:  

Yes, I want something like above. But problem with above approach is that if i have 100s text elements, and want different style tag for each of them. then i need to declare addInfo.fontSize1, addInfo.fontSize2.... addInfo.fontSize1000.

it looks very complex and time taking to manage n number of text elements with n number of style attributes. do we have other choice?



SG Shyam G Syncfusion Team February 15, 2018 12:50 PM UTC

Hi Ahman, 

Solution 1: 

You can define the values as an array and bind it to SVG element directly. Please refer the below code snippet. 

var nodes = [          
          { name: "Native", addInfo: { fill:"red", fontSize:[60,30], startIndex: 0 }, …}, 

<text fill={{:addInfo.fill}} transform="matrix(1 0 0 1 156.6821 149.2686)" font-family="'GothamBold'" font-size={{:addInfo.fontSize[0]}}>New Apply</text> 
<text fill={{:addInfo.fill}} transform="matrix(1 0 0 1 136.6821 49.2686)" font-family="'GothamBold'" font-size={{:addInfo.fontSize[1]}}>APPLY NOW</text> 

Solution 2: 

You can define the values as an array and create the script template dynamically and bind the values. Please refer the below code snippet. 


var addInfo = { fill:"red", fontSize: [60, 30], matrix: ["matrix(1 0 0 1 156.6821 159.2686)", "matrix(1 0 0 1 136.6821 49.2686)"] }; 
 
var scriptTemplate = document.createElement("script"); 
scriptTemplate.setAttribute("type", "text/x-jsrender"); 
scriptTemplate.setAttribute("id", "svgTemplate"); 
 
var ss = "<svg class=\"test-Diagram\" version=\"1.1\" id=\"Layer_1\" xmlns=\"https://www.w3.org/2000/svg\" xmlns:xlink=\"https://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" " + 
"width=\"520.915px\" height=\"294.965px\" viewBox=\"-0.305 0 520.915 294.965\" enable-background=\"new -0.305 0 520.915 294.965\"" + 
"xml:space=\"preserve\">" + 
"<rect x=\"-0.305\" fill=\"white\" width=\"520.609\" height=\"294.965\"/><title>Apply Now</title>" + 
"<g><path d=\"M520.304,294.965H-0.305V0h520.609V294.965z M8.695,285.965h502.609V9H8.695V285.965z\"/></g>"; 
 
for (var i = 0; i < addInfo.fontSize.length; i++) { 
    ss += "<text fill=\"{{:addInfo.fill}}\" transform=\"{{:addInfo.matrix[" + i + "]}}\" font-family=\"GothamBold\" font-size=\"{{:addInfo.fontSize[" + i + "]}}\">New Apply</text>"; 
} 
ss += "</svg>"; 
scriptTemplate.innerHTML = ss; 
 
document.body.appendChild(scriptTemplate); 
 
var nodes = [          
        { name: "Native", addInfo: addInfo, …}, 
] 
 
Here is the playground link. 

 
Regards, 
Shyam G 



AH ahman February 20, 2018 11:46 AM UTC

Hi,
I got it. It looks like we need to add info in nodes at time of initialization and define addinfo properties in diagram at time of initializations.
But it looks too lengthy to define addinfo in each of the node one by one. I was thinking if we do not initialize any addinfo in nodes or in diagrams. when user drag any node from symbol palette to diagram at that time when node is clicked then we initialize or addinfo for that node only. not for all the nodes which are available in symbol palette collection. Is it possible?


KU Kutraleeswaran Syncfusion Team February 21, 2018 11:58 AM UTC

Hi Ahman, 
 
QUERIES 
RESPONSE 
But it looks too lengthy to define addinfo in each of the node one by one. I was thinking if we do not initialize any addinfo in nodes or in diagrams. 
Instead of initializing nodes addInfo property for each node,  you can  initialize addInfo property for nodes using model default settings node property , So that it applies for all the nodes in diagram. 
 
Code Sample: 
$("#diagram").ejDiagram({ 
            width: "700px", 
            height: "700px", 
            nodes: nodes, 
            itemClick: diagramClick, 
            defaultSettings: { node: { addInfo:{ fill:["black","black"], fontSize:[12,12] }} }, 
            pageSettings: { scrollLimit: "diagram" }, 
   }); 
 
Sample: 
<text fill={{:addInfo.fill[0]}} transform="matrix(1 0 0 1 156.6821 149.2686)" font-family="'GothamBold'" font-size={{:addInfo.fontSize[0]}}>New Apply</text>  
<text fill={{:addInfo.fill[1]}} transform="matrix(1 0 0 1 136.6821 49.2686)" font-family="'GothamBold'" font-size={{:addInfo.fontSize[1]}}>APPLY NOW</text>  
 
 
when user drag any node from symbol palette to diagram at that time when node is clicked then we initialize or addinfo for that node only. not for all the nodes which are available in symbol palette collection.  Is it possible? 
Yes. when node is clicked , you can use itemClick event  in which you can update node appearance by using updateNode method. 
 
Code Sample: 
$("#diagram").ejDiagram({ 
            width: "700px", 
            height: "700px", 
            nodes: nodes, 
            itemClick: diagramClick, 
            defaultSettings: { node: { addInfo:{ fill:["black","black"], fontSize:[12,12] }} }, 
            pageSettings: { scrollLimit: "diagram" }, 
     }); 
 
Method: 
function diagramClick(args){ 
          var diagram = $("#diagram").ejDiagram("instance");  
          if (args.element) {  
            var node = args.element;  
            if (node.addInfo) {  
                  //update node template at runtime  
              diagram.updateNode(node.name, { templateId: "svgTemplate", 
                    addInfo:{fill : ["red","orange"], fontSize:[40,40]}});  
                 }  
               }  
            } 
 
 
 
 
 
 
 
Regards, 
Kutraleeswaran Samuthirapandian  


Loader.
Up arrow icon