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.