Giter VIP home page Giter VIP logo

comical-js's Introduction

Comical-JS

Typed with TypeScript

Comical-JS is a JavaScript library for displaying and editing comic balloons (speech bubbles), captions, callouts, and related text that floats above one or more images. Lacking a better term, we call all of these things bubbles.

Comical-JS only provides ui elements (handles) to control bubble tails. In the future it may provide ui for controlling the location and bounds of the bubble. But ui for properties like bubble style (thought-bubble, whisper, etc.), background color, etc. will always be left to the client application.

Similarly, Comical-JS does not provide any features related to the text inside the bubble. Instead, the client application must create the element containing the text, and then tell Comical-JS to attach to it. This gives client applications freedom to do whatever they need to with text.

Comical-JS comes from the Bloom project which is an HTML-based literacy material production app. So it is a bit unusual in that it is designed to work with HTML-based editors like Bloom which make changes to the DOM and then save that DOM. For example, when active, Comical draws all the bubbles above an image using the HTML canvas. But when deactivated, Comical-JS inserts an SVG into the DOM, so that you can display the page without having to fire up Comical. Since you might want to later edit the bubbles, it also stores the JSON that defines each bubble in an attribute named data-comical. Using this, it can recreate the interactive bubble as needed.

Demo of use inside of Bloom

Example from Bloom

Project Status

Comical has the main pieces in place and is in use within Bloom. We are gradually adding new bubble types and ways to style bubbles.

Using Comical-JS

To get started:

yarn add comicaljs

To make bubbles appear

You need one or more parent elements, typically containing the picture to which you want to add bubbles, and one or more elements you want to wrap bubbles around, typically positioned relative to the parent. The child elements must have a data-bubble attribute giving an initial specification of the desired bubble (and possibly tails) for that element.

A simple way to do this is, for each desired child, call

Bubble.setBubbleSpec(child, Bubble.getDefaultBubbleSpec(child, "speech));

To turn on editing mode, call

Comical.startEditing([parent]);

A user can then interactively click on a bubble to make handles appear and drag them to move the tail. You can specify more than one parent if you wish. Performance may well suffer with a large number of parents; Comical is designed for a number of parent images that would reasonably fit on a page.

When done editing

To put the document in a state where the bubbles can't be edited and Comical.js code is not needed to make them appear, call

Comical.stopEditing();

(Later, you can call startEditing() again to resume editing.)

BubbleSpec

The content of the data-comical attribute is a slightly modified JSON representation of a BubbleSpec. You can convert between them using Bubble.getBubbleSpec(element) and Bubble.setBubbleSpec(element, spec).

While we are still defining things, the details of BubbleSpec and the related TailSpec classes can be found in the sources.

If you setBubbleSpec() while Comical editing is happening (a valid way of changing an element's properties), or if you add or delete children, you should call

Comical.update(parent);

on the appropriate parent element to make the visible bubbles conform. Note that this must be done after calling Comical.startEditing() with 'parent' in the list of parents, and before the corresponding stopEditing() call.

(This isn't necessary if you just move the element that the bubble is wrapped around; Comical will automatically adjust things, as long as editing is turned on.)

Child bubbles

Two of the properties of bubbles are level and order. Bubbles at the same level are considered to be a family and should have different orders. They will merge their outlines if they overlap. Bubbles in a family are expected to share most other properties; the one with the lowest order is considered the parent, and its properties control all the others in the family. Typically the parent is the bubble which has a tail linked to something in the picture. If the other bubbles don't overlap, joiner tails will be drawn linking them in order.

Developing

Do this once to get the dependencies yarn

Do this to launch a browser window in which you can see various examples of ComicalJS running, or add your own yarn storybook

Do this to create a 'dest' directory with the current version of the files that are npm-published as part of Comical.js yarn build

Acknowledgements

paperjs

Storybook

comical-js's People

Contributors

andrew-polk avatar dependabot[bot] avatar eomerdws avatar gmartin7 avatar hatton avatar johnthomson avatar jsubloom avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

comical-js's Issues

(low) Add borderStyle property

  • Add borderStyleName property
  • Add getBorderStyleNameChoices() method that returns the set of supported style names.

All we need is a set of strings like : "solid", "dashed", "dotted".

These can map to hard-coded paperjs strokes. In the future we can add a different property that allows you to have access to the details of the stroke, but this property will still allow for a cheap UI.

Standalone comical-js samples

I would like to try out comical-js for a prototype I am trying to create to incorporate speech bubbles in my web content. Seems like comical-js can do what I am looking for based on the description. I am looking for a way to run some standalone samples along with it's source code to get an idea how to use the library. I looked at the github readme.md but couldn't quite follow. I see this step in the Developing section:

"Do this to launch a browser window in which you can see various examples of ComicalJS running, or add your own yarn storybook"

Which I thought will enable me to checkout some samples. But I get the following:

$ yarn storybook
yarn run v1.22.10
warning package.json: No license field
error Command "storybook" not found.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

This is the first time I have used yarn, so don't know if I am missing some step or missing something in the package.json. I haven't really started developing anything with comical-js so don't know if I am supposed to configure yarn or my project before being able to run those samples. Any pointers would be greatly appreciated.

Simple Puckered Exclamation Bubble

I haven't found a good name for this; it has to be distinguished from "shout".

It would be good to have a name that isn't hard to translate (e.g. "puckered" would be hard).

For now, let's call it "Exclamation2".

This one is another simple SVG.

Should have 12 points:

image

See #9 for an arithmetically drawn version we'd like to have eventually.

Browser: Project is null, _currentStyle not being set

EDIT: The goal here is to have dynamic word bubbles near a character on the lower right side of an OBS scene to broadcast messages to the viewer. The tail will always be to the right and point to a specific region (the head). I'll want the bubble to appear for variable amounts of time, with successive messages in the same topic appending below it. After a while, I want them to disappear.

I'm using the SkyPack CDN to get the library. It isn't able to get the _currentStyle property from the project object, which I had assumed was being set with the paper.setup call. The exports are coming in, they just don't seem to be working.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Chat Bubbles</title>
</head>

<body>
    <div id="bubble-container" style="position: relative; height: 600px">
        <canvas height="500" width="500"></canvas>
        <div class="word-bubble" style="width: 200px; text-align:center; position: absolute; top: 10px; left: 20px;">Hi
            there!</div>
    </div>

    <script type="module">
        import paper from 'https://cdn.skypack.dev/paper';
        import { Comical, Bubble } from 'https://cdn.skypack.dev/comicaljs';

        document.addEventListener("DOMContentLoaded", function () {
            // Fetch references to elements
            const wrapDiv = document.querySelector('#bubble-container');
            const canvas = document.querySelector('canvas');
            const bubbleContent = document.querySelector('.word-bubble');
            
            // Initialize Paper.js
            paper.setup(canvas);

            // Create a new Comical instance
            const b = new Bubble(bubbleContent);

            // Set the bubble spec
            b.setBubbleSpec({
                version: "1.0",
                style: "speech",
                tails: [{ tipX: 420, tipY: 400, midpointX: 320, midpointY: 375 }],
                level: 1
            });

            // Initialize the bubble tails
            b.tails = [{ tipX: 420, tipY: 400, midpointX: 320, midpointY: 375 }];

            setTimeout(() => {
                // Need a timeout because these functions may need to know the width of the content box
                b.initialize();
            }, 1000);
        });
    </script>
</body>

</html>
Uncaught TypeError TypeError: Cannot read properties of null (reading '_currentStyle')
    at _initialize (cdn.skypack.dev/-/[email protected]/dist=es2019,mode=imports/optimized/comicaljs.js:6884:47)
    at Group2 (cdn.skypack.dev/-/[email protected]/dist=es2019,mode=imports/optimized/comicaljs.js:8191:25)
    at Layer2 (cdn.skypack.dev/-/[email protected]/dist=es2019,mode=imports/optimized/comicaljs.js:8251:21)
    at Bubble3.initializeLayers (cdn.skypack.dev/-/[email protected]/dist=es2019,mode=imports/optimized/comicaljs.js:18172:33)
    at Bubble3.initialize (cdn.skypack.dev/-/[email protected]/dist=es2019,mode=imports/optimized/comicaljs.js:18183:18)
    at <anonymous> (c:\dev\obs\public\chat.html:36:19)
    --- setTimeout ---
    at <anonymous> (c:\dev\obs\public\chat.html:34:13)

fillColor

The value should be whatever paperjs supports, which I assume is anything that canvas supports which I assume is anything that css supports. E.g. "red" and "#FECBA1".

Support child bubbles

  • a bubble may have one child bubble

  • a bubble and its children cannot have a different level

  • bubbles in this kind of "family grouping" share a border when they overlap

  • when a child should have a tail that ends in the center of the parent so that when they are apart, you see that tail.

image

Thought bubble with bubble tail

image

Not a requirement, but notice that hand-drawn though bubbles are often drawn with ellipses instead of circles, and sometimes the initial ellipses overlap:

image

Advanced Puckered Exclamation Bubble

See http://clintflickerlettering.blogspot.com/2010/11/lettering-in-adobe-illustrator-five.html for how this is done in Illustrator, which may give some hints to doing it in paperjs.

This one would seem to require a method other than using an SVG template, because the number of points really should vary:

image

Not that there is randomness in there; it's not as though every point is the same distance from the center. But that's just a "nice to have".

  1. In the default "auto" mode, it should add points as the bubble gets larger.
  2. And also take a value that controls how many points it has.

Add bubble `level` or ordering

When bubbles overlap (but are not part of the same "family"), we need a way to say "Move to Top". Internally, we need some way to model this ordering/level.

Multiple (or zero) tails.

We can get a long way with just 0 or 1. So that's all the code needs to implement; but the model should be an array of them, so that some day we can support crowds saying something.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.