STRML / textFit

A jQuery-free component that quickly fits single and multi-line text to the width (and optionally height) of its container.
https://textfit.strml.net
637 stars 123 forks source link

Add compatibility to Vue.js, Angular and React #31

Open patrickpissurno opened 6 years ago

patrickpissurno commented 6 years ago

The problem is: this library replaces the original elements in a way that breaks those frameworks. Please add support for them as they're quite popular nowadays

patrickpissurno commented 6 years ago

At the moment, a workaround I've found is to invoke textFit() in a given element before its template gets replaced by Vue.js. Works fine. Then you can call textFit() whenever you'd like to, and it won't break Vue.js's templating.

Not tested with Angular and React.

loke-dev commented 6 years ago

Trying to get it to work with Vue.js. This turned out to be a much larger problem than i expected!

gcleaves commented 4 years ago

Trying to get it to work with Vue.js. This turned out to be a much larger problem than i expected!

did you get it to work? how?

Sasi-007 commented 4 years ago

Guys anyone please tell me how to install or use this library in scratch Html, CSS, Js webpage

lhermann commented 3 years ago

I managed to create a dirty workaround in Vue. Basically it uses a hidden clone to fit the text and then just extracts the font size. The class names are from https://tailwindcss.com

<template>
  <div ref="container" class="relative">
    <div
      ref="original"
      class="absolute z-10 top-0 left-0 w-full h-full"
      :style="{ fontSize: fontSize }"
    >
      <slot />
    </div>
    <div
      :id="_id"
      class="relative z-0 opacity-0 h-full"
    ></div>
  </div>
</template>

<script>
import textfit from 'textfit'

export default {
  props: {
    options: Object,
    refit: Number,
  },
  data () {
    return {
      fontSize: '0px',
    }
  },
  computed: {
    _options () {
      return {
        maxFontSize: 9999,
        ...this.options,
      }
    },
    _id () {
      return 'textfit-' + this._uid
    },
  },
  watch: {
    refit () {
      this.fit()
    },
  },
  mounted () {
    this.fit()
  },
  methods: {
    fit () {
      // this is a dirty workaround because textfit() replaces the original element thus breaking vue
      const el = this.$refs.container.querySelector(`#${this._id}`)
      el.innerHTML = this.$refs.original.innerHTML
      textfit(el, this._options)
      this.fontSize = el.querySelector('span.textFitted')?.style.fontSize
    },
  },
}
</script>
pcherna commented 3 years ago

I spent a bit of time trying to figure this out for Vue 3. One problem is making sure that the text to fit can be reactive (which is tricky because textfit creates an inner element in the DOM to hold the actual text, which bypasses and thus breaks Vue's dominion over the DOM). But the bigger problem is finding the right time to run textfit() for elements that use v-show and start off hidden. At the times I can hook, the geometry isn't yet there to do the fitting. See https://github.com/pcherna/vue-textfit-experiment for my work in progress, any insights would be appreciated.

devellopah commented 3 years ago

For me the binded style works pretty well in vue 2.

<template>
<div
  ref="number"
  :style="{height: height + 'px'}"
>
  {{ number }}
</div>
</template>

<script>
import textfit from 'textfit'

export default {
  props: ['number', 'height'],
  mounted() {
    textfit(this.$refs.number, { minFontSize: 20, maxFontSize: 200,})
  }
}
</script>