2013-03-20 11 views
12

Mam wygenerowany diagram rozkładu sił d3, muszę wyeksportować go do png z bieżącym (wybranym przez użytkownika) skalowaniem nienaruszonym.Pokaż pełne SVG ze skalowaniem nienaruszonym

Według mojego rozumowania to wtedy rośnie szerokość SVG i wysokość, więc jeśli svg jest 1920x1080 i jest „powiększony” w, eksportowany svg prawdopodobnie powinien mieć znacznie większą szerokość i wysokość, aby pomieścić to.

Próbowałem wszystkiego, a czegoś mi brakuje, po prostu nie mogę dynamicznie obliczyć prawidłowych wartości dla wymaganego wyjścia.

Oto example mojego eksportowane SVG, trzeba pamiętać, że istnieje wiele więcej informacji, to po prostu nie jest widoczny na tej skali.

EDIT

Tu jest mój podstawowy kod eksportującego, głównie adaptacją highcharts:

serializeSvg: function() { 
     /** 
     * serialize a xml object to string 
     * @param {type} xmlNode the node to use 
     * @returns {String|@exp;[email protected];xml|@exp;[email protected];[email protected];@call;serializeToString} 
     */ 
     function serializeXmlNode(xmlNode) { 
      if (typeof window.XMLSerializer !== 'undefined') { 
       return (new window.XMLSerializer()).serializeToString(xmlNode); 
      } else if (typeof xmlNode.xml !== 'undefined') { 
       return xmlNode.xml; 
      } 

      return ''; 
     } 

     var svg = serializeXmlNode(document.getElementsByTagName('svg')[0]), 
      factor = 2; 
     svg = '<svg' 
       + ' xmlns="http://www.w3.org/2000/svg"' // xml namespace 
       + ' version="1.1"' 
       + ' xmlns:xlink="http://www.w3.org/1999/xlink"' // for images 
       + ' ' + svg.substring(svg.indexOf('<svg ') + 5); 

     // highcharts svg sanitizer 
     svg = svg.replace(/width="([^"]+)"/, function(m, width) { 
       return 'width="' + (width * factor) + '"'; 
      }).replace(/height="([^"]+)"/, function(m, height) { 
       return 'height="' + (height * factor) + '"'; 
      }).replace(/<rect class="drag"[^<]+<\/rect>/, '') 

      // IE specific 
      .replace(/<IMG /g, '<image ') 
      .replace(/height=([^" ]+)/g, 'height="$1"') 
      .replace(/width=([^" ]+)/g, 'width="$1"') 
      .replace(/id=([^" >]+)/g, 'id="$1"') 
      .replace(/class=([^" ]+)/g, 'class="$1"') 
      .replace(/ transform /g, ' ') 
      .replace(/:(path|rect)/g, '$1') 
      .replace(/style="([^"]+)"/g, function(s) { 
        return s.toLowerCase(); 
      }); 

     return svg; 
    } 

a głównym zoom/skalowanie startowy dla układu D3:

var layout = d3.layout.force(); 
var DEFAULT_SIZE = 64; 
var GROWTH_SCALE = 1.15; 
var SHRINK_SCALE = 1.05; 

// creates a new force layout 
var force = layout 
    .size([w, h]) 
    .gravity(.06) 
    .distance(110) 
    //.friction(0.6) 
    //.linkStrength(0.4) 
    .charge(-((DEFAULT_SIZE * GROWTH_SCALE) * 10)) 
    .on('tick', tick); 

// creates the svg context 
var svg = d3.select('.la-container').append('svg:svg') 
    .attr('width', w) 
    .attr('height', h) 
    .attr('pointer-events', 'all') // set for the pan/zooming 
    .append('svg:g') // add a g element for capturing zoom and pan 
     .call(d3.behavior.zoom().scaleExtent([0.6, 6.0]).on('zoom', redraw)) 
    .append('svg:g'); 

svg.append('svg:rect') 
    .attr('class', 'drag') 
    .attr('width', w) 
    .attr('height', h) 
    .attr('fill', 'white'); 
+0

Czy używasz zachowania powiększenia w d3, aby skalować obraz? Powinieneś być w stanie użyć zoom.scale(), aby uchwycić poziom zoomu i odpowiednio przekształcić wyjściowy SVG. Więcej informacji (i kod javascript) byłoby pomocne w dokładnym ustaleniu, co próbujesz zrobić? – RoryB

+0

Tak, używam 'd3.behavior.zoom()' i 'd3.behavior.drag()', załóżmy, że użytkownik jest powiększony na węźle grafu zawierającym 500 węzłów w odległości 100 pikseli, będzie musiał przeciągnąć aby zobaczyć inne węzły, teraz to, czego chcę, to to, że jeśli kliknie eksport podczas powiększania, cały wykres 500 węzłów powinien zostać wyeksportowany w pliku SVG, gdzie wszystko jest widoczne na tym poziomie powiększenia. – epoch

+0

Czy masz problem z przechwytywaniem poziomu powiększenia lub z faktycznym procesem eksportu? Trudno ci będzie pomóc bez jakiegoś pojęcia o javascriptie, którego faktycznie używasz i jakie komunikaty o błędach itp., Które generuje twój aktualny kod. – RoryB

Odpowiedz

0

Od Twoje komentarze, możesz sprawdzić niektóre z omawianych tutaj opcji: https://groups.google.com/forum/#!msg/d3-js/tHRV4uvvHFU/yjIAfdQN8WsJ

D3 powinien wpisywać atrybuty do DOM, ogólne oczekiwanie jest takie, że jeśli eksportujesz SVG tak jak jest, powinieneś uzyskać dokładnie ten sam widok. Wygląda na to, że chcesz uczynić istniejący widok jako PNG lub podobny.

Oto interesujące stronie klienta tylko wziąć http://html2canvas.hertzen.com/

+0

dziękuję, przeszedłem przez to. Nie mam problemu z renderowaniem svg, po prostu muszę renderować go we właściwej skali i pozycji, i do tego potrzebuję zastosować poprawne transformacje i rozmiary – epoch

0

I miałaś to przetestowane, ale myślę, że po wyeksportowaniu do obrazu będzie trzeba najpierw pomniejszyć do poziomu początkowego. Następnie serializuj kod XMLNode. Następnie zwiększ rozmiar, tak jak robisz teraz, zgodnie z poziomem skalowania użytkownika. A potem go zwróć.

Powinieneś być w stanie uzyskać przekształceń użytkownika początkowo przy użyciu:

zoom.scale()

Jeśli nie podano, zwraca bieżącą skalę powiększenia, domyślnie na 1.

zoom.translate()

Jeśli nie zostanie określony, zwraca bieżący wektor translacji, którego domyślną wartością jest [0, 0].

+0

wiem wszystko to, ale niestety nadal nie odpowiada na moje pytanie – epoch

+0

Przykro mi, nie sądzę, że rozumiem dokładnie problem.Czy to wynik jest skalowany do odpowiedniego rozmiaru, ale pokazuje tylko małą porcję mapy, czy też coś mi umknęło? Gdzie dzwonisz "serializeSvg()" i co robisz bezpośrednio przed tym? –

+0

Twoje pierwsze przypuszczenie jest poprawne sir :) serializeSvg pochodzi z zdarzenia click – epoch

1

Tak więc w kodzie startowym d3 wywołuje się d3.behaviour.zoom.on(), aby powiązać funkcję "odświeżania" z działaniem "powiększenia".Aby uzyskać skalę i poziom tłumaczenia, chcesz uchwycić wartości d3.scale i d3.translate w tej funkcji, coś takiego (jak nie napisali kod dla funkcji odświeżania):

var scale = 1; 
var xtranslate=0; 
var ytranslate=0; 

var redraw = function(){ 
    scale= d3.event.scale; 
    xtranslate=d3.event.translate[0]; 
    ytranslate=d3.event.translate[1]; 

    //your actual code to redraw stufff 
} 

To będzie Ci wartości skalowania i translacji z d3: musisz zastosować odpowiednie zmiany do wyeksportowanego pliku SVG: tak naprawdę tego nie zrobiłem, ale prawdopodobnie odpowiednio skalowujesz atrybuty "wysokość" i "szerokość" (myślę, że to byłoby po prostu przez pomnożenie wartości atrybutów przez wartość skali, ale nie mogę być tego pewien).

1

Stosowanie pole widzenia i należy pomnożyć przez wartość skalę

np 1920x1080 przy czyli mniej następnie viewbox = 0 0 1920 1080

w skali = 0,5 1920 * 0,5 1080 * 0,5 viewbox = 0 0 960 540

+0

pomogło mi to zawsze ograniczyć eksportowany obraz do eksportu, ale rozmiar nadal nie rośnie wraz z powiększeniem, a zoom jest teraz również ignorowany – epoch