SSShooter / mind-elixir-core

⚗ Mind Elixir is a JavaScript, framework-agnostic mind map core.
https://docs.mind-elixir.com/
MIT License
1.98k stars 294 forks source link

How to init new mind map along with previous? #30

Closed Nehasoni988 closed 3 years ago

Nehasoni988 commented 3 years ago

I have initialized one mind map by following the code of the repo, now I want to initialize another mind map bu it throws the error- "Cannot read property 'className' of null at me.init".

My source code is-

// vue file

<v-btn color="primary" @click="initializeSecond()">Add one more mind map</v-btn>
 <v-row no-gutters>
        <v-col sm="6">
          <div id="map-1" style="width: 100%; height: 500px"></div>
        </v-col>
        <v-col sm="6">
          <div id="map-2" style="width: 100%; height: 500px"></div>
        </v-col>
 </v-row>

// Js code

import MindElixir, { E } from "mind-elixir";

data() {
    return {
    ME: null,
    ME_1: null   
 }
},

mounted() {
  let options = {
    el: '#map-1',
    direction: MindElixir.LEFT,
    // the data return from `.getAllData()`
    data: dummyData,
    draggable: true, // default true
    contextMenu: true, // default true
    toolBar: true, // default true
    nodeMenu: true, // default true
    keypress: true, // default true
    locale: 'en', // [zh_CN,zh_TW,en,ja] waiting for PRs
    overflowHidden: false, // default false
    primaryLinkStyle: 2, // [1,2] default 1
    primaryNodeVerticalGap: 15, // default 25
    primaryNodeHorizontalGap: 15, // default 65
    contextMenuOption: {
      focus: true,
      link: true,
      extend: [
        {
          name: 'Node edit',
          onclick: () => {
            alert('extend menu')
          },
        },
      ],
    },
    allowUndo: false
  }

  this.ME = new MindElixir(options);
  this.ME.init();
},

methods: {
    async initializeSecond() {
      try {
      let option = {
        el: '#map-2',
        direction: MindElixir.LEFT,
        // the data return from `.getAllData()`
        data: dummyData,
        draggable: true, // default true
        contextMenu: true, // default true
        toolBar: true, // default true
        nodeMenu: true, // default true
        keypress: true, // default true
        locale: 'en', // [zh_CN,zh_TW,en,ja] waiting for PRs
        overflowHidden: false, // default false
        primaryLinkStyle: 2, // [1,2] default 1
        primaryNodeVerticalGap: 15, // default 25
        primaryNodeHorizontalGap: 15, // default 65
        contextMenuOption: {
          focus: true,
          link: true,
          extend: [
            {
              name: 'Node edit',
              onclick: () => {
                alert('extend menu')
              },
            },
          ],
        },
        allowUndo: false
      }
      this.ME_1 = await new MindElixir(option);
      this.ME_1.init();
      } catch (error) {
        console.error('______', error)
      }
    }
}

// Error

Screenshot from 2021-01-18 12-00-32

Could you please help? @ssshooter

SSShooter commented 3 years ago

Which version do you use?

Nehasoni988 commented 3 years ago

Which version do you use?

"mind-elixir": "^0.13.3",

SSShooter commented 3 years ago

I try to render two maps with vue and it seems working.

https://codesandbox.io/s/mind-elixir-vue-forked-jl5v6?file=/src/App.vue

Could you reproduce the problem in codesandbox.io?

Nehasoni988 commented 3 years ago

I have copy-pasted your code and it is working, I didn't found any difference, now this error has resolved. But, I run your code of sandbox, when I am changing the color of the ME2 map, it is changing the color of the ME map, could you please look into it?

SSShooter commented 3 years ago

what does "change the color" mean?

Nehasoni988 commented 3 years ago

I have recorded the behavior, please have a look. I am changing the background color and font color of the second map but the first map's colors are changing.

https://www.awesomescreenshot.com/video/2416575?key=8cc66692123760e54b91c4f090ceca5e

SSShooter commented 3 years ago

ok, it's a bug 😂

Nehasoni988 commented 3 years ago

ok, it's a bug

:-D

Okay, please update me after fixing this, I have an urgent deadline. Thanks!

SSShooter commented 3 years ago

Fixed it, please update to 0.13.4 :-D

Nehasoni988 commented 3 years ago

Fixed it, please update to 0.13.4 :-D

Hey, I have upgraded the version, it is throwing another error. Please have a look

https://codesandbox.io/s/xenodochial-mclaren-xmh51?file=/src/App.vue

@ssshooter

SSShooter commented 3 years ago

0.13.5 fixed 😂

Nehasoni988 commented 3 years ago

😅 Thanks a bunch! Everything is working now. Giving star ⭐

SSShooter commented 3 years ago

Reproduction Needed 😥

Nehasoni988 commented 3 years ago

Reproduction Needed

Sorry, but I can't reproduce the problem because I have a lot more code also I am using vuex router and all kinds of stuff, let me elaborate on the problem in another manner.

I have seen in the repository's example data that the nodeData object is not having any parent property. Now, what my workflow is-

  1. I have a button on which click I generate a new map data using MindElixir.new("Root Node").
  2. I have a save button on which click I get the data of just created map using map.getAllData() and save this data in my database and on component's mounted hook I retrieve the data from the database (which I just stored) and pass it to the map initialization property like this-
    1. let options = {data: database_retrieved_data};
    2. let var_name = new MindElixir(options);
    3. var_name.init(); Everything is working fine till here.

Now when I add some child nodes to any map and click on the save button (which will take the data using the map.getAllData()) and send this data to Database for saving purpose, and also store this data into my state. It is throwing an error-

Screenshot from 2021-01-20 11-14-59

Also, after adding child nodes to some existing map, when I click on the button "create_map" it is also throwing the same problem.

I don't understand but I have seen that whenever I retrieve the data from DB, I found that nodeData object has parent property which has the value undefined, I have tried to remove the parent property from nodeData (as error is saying about parent property) but the property is not removing at all.

Please, Let me know if any further explanation needed. Thanks!

@ssshooter

SSShooter commented 3 years ago

I consider the problem occurs because of the getAllData function.

let getAllData = function () {
  let data = {
    nodeData: this.nodeData,
    linkData: this.linkData,
  }
  return JSON.parse(
    JSON.stringify(data, (k, v) => {
      if (k === 'parent') return undefined
      if (k === 'from') return v.nodeObj.id
      if (k === 'to') return v.nodeObj.id
      return v
    })
  )
}

Check if your data contain any object that JSON.stringify can't process.

Nehasoni988 commented 3 years ago

the getAllData function is returning the data like this-

Screenshot from 2021-01-20 11-39-24

which has no parent property, and the same data I am storing in the DB. but on mounted when I retrieve this same data from DB and passing it to the initialization object, somehow it is adding the parent property to the nodeData, like that-

Screenshot from 2021-01-20 11-41-19

I can understand it's hard to debug without looking into the code, If it's still unclear to you, let me know, I will upload the sample project on git you can clone and test this.

SSShooter commented 3 years ago

So the getAllData function is not the one throwing error? 😂

Nehasoni988 commented 3 years ago

Hey, I found when this error occurs, just follow these steps-

  1. Copy example data from here https://github.com/ssshooter/mind-elixir-core/blob/develop/src/exampleData/1.js, store this data in the Vue state.
  2. Now in component, take the data from state and pass in configurations' data key, check if the mind map has generated for this data.
  3. If generated then remove some nodes and after removing add some nodes again then reload the page, the error will come.
Nehasoni988 commented 3 years ago

See this video,

https://www.awesomescreenshot.com/video/2444909?key=47f1d9de50c40894d84aef2181f1d62e

When I click on the green button, I export the data by calling the getAllData function like map.getAllData. map is the variable which I used to store when init the map and its auto update when I call export data.

It seems that there is a problem with getAllData function, because its structure is like-

parent: {
    children: [
        parent: {
            children: [
            ]    
      }
]

@ssshooter

SSShooter commented 3 years ago
parent: {
    children: [
        parent: {
            children: [
            ]    
      }
]

this structure should not cause error.

JSON.stringify(data, (k, v) => {
      if (k === 'parent') return undefined
      if (k === 'from') return v.nodeObj.id
      if (k === 'to') return v.nodeObj.id
      return v
    })

this part of code had skipped the stringify of parent propertys.

Nehasoni988 commented 3 years ago

Do you have any idea what I am doing wrong or why I am getting this kind of data structure? I do need to save the modified data to the database, instead of getAllData what else I can use to export data?

@ssshooter

SSShooter commented 3 years ago

I think you can directly access meObject.nodeData and do whatever you want to

Nehasoni988 commented 3 years ago

I think you can directly access meObject.nodeData and do whatever you want to

Hey, I did this, it Is producing the same error. Just check this please - https://codesandbox.io/s/mind-elixir-vue-forked-xxm79?file=/src/App.vue

and add any child node, and click on the export data button, you should see something like that- children->parent->children->...

Screenshot from 2021-01-21 10-19-28

@ssshooter

SSShooter commented 3 years ago

image

https://codesandbox.io/s/mind-elixir-vue-forked-7bphn

nodeData has parent property if you directly access it, but it doesn't means getAllData will throw an error.

Nehasoni988 commented 3 years ago

No, getAllData is not throwing the error, but it seems that after calling getAllData on ME object, it is assigning something to ME's nodedata that's why the me's nodedata is having a circular json structure, please look at this-

https://codesandbox.io/s/mind-elixir-vue-forked-oxjr2?file=/src/App.vue

(See the last console message nodeData property.)

(It's my row thought, pardon for saying wrong) when ME's nodeData get updates after calling getAllData, ME object updates with circular structure and ME object is in a variable so this variable is not having a correct value and we can't pass this data for mind map initialization.

@ssshooter

SSShooter commented 3 years ago

As below source code shows, getAllData doesn't assign anything to nodedata 😂

let getAllData = function () {
  let data = {
    nodeData: this.nodeData,
    linkData: this.linkData,
  }
  return JSON.parse(
    JSON.stringify(data, (k, v) => {
      if (k === 'parent') return undefined
      if (k === 'from') return v.nodeObj.id
      if (k === 'to') return v.nodeObj.id
      return v
    })
  )
}
Nehasoni988 commented 3 years ago

There is no way to export the data of a map and store it somewhere.

😓

SSShooter commented 3 years ago

How about trying to clone the nodeData manually?

Nehasoni988 commented 3 years ago

Yes, I need to handle it manually.

Nehasoni988 commented 3 years ago

Hey, could you please tell me where is the init function? I searched in the DOC but didn't found it.

Actually, I noticed that whenever change the direction either initLeft or initRight or initSide, map calls init() again, so the saved color also change back to default blue color again.

I want to debug this.

@ssshooter

SSShooter commented 3 years ago

https://github.com/ssshooter/mind-elixir-core/blob/8595747d73c3553b1f49377cd695f5c4f427dba9/src/index.js#L323

Nehasoni988 commented 3 years ago

is there any way to listen when initLeft or initRight functions are being called?

@ssshooter

SSShooter commented 3 years ago

no way for now, but you can write your own initRight base on below code.

initRight = function () {
  this.direction = 1
  this.init()
  // do something else
}
Nehasoni988 commented 3 years ago

Okay

Nehasoni988 commented 3 years ago

Hey,

Don't tell me it does not support RTL 😟 😟 😟 @ssshooter

SSShooter commented 3 years ago

😂 try to cover the original css with custom css

Nehasoni988 commented 3 years ago

Yeah, this will burn my head :`(

Nehasoni988 commented 3 years ago

Hey @ssshooter

  1. Change the color of the root node.
  2. Change the position of the mind map, either left or right.
  3. The color of the root node has been reset.

see this - https://www.awesomescreenshot.com/video/2527408?key=e0996b3600ac69156f0217ccd379d632

I have fixed it by adding the below lines in init function-

 let rootNodeColor = null;
    if(this.nodeData.style) {
      rootNodeColor = this.nodeData.style.background;
    }
    if(rootNodeColor) {
      $d.querySelector("root tpc").style.background = rootNodeColor;
    }

Result- https://www.awesomescreenshot.com/video/2527560?key=a900e682ed71581d67785a5470cd07c5 please review. is it okay to handle this in that manner?

SSShooter commented 3 years ago

I had uploaded the dev branch and you can take it as referance.

Nehasoni988 commented 3 years ago

Hey,

The toolbar options and node menu is hiding in full-screen mode only mind map is visible, can you please tell me how to fix this?

@ssshooter

SSShooter commented 3 years ago

https://github.com/ssshooter/mind-elixir-core/blob/9cc25786cfce23db22f49a2a198b12f551632f4f/src/plugin/toolBar.js#L25

Change this line to mind.container.parentElement.requestFullscreen()

Nehasoni988 commented 3 years ago

Yeah, I tried the same logic, a bit different-

fc.onclick = () => {
    // when full screen mode is on, change the bg color;
    mind.mindElixirBox.style.background = "#fff";

    // Make element in full screen mode
    mind.mindElixirBox.requestFullscreen()
  }

Thanks for letting me know. :-D

Nehasoni988 commented 3 years ago

Hey,

The calculation in linkdiv.js is having too large code 😅, how can I customize the CSS for RTL support? Can you please suggest?

@ssshooter

SSShooter commented 3 years ago

I'am not familiar with direction property, directly adding direction:rtl to tpc element may work ? 😂

Nehasoni988 commented 3 years ago

No, it's not working. :`(

I want to customize the package language and I have the locale "heb" (Hebrew) which is RTL. So when my APP is in RTL mode the map's nodes disappear.

Can you have a look at it, when I change the direction of the map-container (Which is exactly when my APP is in RTL mode), what happened to it?

https://codesandbox.io/s/mind-elixir-vue-forked-csebo?file=/src/App.vue

SSShooter commented 3 years ago

it's weird that nodes disappear 😂 have you inspected the element? nodes don't render correctly or there's a error thorwn?

Nehasoni988 commented 3 years ago

I meant, As much as I have observed, the linkDiv.js is having the calculation of nodes always from a fixed direction, either left or right, and also, the package has not any locale which supports RTL, and that's why when I turned my application in RTL mode, the nodes become miscalculated and scattered at many places in the screen.

The above is my concern :`(

SSShooter commented 3 years ago

Could you provide a RTL environment for me to debug this issue?

Nehasoni988 commented 3 years ago

Yeah sure, please follow this link-

https://codesandbox.io/s/mind-elixir-vue-forked-csebo?file=/src/App.vue

I have given the RTL direction to the .map-container which behaves exactly the same behavior when my Application is in RTL mode. Any help from you would great.

SSShooter commented 3 years ago
.map-container {
  direction: ltr;
  tpc {
    direction: rtl;
  }
}

Take a try