2012-05-31 2 views
2

У меня возникла проблема с отображением моего SVG-чертежа в приложении диаграмм. Холст принимает размер своего родительского компонента, а не содержащий его документ. Документы, размер которых превышает этот размер, не полностью отображаются.Сделать JSVGCanvas внутри JSVGScrollPane соответствует размеру SVGDocument

Case

У меня есть рисунок, который, например, 621x621 пикселей.

<?xml version="1.0" encoding="UTF-8"?> 
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" contentScriptType="text/ecmascript" zoomAndPan="magnify" contentStyleType="text/css" preserveAspectRatio="xMaxYMax slice" version="1.0"> 
    <rect x="50" y="50" fill="white" width="20" height="20" stroke="black" stroke-width="1"/> 
    <rect x="600" y="600" fill="blue" width="20" height="20" stroke="black" stroke-width="1"/> 
</svg> 

У него нет viewBox, потому что он создается динамически. Когда я создаю документ, у меня нет такого размера.

У меня есть JSVGCanvas внутри JSVGScrollPane, родительский элемент scrollpane меньше, чем документ, скажем, его 500x500 пикселей.

Ожидаемое поведение

При запуске приложения часть чертежа, который помещается в 500x500 видна. Основной документ больше, поэтому есть полосы прокрутки, которые позволяют мне прокручивать 121px влево и ниже.

Когда вы увеличиваете размер рамки, становится все больше и больше чертежа. Когда вы увеличите его до 620x620px, полосы прокрутки могут полностью исчезнуть.

Если вы сделаете панель меньше, чем документ снова, появятся полосы прокрутки.

Встречающиеся поведение

При запуске приложения часть чертежа, который помещается в 500x500 видна. Прокрутки не видны.

Когда вы делаете панель большей, холст увеличивается (его цвет фона), но рисунок не распространяется на часть, которая находится за пределами начального 500x500px.

Когда вы делаете панель меньшей, скажем, 400x400, появляются полосы прокрутки, но позволяют мне прокручивать 100 пикселей. Таким образом, холст все еще является исходным 500x500 вместо желаемого 621x621.

Пример

встреченного поведение может быть воспроизведен с ScrollExample на хранилище Батика и SVG-файл я добавил выше. В примере используется фиксированный размер 500x500px.

Если вы добавите цвета фона в холст и прокрутку, весь кадр будет синим. Таким образом, хотя холст увеличивается в размерах, он не рисует ничего, кроме его первоначального размера.

canvas.setBackground(Color.blue); 
scroller.setBackground(Color.red); 

Я могу сбросить документ, когда я изменил размер панели. Это заставляет его перерисовывать видимую часть чертежа, но прокрутка по-прежнему не работает должным образом, так как холст по-прежнему является только размером видимой части, а не размером с документом. Вы можете проверить это, добавив этого слушателя в кадр (или любую другую панель, я полагаю).

class ResizeListener implements ComponentListener { 

    JSVGCanvas canvas; 
    URI url; 

    public ResizeListener(JSVGCanvas c, URI u) { 
     canvas = c; 
     url = u; 
    } 

    @Override 
    public void componentResized(ComponentEvent arg0) { 
     canvas.setURI(url.toString()); 
     // Calling invalidate on canvas or scroller does not work 
    } 

    // ... 
}; 

Я прочитал, что я должен иметь Viewbox, но мой документ часто воссозданный (на основе modelchange-события), и когда я создаю документ, я не знаю, как получить Viewbox , SVGDocument.getRootElement().getBBox(); обычно дает мне null. Предполагается, что резервные копии в коде Batik отсутствуют, поэтому я надеюсь, что это необязательно. Кроме того, когда я где-то подправлен, он должен сохранять это панорамирование, если я изменю документ.

Надеюсь, я сделаю свою проблему понятной. Я ожидаю слишком много из JSVG-классов, когда я ожидаю, что они предоставят мое желаемое поведение из коробки или я что-то пропустил? Может ли кто-нибудь помочь мне в решении?

ответ

1

Возможно, я нашел решение. Вместо того, чтобы возиться с viewBox, мне нужно установить высоту и ширину документа. С установленным размером не требуется viewBox, и полосы прокрутки работают должным образом. Если я устанавливаю viewbox, холст продолжает масштабировать изображение, чтобы он соответствовал.

Теперь, для обновления размера, я использую это, когда меняю дом, который может влиять на размер.

static BridgeContext ctx = new BridgeContext(new UserAgentAdapter()); 
static GVTBuilder builder = new GVTBuilder(); 

private static void calculateSize(SVGDocument doc) { 
    GraphicsNode gvtRoot = builder.build(ctx, doc); 

    Rectangle2D rect = gvtRoot.getSensitiveBounds(); 

    doc.getRootElement().setAttributeNS(null, 
      SVGConstants.SVG_WIDTH_ATTRIBUTE, rect.getMaxX() + ""); 
    doc.getRootElement().setAttributeNS(null, 
      SVGConstants.SVG_HEIGHT_ATTRIBUTE, rect.getMaxY() + ""); 
} 

Я делаю это вне от UpdateManager нити и после модификации йот я использую JSVGCanvas.setSVGDocument(). Когда я попытался сделать это через UpdateManager, он только обновил первое изменение. Вероятно, это исправление с правильной инициализацией updatequeue, но поскольку я меняю много документа, я мог бы так же начинать каждый раз.

Я остался с одним незначительным вопросом. Всякий раз, когда я устанавливаю новый документ, позиция прокрутки сбрасывается. Я попытался получить преобразование перед манипуляцией и повторно применить его после, но это, похоже, не работает.

Редактировать +: Мне удалось исправить эту незначительную проблему, заменив корневой узел документа, а не заменяя весь документ. Полотно задано с помощью documentstate ALWAYS_DYNAMIC. Изменения в документе применяются немедленно, в том числе новый размер корневого узла (как описано выше). Но поскольку документ не полностью заменен, состояние прокрутки сохраняется.

Холст готов только для модификации dom после того, как он закончил рендеринг документа. Я использовал SVGLoad-прослушиватель, чтобы обнаружить это.

class Canvas extends JSVGCanvas implements SVGLoadEventDispatcherListener { 

    public Canvas() { 
     super(); 
     setDocumentState(ALWAYS_DYNAMIC); 
     addSVGLoadEventDispatcherListener(this); 
    } 

    /** 
    * Indicatates whether the canvas has finished its first render, the 
    * canvas is now ready for modification of the dom 
    */ 
    private boolean isReadyForModification = false; 

    /** 
    * Renew the document by replacing the root node with the one of the new 
    * document 
    * 
    * @param doc The new document 
    */ 
    public void renewDocument(final SVGDocument doc) { 

     if (isReadyForModification) { 
      getUpdateManager().getUpdateRunnableQueue().invokeLater(
        new Runnable() { 
         @Override 
         public void run() { 
          // Get the root tags of the documents 
          Node oldRoot = getSVGDocument().getFirstChild(); 
          Node newRoot = doc.getFirstChild(); 

          // Make the new node suitable for the old 
          // document 
          newRoot = getSVGDocument().importNode(newRoot, 
            true); 

          // Replace the nodes 
          getSVGDocument().replaceChild(newRoot, oldRoot); 
         } 
        }); 
     } else { 
      setSVGDocument(doc); 
     } 

    } 

    @Override 
    public void svgLoadEventDispatchCompleted(SVGLoadEventDispatcherEvent e) { 
     isReadyForModification = true; 
    } 

    // ... 
}