Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto resize with contrainer #28

Closed
tylerlong opened this issue Jun 25, 2016 · 17 comments
Closed

Auto resize with contrainer #28

tylerlong opened this issue Jun 25, 2016 · 17 comments
Labels
feature-request Request for new features or functionality
Milestone

Comments

@tylerlong
Copy link

html,body {
  margin: 0;
  padding: 0;
  height:100%;
}

#container {
  height: 100%;
}

The container always takes 100% of the page size. When I resize the page, however, the monaco editor doesn't resize itself. I want the editor to resize itself so there will never be horizontal or vertical scroll bars. I have done similar things with ACE and CodeMirror. Is it possible with monaco-editor?

@alexdima
Copy link
Member

@tylerlong Yes, there is a creation option called automaticLayout:

     /**
     * Enable that the editor will install an interval to check if its container dom node size has changed.
     * Enabling this might have a severe performance impact.
     * Defaults to false.
     */
    automaticLayout?:boolean;

Although convenient, I would personally not use this option as it is implemented by installing an interval that measures the container's size every 100ms. The reason is because the editor has no way of knowing what specifically in your app might cause its container to resize. In your case (when the container size is modified only by the window size), I would add a window.onresize listener and call editor.layout() inside that listener. That will cause the editor to rescan its container size. Even better, if you can somehow compute the size of the container, you can pass the size in to the editor.layout() method.

@tylerlong
Copy link
Author

Although convenient, I would personally not use this option as it is implemented by installing an interval that measures the container's size every 100ms. The reason is because the editor has no way of knowing what specifically in your app might cause its container to resize.

Can we do something like:

$('#container').resize(function(){
  editor.layout();
});

Ref: https://api.jquery.com/resize/

I think the code above should be inside this project instead of let users write it themselves.

Maybe it's a better idea to reimplement the automaticLayout?:boolean; option?

@alexdima
Copy link
Member

From https://api.jquery.com/resize/ I understand that it is a wrapper for the resize event.
From https://www.w3.org/TR/DOM-Level-3-Events/#event-type-resize I understand that the resize event is emitted when the window resizes (not when the element resizes).

I have validated my understanding using the following test page: https://jsfiddle.net/du0d9v9g/1/

$('#element').resize(function(){
  console.log('element resized');
  alert('element resized!');
});
setTimeout(function() {
  // resizing the element
    document.getElementById('element').style.width = '200px';
}, 2000);

That is why automaticLayout scans for the size of the container. The size of the container might be changed by the embedder of the editor due to a number of reasons, only one of them being window.onresize. That is what I mean in my above comment:

The reason is because the editor has no way of knowing what specifically in your app might cause its container to resize. In your case (when the container size is modified only by the window size), I would add a window.onresize listener and call editor.layout() inside that listener. That will cause the editor to rescan its container size. Even better, if you can somehow compute the size of the container, you can pass the size in to the editor.layout() method.

I am open to change the implementation of automaticLayout if we find a JS event that tells us when an element has changed its size.

@nikikante
Copy link
Contributor

nikikante commented Jun 28, 2016

Made some example using transitionend event, works in all major browsers:
https://github.com/nikikante/ResizableElement
demo: https://rawgit.com/nikikante/ResizableElement/master/index.html

Additional testing: Works only on fixed width. Not working with width 100%;

@alexdima alexdima added feature-request Request for new features or functionality question labels Aug 16, 2016
@alexdima alexdima added this to the Backlog milestone Aug 16, 2016
pouyakary added a commit to pouyakary/Graph that referenced this issue Aug 18, 2016
@tylerlong
Copy link
Author

I see there is a commit that referenced this issue on Aug 19. So is this fixed or not?

@fdewannemaeker
Copy link

The automaticlayout option is the only one mentioned here that really worked for me. I'm using the Monaco editor inside a golden-layout module, and everything i tried (including ResizableElement mentioned above) failed. So thank you very much for this option.

@zdne
Copy link

zdne commented Nov 26, 2016

This worked for me:

  updateDimensions() {
    this.editor.layout();
  }

  componentDidMount() {
    window.addEventListener("resize", this.updateDimensions.bind(this));
  }

  componentWillUnmount() {
    window.removeEventListener("resize", this.updateDimensions.bind(this));
  }

@scniro
Copy link

scniro commented Apr 25, 2017

@zdne GOAT

@alexdima alexdima removed their assignment Jun 2, 2017
@alexdima
Copy link
Member

alexdima commented Jun 2, 2017

I'm not sure what else there is to do on our side, so I'm opting to close this issue.

The host of the editor can call editor.layout() when the container size has changed.

If the host of the editor does not want to call editor.layout(), then there is the option automaticLayout (implemented via setInterval that constantly probes for the container's size).

@MRchenkuan
Copy link

listening resize event on window is better than a interval every 100ms , if it is not too frequently

@jmrog
Copy link

jmrog commented Jan 17, 2018

Just in case anyone happens across this issue and sees the snippet posted by @zdne, I wanted to point out that it has a bug. bind creates and returns a new function on each call, so the result of this...

  componentDidMount() {
    window.addEventListener("resize", this.updateDimensions.bind(this));
  }

  componentWillUnmount() {
    window.removeEventListener("resize", this.updateDimensions.bind(this));
  }

...is that a new function is created and added as a resize listener in componentDidMount, and then another new (different) function is created and "removed" (scare-quotes because it was never actually added in the first place) as a resize listener in componentWillMount. What this means is that the listener that was added in componentDidMount is never actually removed, which could result in errors and/or memory leaks. A workaround is to store a reference to the bound function the first time it is created, and then add and remove that same one (using the reference) in the respective methods.

@cancerberoSgx
Copy link
Contributor

cancerberoSgx commented Jun 21, 2018

just in case, my needs are different: I want the user to resize it the container - in a standard way and cheap (both on code and peformance) on libraries and performance. This is what I did:

css container : resize: vertical; overflow: auto

and this js :

function installResizeWatcher(el, fn, interval){
  let offset = {width: el.offsetWidth, height: el.offsetHeight}
  setInterval(()=>{
    let newOffset = {width: el.offsetWidth, height: el.offsetHeight}
    if(offset.height!=newOffset.height||offset.width!=newOffset.width){
      offset = newOffset
      fn()
    }
  }, interval)
}
  const typeScriptCodeContainer = document.getElementById('typeScriptCodeContainer')
  typeScriptCodeEditor = monaco.editor.create(typeScriptCodeContainer, Object.assign(editorOptions, {value: example.codeValue}))
  installResizeWatcher(typeScriptCodeContainer, typeScriptCodeEditor.layout.bind(typeScriptCodeEditor), 2000)

yes, 2 seconds interval and make sure it registers only once. I see there is / was a resize interval on 100ms for the automatic relayout in monaco - IMHO that's too much.

See it in action: https://typescript-api-playground.glitch.me/?example=2

@ddb1494
Copy link

ddb1494 commented Jun 22, 2018 via email

@sheerun
Copy link

sheerun commented Nov 3, 2018

automaticLayout doesn't work when using css grid and reducing window size as ace-editor "fixes" it's height so grid layout engine assumes it cannot reduce it's size

@ghost
Copy link

ghost commented Jan 10, 2019

@ alexandrudima There is a js event for element resize now. Check the links. First one would do the job.
https://developers.google.com/web/updates/2016/10/resizeobserver
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

@jmledantec
Copy link

Hi,

get the same problem here and solved it with this :
react-resize-detector
@atilkan it's based on resizeobserver

Take care to the browser compatibility (I don't care in my project and don't have test it on any other brother than Chrome)

My editor component :

import React, { Component } from 'react';
import ReactResizeDetector from 'react-resize-detector';
import * as monaco from 'monaco-editor';

class Editor extends Component {
    constructor(props) {
        super(props)

        this.state = {
            width: 0,
            height: 0,
        }
        this.editor_div = React.createRef()

        this.handle_rezise = this.handle_rezise.bind(this);
    }

    componentDidMount() {
        const editor_model = monaco.editor.createModel('', 'sql');
        this.monaco_editor = monaco.editor.create(this.editor_div.current, this.props.editorOptions);
        this.monaco_editor.setModel(editor_model);
    }

    componentWillUnmount() {
        this.monaco_editor && this.monaco_editor.dispose();
    }

    handle_rezise(width, height) {
        this.monaco_editor.layout({ height, width });
    }

    render() {
        return(
            <div 
                className="editor-container"
                style={{ height: '100%' }}>
                <ReactResizeDetector
                    handleWidth
                    handleHeight
                    onResize={ this.handle_rezise }
                    refreshMode="debounce"
                    refreshRate={100} />
                <div 
                    className="editor"
                    ref={ this.editor_div }
                    style={{ height: '100%' }} />
            </div>
        )
    }
}

export default Editor;

New to react this code could be better, but hope this help someone.

@epicfaace
Copy link

@ alexandrudima There is a js event for element resize now. Check the links. First one would do the job.
https://developers.google.com/web/updates/2016/10/resizeobserver
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

@alexandrudima so you would be open to a PR that implements automaticLayout using ResizeObserver?

@vscodebot vscodebot bot locked and limited conversation to collaborators Oct 29, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature-request Request for new features or functionality
Projects
None yet
Development

No branches or pull requests