HTML pagination semblable à un livre

Comment puis-je diviser le contenu D'un fichier HTML en morceaux de la taille d'un écran pour le "paginer" dans un navigateur WebKit?

chaque" page " doit afficher une quantité complète de texte. Cela signifie qu'une ligne de texte ne doit pas être coupé en deux dans le bord supérieur ou inférieur de l'écran.

Modifier

cette question a été à l'origine étiquetée" Android " comme mon intention est de construire un lecteur ePub Android. Cependant, il semble que la solution peut être implémentée uniquement avec JavaScript et CSS, donc j'ai élargi la portée de la question pour la rendre indépendante de la plate-forme.

59
demandé sur hpique 2010-09-03 17:11:23

10 réponses

sur la base de la réponse de Dan, voici ma solution pour ce problème, avec lequel je luttais moi-même jusqu'à maintenant. (ce JS fonctionne sur iOS Webkit, pas de garanties pour android, mais s'il vous plaît laissez-moi savoir les résultats)

var desiredHeight;
var desiredWidth;
var bodyID = document.getElementsByTagName('body')[0];
totalHeight = bodyID.offsetHeight;
pageCount = Math.floor(totalHeight/desiredHeight) + 1;
bodyID.style.padding = 10; //(optional) prevents clipped letters around the edges
bodyID.style.width = desiredWidth * pageCount;
bodyID.style.height = desiredHeight;
bodyID.style.WebkitColumnCount = pageCount;

Espérons que cette aide...

30
répondu Engin Kurutepe 2010-10-05 14:19:04

en parlant par expérience, attendez-vous à y consacrer beaucoup de temps, même pour un spectateur sans os. Un EPUB reader était en fait le premier grand projet que j'ai pris sur quand j'ai commencé à apprendre C#, mais la norme ePub est certainement assez complexe.

Vous pouvez trouver la dernière version de la spécification ePub ici: http://www.idpf.org/specs.htm qui comprend L'OPS (Open Publication Structure), L'OPF (Open Packaging Format) et L'OCF (Oebps Container). Format.)

aussi, si elle vous aide à tous, voici un lien vers le code C# source du projet que j'ai commencé:

https://www.dropbox.com/sh/50kxcr29831t854/MDITIklW3I/ePub%20Test.zip

il n'est pas du tout étoffé; Je n'ai pas joué avec cela depuis des mois, mais si je me souviens bien, il suffit de coller un ePub dans le répertoire de débogage, et quand vous exécutez le programme il suffit de taper une partie du nom (par exemple sous la Dome, tapez juste "dome") et il affichera les détails du livre.

Je l'ai fait fonctionner correctement pour quelques livres, mais n'importe quel eBooks de Google Books l'a complètement cassé. Ils ont une mise en œuvre complètement bizarre d'ePub (pour moi, au moins) par rapport à des livres d'autres sources.

quoi qu'il en soit, espérons qu'une partie du code structurel là-bas pourrait vous aider!

21
répondu kcoppock 2012-09-13 00:11:04

j'ai dû coder quelque chose comme ça aussi, et ma solution (de travail) est celle-ci:

vous devez appliquer ces lignes au webview...

    webView_.getSettings().setUseWideViewPort(true);
    webView_.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);

vous devez aussi injecter du javascript. J'ai eu des tonnes de problèmes avec les échelles différentes de mon activité et le contenu rendu dans le webview, de sorte que ma solution ne prend aucune sorte de valeur de "l'extérieur".

    webView_.setWebViewClient(new WebViewClient(){

            public void onPageFinished(WebView view, String url) {
                injectJavascript();
            }

        });

[...]

    public void injectJavascript() {
        String js = "javascript:function initialize() { " +
                "var d = document.getElementsByTagName('body')[0];" +
                "var ourH = window.innerHeight; " +
                "var ourW = window.innerWidth; " + 
                "var fullH = d.offsetHeight; " +
                "var pageCount = Math.floor(fullH/ourH)+1;" +
                "var currentPage = 0; " +
                "var newW = pageCount*ourW; " +
                "d.style.height = ourH+'px';" +
                "d.style.width = newW+'px';" +
                "d.style.webkitColumnGap = '2px'; " +
                "d.style.margin = 0; " +
                "d.style.webkitColumnCount = pageCount;" +
                "}";
        webView_.loadUrl(js);
        webView_.loadUrl("javascript:initialize()");
    }

Enjoy:)

18
répondu Nacho L. 2012-02-06 19:04:39

j'ai récemment essayé quelque chose de similaire à cela et j'ai ajouté un style CSS pour changer la disposition à l'horizontale au lieu de la verticale. Cela m'a donné l'effet désiré sans avoir à modifier le contenu de l'Epub en aucune façon.

ce code devrait fonctionner.

mWebView.setWebViewClient(new WebViewClient() {
    public void onPageFinished(WebView view, String url) {

        // Column Count is just the number of 'screens' of text. Add one for partial 'screens'
        int columnCount = Math.floor(view.getHeight() / view.getWidth())+1;

        // Must be expressed as a percentage. If not set then the WebView will not stretch to give the desired effect.
        int columnWidth = columnCount * 100;

        String js = "var d = document.getElementsByTagName('body')[0];" + 
            "d.style.WebkitColumnCount=" + columnCount + ";" + 
            "d.style.WebkitColumnWidth='" + columnWidth + "%';";
        mWebView.loadUrl("javascript:(function(){" + js + "})()");
    }
});

mWebView.loadUrl("file:///android_asset/chapter.xml");

donc, fondamentalement, vous injectez JavaScript pour changer le style de l'élément de corps après le chapitre a été chargé (très important). Le ce n'est que lorsque vous avez des images dans le contenu que le nombre de colonnes calculé va de travers. Ça ne devrait pas être trop dur à réparer. Ma tentative allait être d'injecter du JavaScript pour ajouter des attributs de largeur et de hauteur à toutes les images dans le DOM qui n'en ont pas.

J'espère que ça aidera.

- Dan

12
répondu Dan 2010-09-14 16:19:06

peut-être que ça marcherait d'utiliser XSL-FO . Cela semble lourd pour un appareil mobile, et peut-être que c'est exagéré, mais cela devrait fonctionner, et vous n'auriez pas à mettre en œuvre les complexités de la bonne pagination (par exemple, comment vous assurez-vous que chaque écran ne coupe pas le texte en deux) vous-même.

L'idée de base serait:

  • transformez le XHTML (et d'autres trucs EPUB) en XSL-FO en utilisant XSLT.
  • utiliser un Processeur XSL-FO pour rendre le XSL-FO dans un format de page que vous pouvez afficher sur l'appareil mobile, tel que PDF (pouvez-vous l'afficher?)

Je ne sais pas s'il existe un processeur XSL-FO disponible pour Android. Tu pourrais essayer Apache FOP. RenderX (processeur XSL-FO) a l'avantage d'avoir une option de sortie pagée-HTML , mais encore une fois je ne sais pas si elle pourrait fonctionner sur Android.

4
répondu LarsH 2010-09-15 04:35:25

il y a plusieurs façons d'y parvenir. Si chaque ligne est dans son propre élément tout ce que vous avez à faire est de vérifier si l'un de ses bords sort de la vue (soit les navigateurs, ou la "page de livre").

si vous voulez savoir combien de" pages " il va y avoir à l'avance, il suffit de les déplacer temporairement dans la vue et obtenir quelle ligne une page se termine. Cela pourrait être lent, car le retour de page est nécessaire pour que le navigateur sache où se trouve quelque chose.

sinon je pense que vous pourriez utiliser l'élément canvas HTML5 pour mesurer le texte et / ou le dessiner.

quelques infos à ce sujet ici: https://developer.mozilla.org/en/Drawing_text_using_a_canvas http://uupaa-js-spinoff.googlecode.com/svn/trunk/uupaa-excanvas.js/demo/8_2_canvas_measureText.html

1
répondu Frank 2010-10-07 03:01:31

avait ce même problème récemment et inspiré par les réponses trouvé une solution CSS simple en utilisant la colonne CSS3 - * attributs:

/* CSS */
.chapter {
    width: 600px;
    padding: 60px 10px;
    -webkit-column-gap: 40px;
    -webkit-column-width: 150px;
    -webkit-column-count: 2;
    height:400px;
}

/* HTML */
<div class="chapter">
    your long lorem ipsum arbitrary HTML
</div>

l'exemple ci-dessus donne de grands résultats sur un iPhone de la rétine. Jouer avec les différents attributs donne un espacement différent entre les pages et tel.

si vous avez besoin de supporter plusieurs chapitres par exemple qui doivent commencer sur les nouvelles pages, il y a un exemple XCode 5 sur github: https://github.com/dmrschmidt/ios_uiwebview_pagination

1
répondu Dennis 2013-11-01 03:31:58

j'ai pu améliorer la solution Nacho pour obtenir un effet de pagination par balayage horizontal avec WebView. Vous pouvez trouver la solution ici et l'exemple code .

Edit:

Code de la Solution

.

activité principale.java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        WebView.setWebContentsDebuggingEnabled(true);
    }
    wv = (HorizontalWebView) findViewById(R.id.web_view);
    wv.getSettings().setJavaScriptEnabled(true);
    wv.setWebViewClient(new WebViewClient() {

        public void onPageFinished(WebView view, String url) {
            injectJavascript();
        }
    });

    wv.setWebChromeClient(new WebChromeClient() {
        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            int pageCount = Integer.parseInt(message);
            wv.setPageCount(pageCount);
            result.confirm();
            return true;
        }
    });
    wv.loadUrl("file:///android_asset/ch03.html");   // now it will not fail here
}

private void injectJavascript() {
    String js = "function initialize(){\n" +
            "    var d = document.getElementsByTagName('body')[0];\n" +
            "    var ourH = window.innerHeight;\n" +
            "    var ourW = window.innerWidth;\n" +
            "    var fullH = d.offsetHeight;\n" +
            "    var pageCount = Math.floor(fullH/ourH)+1;\n" +
            "    var currentPage = 0;\n" +
            "    var newW = pageCount*ourW;\n" +
            "    d.style.height = ourH+'px';\n" +
            "    d.style.width = newW+'px';\n" +
            "    d.style.margin = 0;\n" +
            "    d.style.webkitColumnCount = pageCount;\n" +
            "    return pageCount;\n" +
            "}";
    wv.loadUrl("javascript:" + js);
    wv.loadUrl("javascript:alert(initialize())");
}

dans mon webchromeclient's onJsAlert obtenir le nombre de pages horizontales que je passe à la vue horizontale personnalisée pour mettre en œuvre l'effet de paging

HorizontalWebView.java

public class HorizontalWebView extends WebView {
    private float x1 = -1;
    private int pageCount = 0;

    public HorizontalWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                x1 = event.getX();
                break;
            case MotionEvent.ACTION_UP:
                float x2 = event.getX();
                float deltaX = x2 - x1;
                if (Math.abs(deltaX) > 100) {
                    // Left to Right swipe action
                    if (x2 > x1) {
                        turnPageLeft();
                        return true;
                    }

                    // Right to left swipe action
                    else {
                        turnPageRight();
                        return true;
                    }

                }
                break;
        }
        return true;
    }

    private int current_x = 0;

    private void turnPageLeft() {
        if (getCurrentPage() > 0) {
            int scrollX = getPrevPagePosition();
            loadAnimation(scrollX);
            current_x = scrollX;
            scrollTo(scrollX, 0);
        }
    }

    private int getPrevPagePosition() {
        int prevPage = getCurrentPage() - 1;
        return (int) Math.ceil(prevPage * this.getMeasuredWidth());
    }

    private void turnPageRight() {
        if (getCurrentPage() < pageCount - 1) {
            int scrollX = getNextPagePosition();
            loadAnimation(scrollX);
            current_x = scrollX;
            scrollTo(scrollX, 0);
        }
    }

    private void loadAnimation(int scrollX) {
        ObjectAnimator anim = ObjectAnimator.ofInt(this, "scrollX",
                current_x, scrollX);
        anim.setDuration(500);
        anim.setInterpolator(new LinearInterpolator());
        anim.start();
    }

    private int getNextPagePosition() {
        int nextPage = getCurrentPage() + 1;
        return (int) Math.ceil(nextPage * this.getMeasuredWidth());
    }

    public int getCurrentPage() {
        return (int) (Math.ceil((double) getScrollX() / this.getMeasuredWidth()));
    }

    public void setPageCount(int pageCount) {
        this.pageCount = pageCount;
    }
}
1
répondu Gautam Chibde 2017-06-24 21:14:09

vous pouvez diviser les pages en fichiers XHTML séparés et les stocker dans un dossier. Par exemple: page01, page02. Vous pouvez alors rendre ces pages une par une sous l'autre.

0
répondu Charles 2010-09-03 13:22:40

vous pouvez regarder http://www.litres.ru/static/OR/or.html?data=/static/trials/00/42/47/00424722.gur.html&art=424722&user=0&trial=1 mais le code peut être fortement obscurci, donc utilisez Firebug pour inspecter DOM.

Si le lien ne fonctionne pas, comment - vous donnerait fixe.

0
répondu kagali-san 2010-10-05 19:26:07