I wrote a doodle component based on SVG. I wrote a doodle component based on SVG. I wrote a doodle component based on SVG.

The address of the project: https://github.com/linmingdao/SVGraffiti

Effect preview:

Functional demonstration:

Due to space problems, this paper first introduces the general situation of the project, focusing on the communication between components.

I. Project description

The project is a multi-page application built on [email protected], developed using ES6 and organized as a component. After git Clone project (with github repository address attached), NPM I will install related dependencies, and NPM run dev will run the project. By default, the home page of the application will be opened, which is the interface corresponding to the effect preview above. The development process will write some test code for some functions separately, so the project provides different pages for different functions, such as:

Color Picker component test page:

Component Messaging Framework test page:

SVG low-level drawing API test page:

2. Communication between components

1. In order to achieve maximum encapsulation and decoupling, components do not directly communicate with each other, but indirectly through the message subscription/publication Management Center (hereinafter referred to as the “Message Center”). Components have corresponding communication capabilities by declaring themselves as different roles:

  • The component declares Subscriber and subscribes to the message it is interested in from “message center” in the form of @topics annotation. The corresponding message will be notified to the component through notify interface.
  • The component is declared Publisher and can publish topic messages through the publish method injected by Publisher roles;
  • The component is declared as a publisher/subscriber and has communication capabilities for both the subscriber and the publisher.

The palette component in the middle of the project is used as an example. Since the Palette component only receives information from the Toolbar component about toggle drawing capabilities and clearing drawing content, and Settings component about setting drawing parameters, this component is only a message subscriber role and is encoded as follows:

First import the corresponding role class:

import Subscriber from '.. /.. /supports/pubsub/base/subscriber';
import Topics from '.. /.. /supports/pubsub/base/topics';
Copy the code

Write the corresponding component:

// Subscribe to interested message types @topics (['function'.'resident_function'.'set_preference'])
exportDefault class Sketchpad extends Subscriber {// constructor(Sketchpad) {super(); this.sketchpad = sketchpad; / /... } /** * This interface is called by [PubSub Message Management Center], where the Palette component processes the received message type * 1. The "Toggle palette drawing state" message type sent by the Toolbar component is:function* 2, Process the Toolbar component's "Clear Paint content" message type: "Resident_function" * 3, process the Settings component's "Set Paint Parameters" message type: "Set_preference" * @param {String} topic Message topic identifier * @param {Object} entity Message entity Object */ notify(topic, Entity) {// Process the received message here}}Copy the code

Note: @topics is static. If some Topics require a run-time subscription, you can subscribe messages dynamically by calling the Subscribe method provided by the Subscriber role.

2. The implementation of PubSub (Message subscription/Publication Management Center), since it is a general capability at the bottom, must be realized without any specific business, and it must be guaranteed to be a general module both in naming conventions and coding implementations

Implementation of PubSub:

/** * Topic subscription publishing center */exportDefault class PubSub {// Caches topics and list of subscribers to topics static Topics = {}; @param {String} topic topic @param {*} entity body */ static publish(topic, entity) {if(! PubSub.topics[topic])return; Const Subscribers = Pubsub.topics [topic]; // Send a topic message to all subscribers of the topicfor (letsubscriber of subscribers) { subscriber.notify && subscriber.notify(topic, entity); @param {String} topic */ static registerTopic(topic) {const topics = PubSub['topics']; ! topics[topic] && (topics[topic] = []); @param {Array} topics */ static registerTopics(topics = []) {topics. ForEach (topic => { this.registerTopic(topic); }); } /** * add topic subscriber * @param {String} topic topic * @param {Object} subscriber implement notify interface subscriber */ static addSubscriber(topic, subscriber) { const topics = PubSub['topics']; ! topics[topic] && (topics[topic] = []); // Register the subscriber of this topic to the corresponding topic topics[topic].push(subscriber); } /** * delete the corresponding subscriber * @param subscriber */ static removeSubscriber(subscriber) {const subs = []; // Iterate over the list of subscribers under all topics and delete the corresponding subscribers const Topics = pubsub.topics; Object.keys(topics).forEach(topicName => { const topic = topics[topicName];for (let i = 0; i < topic.length; ++i) {
                if (topic[i] === subscriber) {
                    subs.push(topics[topic].splice(i, 1));
                    break; }}});returnsubs; }}Copy the code

Subscriber realization:

import PubSub from '.. /pubsub'; const addSubscribe = (topics = [], context) => { topics.forEach(topic => { PubSub.addSubscriber(topic, context); }); } /** * Topic subscribers */export default class Subscriber {
    constructor() { addSubscribe(this.__proto__.constructor.topics, this); } subscribe(topic) { PubSub.addSubscriber(topic, this); }}Copy the code

To make it easier to subscribe to Topics, add a @topics annotation:

import PubSub from '.. /pubsub'; /** * Subscriber theme decorator * @param {Array} topics */export default function Topics(topics) {
    returntarget => { target.topics = topics; PubSub.registerTopics(topics); }}Copy the code

Publisher implementation:

import PubSub from '.. /pubsub'; /** * Topic message publisher */exportdefault class Publisher { publish(topic, entity) { PubSub.publish(topic, entity); }}Copy the code

Implementation of the SubScatterer:

import PubSub from '.. /pubsub';
import Subscriber from './subscriber'; /** * Topic subscriber and topic message publisher */exportdefault class SubScatterer extends Subscriber { publish(topic, entity) { PubSub.publish(topic, entity); }}Copy the code

This paper introduces the project general situation, analyzed how to implement the component in the form of the publish/subscribe communication between, there will be time to write a few articles respectively introduce SVG drawing ability at the bottom of the packaging, “sketchpad render state the implementation and management of different”, “how to develop a general ColorPicker” and so on articles related to this project, It’s not good writing.

The address of the project: https://github.com/linmingdao/SVGraffiti

Interested students are welcome to communicate with Star.