W jaki sposób zamienić then na click?

0

Cześć, mam pewną funkcjonalność, która aktualnie wykonuje się po .then, chciałbym, żeby wszystko to co dzieje się po .then wykonywało się po clicku na jakiegoś butona na stronie. W jaki sposób należałoby to przerobić?

Plotly.newPlot('plotly', data, layout, 
      { 
        responsive: true,
        displaylogo: false,
        locale: 'pl',
        modeBarButtonsToRemove: ['toImage']
      }).then(
        function(gd)
         {
          Plotly.toImage(gd)
             .then(
                 function(url)
             {
                 img_jpg.attr("src", url);
                 Plotly.downloadImage(gd);
             }
             )
        });
1

W ciele then dodajesz event listenera do tego buttona (i opcjonalnie w ogole go odpalasz bo wczesniej pewnie chcesz zeby byl disabled)

0
stivens napisał(a):

W ciele then dodajesz event listenera do tego buttona (i opcjonalnie w ogole go odpalasz bo wczesniej pewnie chcesz zeby byl disabled)

Jakby to miało wyglądać?

0

#pseudokod

then:
    document.getElementById('...').addEventListener('click', function(){...});
0
stivens napisał(a):

#pseudokod

then:
    document.getElementById('...').addEventListener('click', function(){...});
Plotly.newPlot('plotly', data, layout, 
      { 
        responsive: true,
        displaylogo: false,
        locale: 'pl',
        modeBarButtonsToRemove: ['toImage']
      }).then(
        document.getElementById("getChartImage")
        .addEventListener('click', 
        function(gd)
         {
          Plotly.toImage(gd)
             .then(
                 function(url)
             {
                  img_jpg.attr("src", url);
                 Plotly.downloadImage(gd);
             }
             )
        }));

Zrobiłem w ten sposób, tyle że mam wrażenie, że 'gd' nie pamięta nic, bo zapisuje mi się obrazek bez zadnych danych na wykresie.

0
stivens napisał(a):

#pseudokod

then:
    document.getElementById('...').addEventListener('click', function(){...});

function tutaj moze miec postac np function(e){...} gdzie e jest eventem wywolujacym funkcje. Nie przekazuj tak gd. Nie przekazuj w ogole, przeciez gd znajduje sie w scope'ie w momencie dodawania listenera

0

A poza tym to zle napisales ten then bo on przyjmuje funkcje a Ty masz tylko cialo

Edit: to tutaj powinno function(gd) z cialem jak wyzej (ale function event listenera bez parametru)

0
stivens napisał(a):

A poza tym to zle napisales ten then bo on przyjmuje funkcje a Ty masz tylko cialo

Edit: to tutaj powinno function(gd) z cialem jak wyzej (ale function event listenera bez parametru)

Nie bardzo wiem jak to zapisać. Chyba inaczej niż tutaj?

 Plotly.newPlot('plotly', data, layout, 
      { 
        responsive: true,
        displaylogo: false,
        locale: 'pl',
        modeBarButtonsToRemove: ['toImage']
      }).then(
        function(gd){
          document.getElementById("getChartImage")
        .addEventListener('click', 
        function()
         {
          Plotly.toImage(gd)
             .then(
                 function(url)
             {
                  img_jpg.attr("src", url);
                 Plotly.downloadImage(gd);
             }
             )
        })

        }
        );
2

Popracuj nad wcieciami bo sa fatalne

 Plotly.newPlot('plotly', data, layout, {
    responsive: true,
    displaylogo: false,
    locale: 'pl',
    modeBarButtonsToRemove: ['toImage']
 }).then(function(gd) {
    document.getElementById("getChartImage").addEventListener('click', function() {
        Plotly.toImage(gd)
        .then(function(url) {
            img_jpg.attr("src", url);
            Plotly.downloadImage(gd);
        });
    });
});

brakowalo dwoch srednikow. No chyba ze dalej nie dziala

0

Wracam jeszcze do tego pytania :) Owszem, ostatnia wersja kodu pomogła i działa. Jednak wprowadziłem teraz pewną funkcjonalność, która pozwala na odświeżenie wykresu rysowanego przez Plotly. czyli po prostu objąłem tą powyższą funkcją dodatkowo refresh(), które wywołuję sobie na klik w przycisk.
Dochodzi teraz do sytuacji, że wykresy generują się tyle razy, ile razy ktoś zrefreshuje wykres. Pewnie chodzi o addEventListener - w jaki sposób możnaby przerobić funkcję tak, aby nie było takiej sytuacji, a wykres zawsze generował się pojedynczo.

1

Ogólnie promisy i eventy słabo współpracują, bo promise jest rozwiązywany raz, a event wielokrotnie (m.in. dlatego istnieją takie rzeczy jak RX i channele), ale w tym przypadku da się to w miarę elegancko zrobić, bez uciekania się do globali itp (choć mamy niestety coupling, ale bez wspomnianych wcześniej rozwiązań nie bardzo wiem czy da się tego uniknąć), przykład:

<button id="example">Example</button>
<button id="redraw">redraw</button>
const draw = (() => {
  // Create a scoped variable inside a closure,
  // so we can change it, without re-registering event:
  let _value

  // Register event inside a closure (just an example code):
  document
    .getElementById("example")
    .addEventListener('click', event => {
      console.log("Handling event...")
      event.target.innerText = `${_value} | ${Math.random()}`
    })

  // Return an actual function that have acces to the lexical closure
  return () => {
    Promise.resolve(Math.random()) // Your promise goes here, instead of this fake
      .then(value => {
        // ... do some stuff
      
        // Assign dynamic value to the ecnclosed equivalent:
        _value = value
      })
  }
})() // Immidiatelly execute enclosing function to get the inner one

// First render:
draw()
// Register a redraw on click:
document.getElementById("redraw").addEventListener("click", draw)

CodePen: https://codepen.io/caderek/pen/vYYObNa?editors=1010

Alternatywnie z użyciem klasy (trochę dłuższe):

class MyClass {
  constructor() {
    this._value = null
    
    document
      .getElementById("example")
      .addEventListener('click', event => {
        console.log("Handling event...")
        event.target.innerText = `${this._value} | ${Math.random()}`
      })
    
    this.draw = this.draw.bind(this)
  }
  
  draw() {
    Promise.resolve(Math.random())
      .then(value => {
        // ...do some stuff
        this._value = value
      })
  }
}

const myObject = new MyClass()

myObject.draw()
document.getElementById("redraw").addEventListener("click", myObject.draw)

CodePen: https://codepen.io/caderek/pen/VwwLqaP?editors=1010

W twoim przypadku to będzie coś w stylu:

const draw = (() => {
  let _gd

  document.getElementById("getChartImage").addEventListener("click", () => {
    if (_gd) {
      Plotly.toImage(_gd).then(url => {
        img_jpg.attr("src", url)
        Plotly.downloadImage(gd)
      })
    }
  })

  return () => {
    Plotly.newPlot("plotly", data, layout, {
      responsive: true,
      displaylogo: false,
      locale: "pl",
      modeBarButtonsToRemove: ["toImage"]
    }).then(gd => {
      _gd = gd
    })
  }
})()

draw()
document.getElementById("redraw").addEventListener("click", draw)
0

Niestety, ale działa to w dokładnie ten sam sposób co prędzej.

0

Aktualna postać funkcji jest taka:

const draw = (() => {
          let _gd
        
          document.getElementById("getChartImage").addEventListener("click", () => {
            if (_gd) {
              Plotly.toImage(_gd).then(
                Plotly.downloadImage(_gd)
              )
            }
          })
        
          return () => {
            Plotly.newPlot("plotly", traces, layout, {
              responsive: true,
              displaylogo: false,
              locale: "pl",
              modeBarButtonsToRemove: ["toImage"]
            }).then(gd => {
              _gd = gd
            }, {once: true})
          }
        })()        
        draw()

Co by tu można jeszcze zmodyfikować, tak aby addEventListenery się nie dublowały i zawsze pobierany był jeden obraz?

0

Ten kawałek kodu sam w sobie nie powoduje dublowania listenerów, problem musi leżeć gdzie indziej (chyba, że Ploty wewnętrznie jakieś listenery tworzy)

1 użytkowników online, w tym zalogowanych: 0, gości: 1